failing test for unordered mempool

This commit is contained in:
Victor Shyba 2019-08-30 00:52:08 -03:00
parent 96800de052
commit 925eb618de
2 changed files with 45 additions and 2 deletions

View file

@ -1,6 +1,9 @@
import logging
import asyncio
import random
from itertools import chain
from random import shuffle
from torba.testcase import IntegrationTestCase
from torba.client.util import satoshis_to_coins, coins_to_satoshis
@ -129,3 +132,39 @@ class BasicTransactionTests(IntegrationTestCase):
self.assertEqual(tx.outputs[0].get_address(self.ledger), address2)
self.assertEqual(tx.outputs[0].is_change, False)
self.assertEqual(tx.outputs[1].is_change, True)
async def test_history_edge_cases(self):
await self.assertBalance(self.account, '0.0')
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:
ordered = summary.copy()
while summary == ordered:
random.shuffle(summary)
return summary
self.conductor.spv_node.server.mempool.transaction_summaries = random_summary
# 10 unconfirmed txs, all from blockchain wallet
sends = list(self.blockchain.send_to_address(address, 10) for _ in range(10))
# use batching to reduce issues with send_to_address on cli
for batch in range(0, len(sends), 10):
txids = await asyncio.gather(*sends[batch:batch + 10])
await asyncio.wait([self.on_transaction_id(txid) for txid in txids])
remote_status = await self.ledger.network.subscribe_address(address)
self.assertTrue(await self.ledger.update_history(address, remote_status))
# 20 unconfirmed txs, 10 from blockchain, 10 from local to local
utxos = await self.account.get_utxos()
txs = []
for utxo in utxos:
tx = await self.ledger.transaction_class.create(
[self.ledger.transaction_class.input_class.spend(utxo)],
[],
[self.account], self.account
)
await self.broadcast(tx)
txs.append(tx)
await asyncio.wait([self.on_transaction_address(tx, address) for tx in txs], timeout=1)
remote_status = await self.ledger.network.subscribe_address(address)
self.assertTrue(await self.ledger.update_history(address, remote_status))

View file

@ -415,7 +415,7 @@ class BaseLedger(metaclass=LedgerRegistry):
local_status, local_history = await self.get_local_status_and_history(address)
if local_status == remote_status:
return
return True
remote_history = await self.network.retriable_call(self.network.get_history, address)
@ -472,14 +472,18 @@ class BaseLedger(metaclass=LedgerRegistry):
local_status, local_history = await self.get_local_status_and_history(address)
if local_status != remote_status:
remote_history = list(map(itemgetter('tx_hash', 'height'), remote_history))
if remote_history == local_history:
return True
log.debug(
"Wallet is out of sync after syncing. Remote: %s with %d items, local: %s with %d items",
remote_status, len(remote_history), local_status, len(local_history)
)
log.debug("local: %s", local_history)
log.debug("remote: %s", remote_history)
return False
else:
log.debug("Sync completed for: %s", address)
return True
async def cache_transaction(self, txid, remote_height):
cache_item = self._tx_cache.get(txid)