Browse Source

synchronizer: allow server not finding txn sometimes

User has wallet file with history that includes some txid; corresponding
raw tx is not in the "transactions" dict in the file however.
When the synchronizer starts up, it requests this "missing" txn from
the server... but what if the server does not know about it?
Maybe it was reorged and is not in the new best chain,
and not even in mempool. This was not handled previously.

fix #5122
sqlite_db
SomberNight 6 years ago
parent
commit
7b8114f865
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 2
      electrum/network.py
  2. 17
      electrum/synchronizer.py

2
electrum/network.py

@ -780,7 +780,7 @@ class Network(PrintError):
try: try:
return await func(self, *args, **kwargs) return await func(self, *args, **kwargs)
except aiorpcx.jsonrpc.CodeMessageError as e: except aiorpcx.jsonrpc.CodeMessageError as e:
raise UntrustedServerReturnedError(original_exception=e) raise UntrustedServerReturnedError(original_exception=e) from e
return wrapper return wrapper
@best_effort_reliable @best_effort_reliable

17
electrum/synchronizer.py

@ -32,6 +32,7 @@ from aiorpcx import TaskGroup, run_in_thread
from .transaction import Transaction from .transaction import Transaction
from .util import bh2u, make_aiohttp_session, NetworkJobOnDefaultServer from .util import bh2u, make_aiohttp_session, NetworkJobOnDefaultServer
from .bitcoin import address_to_scripthash, is_address from .bitcoin import address_to_scripthash, is_address
from .network import UntrustedServerReturnedError
if TYPE_CHECKING: if TYPE_CHECKING:
from .network import Network from .network import Network
@ -165,7 +166,7 @@ class Synchronizer(SynchronizerBase):
# Remove request; this allows up_to_date to be True # Remove request; this allows up_to_date to be True
self.requested_histories.pop(addr) self.requested_histories.pop(addr)
async def _request_missing_txs(self, hist): async def _request_missing_txs(self, hist, *, allow_server_not_finding_tx=False):
# "hist" is a list of [tx_hash, tx_height] lists # "hist" is a list of [tx_hash, tx_height] lists
transaction_hashes = [] transaction_hashes = []
for tx_hash, tx_height in hist: for tx_hash, tx_height in hist:
@ -179,10 +180,18 @@ class Synchronizer(SynchronizerBase):
if not transaction_hashes: return if not transaction_hashes: return
async with TaskGroup() as group: async with TaskGroup() as group:
for tx_hash in transaction_hashes: for tx_hash in transaction_hashes:
await group.spawn(self._get_transaction, tx_hash) await group.spawn(self._get_transaction(tx_hash, allow_server_not_finding_tx=allow_server_not_finding_tx))
async def _get_transaction(self, tx_hash): async def _get_transaction(self, tx_hash, *, allow_server_not_finding_tx=False):
try:
result = await self.network.get_transaction(tx_hash) result = await self.network.get_transaction(tx_hash)
except UntrustedServerReturnedError as e:
# most likely, "No such mempool or blockchain transaction"
if allow_server_not_finding_tx:
self.requested_tx.pop(tx_hash)
return
else:
raise
tx = Transaction(result) tx = Transaction(result)
try: try:
tx.deserialize() tx.deserialize()
@ -207,7 +216,7 @@ class Synchronizer(SynchronizerBase):
# Old electrum servers returned ['*'] when all history for the address # Old electrum servers returned ['*'] when all history for the address
# was pruned. This no longer happens but may remain in old wallets. # was pruned. This no longer happens but may remain in old wallets.
if history == ['*']: continue if history == ['*']: continue
await self._request_missing_txs(history) await self._request_missing_txs(history, allow_server_not_finding_tx=True)
# add addresses to bootstrap # add addresses to bootstrap
for addr in self.wallet.get_addresses(): for addr in self.wallet.get_addresses():
await self._add_address(addr) await self._add_address(addr)

Loading…
Cancel
Save