Browse Source

network: fix bug in best_effort_reliable

self.interface might get set to None after decorator checks it but before func gets scheduled:

125.04 | E | asyncio | Task exception was never retrieved
future: <Task finished name='Task-408' coro=<Transaction.add_info_from_network.<locals>.add_info_to_txin() done, defined at ...\electrum\electrum\transaction.py:976> exception=AttributeError("'NoneType' object has no attribute 'get_transaction'")>
Traceback (most recent call last):
  File "...\electrum\electrum\transaction.py", line 980, in add_info_to_txin
    await txin.add_info_from_network(network=network, ignore_network_issues=ignore_network_issues)
  File "...\electrum\electrum\transaction.py", line 375, in add_info_from_network
    self.utxo = await fetch_from_network(txid=self.prevout.txid.hex())
  File "...\electrum\electrum\transaction.py", line 362, in fetch_from_network
    raw_tx = await network.get_transaction(txid, timeout=10)
  File "...\electrum\electrum\network.py", line 866, in make_reliable_wrapper
    async with OldTaskGroup(wait=any) as group:
  File "...\aiorpcX\aiorpcx\curio.py", line 304, in __aexit__
    await self.join()
  File "...\electrum\electrum\util.py", line 1410, in join
    self.completed.result()
  File "...\electrum\electrum\network.py", line 889, in wrapper
    return await func(self, *args, **kwargs)
  File "...\electrum\electrum\network.py", line 1114, in get_transaction
    return await self.interface.get_transaction(tx_hash=tx_hash, timeout=timeout)
AttributeError: 'NoneType' object has no attribute 'get_transaction'
master
SomberNight 3 years ago
parent
commit
9439261e42
No known key found for this signature in database
GPG Key ID: B33B5F232C6271E9
  1. 16
      electrum/network.py

16
electrum/network.py

@ -894,10 +894,14 @@ class Network(Logger, NetworkRetryManager[ServerAddr]):
@best_effort_reliable @best_effort_reliable
@catch_server_exceptions @catch_server_exceptions
async def get_merkle_for_transaction(self, tx_hash: str, tx_height: int) -> dict: async def get_merkle_for_transaction(self, tx_hash: str, tx_height: int) -> dict:
if self.interface is None: # handled by best_effort_reliable
raise RequestTimedOut()
return await self.interface.get_merkle_for_transaction(tx_hash=tx_hash, tx_height=tx_height) return await self.interface.get_merkle_for_transaction(tx_hash=tx_hash, tx_height=tx_height)
@best_effort_reliable @best_effort_reliable
async def broadcast_transaction(self, tx: 'Transaction', *, timeout=None) -> None: async def broadcast_transaction(self, tx: 'Transaction', *, timeout=None) -> None:
if self.interface is None: # handled by best_effort_reliable
raise RequestTimedOut()
if timeout is None: if timeout is None:
timeout = self.get_network_timeout_seconds(NetworkTimeout.Urgent) timeout = self.get_network_timeout_seconds(NetworkTimeout.Urgent)
try: try:
@ -1106,31 +1110,43 @@ class Network(Logger, NetworkRetryManager[ServerAddr]):
@best_effort_reliable @best_effort_reliable
@catch_server_exceptions @catch_server_exceptions
async def request_chunk(self, height: int, tip=None, *, can_return_early=False): async def request_chunk(self, height: int, tip=None, *, can_return_early=False):
if self.interface is None: # handled by best_effort_reliable
raise RequestTimedOut()
return await self.interface.request_chunk(height, tip=tip, can_return_early=can_return_early) return await self.interface.request_chunk(height, tip=tip, can_return_early=can_return_early)
@best_effort_reliable @best_effort_reliable
@catch_server_exceptions @catch_server_exceptions
async def get_transaction(self, tx_hash: str, *, timeout=None) -> str: async def get_transaction(self, tx_hash: str, *, timeout=None) -> str:
if self.interface is None: # handled by best_effort_reliable
raise RequestTimedOut()
return await self.interface.get_transaction(tx_hash=tx_hash, timeout=timeout) return await self.interface.get_transaction(tx_hash=tx_hash, timeout=timeout)
@best_effort_reliable @best_effort_reliable
@catch_server_exceptions @catch_server_exceptions
async def get_history_for_scripthash(self, sh: str) -> List[dict]: async def get_history_for_scripthash(self, sh: str) -> List[dict]:
if self.interface is None: # handled by best_effort_reliable
raise RequestTimedOut()
return await self.interface.get_history_for_scripthash(sh) return await self.interface.get_history_for_scripthash(sh)
@best_effort_reliable @best_effort_reliable
@catch_server_exceptions @catch_server_exceptions
async def listunspent_for_scripthash(self, sh: str) -> List[dict]: async def listunspent_for_scripthash(self, sh: str) -> List[dict]:
if self.interface is None: # handled by best_effort_reliable
raise RequestTimedOut()
return await self.interface.listunspent_for_scripthash(sh) return await self.interface.listunspent_for_scripthash(sh)
@best_effort_reliable @best_effort_reliable
@catch_server_exceptions @catch_server_exceptions
async def get_balance_for_scripthash(self, sh: str) -> dict: async def get_balance_for_scripthash(self, sh: str) -> dict:
if self.interface is None: # handled by best_effort_reliable
raise RequestTimedOut()
return await self.interface.get_balance_for_scripthash(sh) return await self.interface.get_balance_for_scripthash(sh)
@best_effort_reliable @best_effort_reliable
@catch_server_exceptions @catch_server_exceptions
async def get_txid_from_txpos(self, tx_height, tx_pos, merkle): async def get_txid_from_txpos(self, tx_height, tx_pos, merkle):
if self.interface is None: # handled by best_effort_reliable
raise RequestTimedOut()
return await self.interface.get_txid_from_txpos(tx_height, tx_pos, merkle) return await self.interface.get_txid_from_txpos(tx_height, tx_pos, merkle)
def blockchain(self) -> Blockchain: def blockchain(self) -> Blockchain:

Loading…
Cancel
Save