diff --git a/torba/tests/client_tests/integration/test_network.py b/torba/tests/client_tests/integration/test_network.py index ee7ed4882..7f60441a2 100644 --- a/torba/tests/client_tests/integration/test_network.py +++ b/torba/tests/client_tests/integration/test_network.py @@ -59,7 +59,7 @@ class ReconnectTests(IntegrationTestCase): master_client = self.ledger.network.client self.ledger.network.client.connection_lost(Exception()) with self.assertRaises(asyncio.TimeoutError): - await d + await d self.assertIsNone(master_client.response_time) # response time unknown as it failed # rich but offline? no way, no water, let's retry with self.assertRaisesRegex(ConnectionError, 'connection is not available'): diff --git a/torba/tests/client_tests/integration/test_transactions.py b/torba/tests/client_tests/integration/test_transactions.py index 4ee4e2dfe..f7f7581a0 100644 --- a/torba/tests/client_tests/integration/test_transactions.py +++ b/torba/tests/client_tests/integration/test_transactions.py @@ -138,6 +138,7 @@ class BasicTransactionTests(IntegrationTestCase): address = await self.account.receiving.get_or_create_usable_address() # evil trick: mempool is unsorted on real life, but same order between python instances. reproduce it original_summary = self.conductor.spv_node.server.mempool.transaction_summaries + async def random_summary(*args, **kwargs): summary = await original_summary(*args, **kwargs) if summary and len(summary) > 2: @@ -174,3 +175,5 @@ class BasicTransactionTests(IntegrationTestCase): self.assertTrue(await self.ledger.update_history(address, remote_status)) self.assertEqual(21, len((await self.ledger.get_local_status_and_history(address))[1])) self.assertEqual(0, len(self.ledger._known_addresses_out_of_sync)) + # should be another test, but it would be too much to setup just for that and it affects sync + self.assertIsNone(await self.ledger.network.get_transaction('1'*64)) diff --git a/torba/tests/client_tests/unit/test_ledger.py b/torba/tests/client_tests/unit/test_ledger.py index beb26a5d1..f94326f5d 100644 --- a/torba/tests/client_tests/unit/test_ledger.py +++ b/torba/tests/client_tests/unit/test_ledger.py @@ -29,7 +29,7 @@ class MockNetwork: async def get_merkle(self, txid, height): return {'merkle': ['abcd01'], 'pos': 1} - async def get_transaction(self, tx_hash): + async def get_transaction(self, tx_hash, _=None): self.get_transaction_called.append(tx_hash) return self.transaction[tx_hash] diff --git a/torba/torba/client/basedatabase.py b/torba/torba/client/basedatabase.py index a9b802dbf..f31e816df 100644 --- a/torba/torba/client/basedatabase.py +++ b/torba/torba/client/basedatabase.py @@ -220,7 +220,7 @@ class SQLiteMixin: async def open(self): log.info("connecting to database: %s", self._db_path) - self.db = await AIOSQLite.connect(self._db_path) + self.db = await AIOSQLite.connect(self._db_path, isolation_level=None) await self.db.executescript(self.CREATE_TABLES_QUERY) async def close(self): diff --git a/torba/torba/client/baseledger.py b/torba/torba/client/baseledger.py index c31612aee..cba9a8d9a 100644 --- a/torba/torba/client/baseledger.py +++ b/torba/torba/client/baseledger.py @@ -287,7 +287,7 @@ class BaseLedger(metaclass=LedgerRegistry): await self.join_network() self.network.on_connected.listen(self.join_network) - async def join_network(self, *args): + async def join_network(self, *_): log.info("Subscribing and updating accounts.") async with self._header_processing_lock: await self.update_headers() @@ -472,9 +472,10 @@ class BaseLedger(metaclass=LedgerRegistry): await self.db.save_transaction_io_batch( synced_txs, address, self.address_to_hash160(address), synced_history.getvalue() ) - - for tx in synced_txs: - await self._on_transaction_controller.add(TransactionEvent(address, tx)) + await asyncio.wait([ + self._on_transaction_controller.add(TransactionEvent(address, tx)) + for tx in synced_txs + ]) if address_manager is None: address_manager = await self.get_address_manager_for_address(address) @@ -517,7 +518,7 @@ class BaseLedger(metaclass=LedgerRegistry): if tx is None: # fetch from network - _raw = await self.network.retriable_call(self.network.get_transaction, txid) + _raw = await self.network.retriable_call(self.network.get_transaction, txid, remote_height) if _raw: tx = self.transaction_class(unhexlify(_raw)) cache_item.tx = tx # make sure it's saved before caching it diff --git a/torba/torba/client/basenetwork.py b/torba/torba/client/basenetwork.py index 121c3f3d9..6bb789d3d 100644 --- a/torba/torba/client/basenetwork.py +++ b/torba/torba/client/basenetwork.py @@ -72,6 +72,10 @@ class ClientSession(BaseClientSession): log.debug("got reply for %s from %s:%i", method, *self.server) return reply except RPCError as e: + if str(e).find('.*no such .*transaction.*') and args: + # shouldnt the server return none instead? + log.warning("Requested transaction missing from server: %s", args[0]) + return None log.warning("Wallet server (%s:%i) returned an error. Code: %s Message: %s", *self.server, *e.args) raise e @@ -220,20 +224,17 @@ class BaseNetwork: def _update_remote_height(self, header_args): self.remote_height = header_args[0]["height"] - def get_transaction(self, tx_hash): - return self.rpc('blockchain.transaction.get', [tx_hash]) + def get_transaction(self, tx_hash, known_height=None): + # use any server if its old, otherwise restrict to who gave us the history + restricted = not known_height or 0 > known_height > self.remote_height - 10 + return self.rpc('blockchain.transaction.get', [tx_hash], restricted) def get_transaction_height(self, tx_hash, known_height=None): - restricted = True # by default, check master for consistency - if known_height: - if 0 < known_height < self.remote_height - 10: - restricted = False # we can get from any server, its old + restricted = not known_height or 0 > known_height > self.remote_height - 10 return self.rpc('blockchain.transaction.get_height', [tx_hash], restricted) def get_merkle(self, tx_hash, height): - restricted = True # by default, check master for consistency - if 0 < height < self.remote_height - 10: - restricted = False # we can get from any server, its old + restricted = 0 > height > self.remote_height - 10 return self.rpc('blockchain.transaction.get_merkle', [tx_hash, height], restricted) def get_headers(self, height, count=10000):