From ecebbc86c65a11c165c7ac440078f94eeb95a6cb Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Tue, 18 Jun 2019 17:50:41 -0400 Subject: [PATCH] fixed reorg issue with headers --- .../test_blockchain_reorganization.py | 42 ++++++++----------- torba/client/baseheader.py | 7 +++- torba/orchstr8/node.py | 5 ++- torba/server/block_processor.py | 4 +- 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/tests/client_tests/integration/test_blockchain_reorganization.py b/tests/client_tests/integration/test_blockchain_reorganization.py index 6f6ecbd02..ff85fd29c 100644 --- a/tests/client_tests/integration/test_blockchain_reorganization.py +++ b/tests/client_tests/integration/test_blockchain_reorganization.py @@ -1,5 +1,4 @@ import logging -from unittest import skip from torba.testcase import IntegrationTestCase @@ -8,30 +7,23 @@ class BlockchainReorganizationTests(IntegrationTestCase): VERBOSITY = logging.WARN async def test_reorg(self): + # invalidate current block, move forward 2 self.assertEqual(self.ledger.headers.height, 200) - - await self.blockchain.generate(1) - await self.on_header(201) + self.assertEqual( + self.ledger.headers.hash(200).decode(), + await self.blockchain.get_block_hash(200) + ) + await self.blockchain.invalidate_block(self.ledger.headers.hash(200).decode()) + await self.blockchain.generate(2) + await self.ledger.on_header.where(lambda e: e.height == 201) self.assertEqual(self.ledger.headers.height, 201) - height = 201 + self.assertEqual( + self.ledger.headers.hash(200).decode(), + await self.blockchain.get_block_hash(200) + ) - # simple fork (rewind+advance to immediate best) - height = await self._simulate_reorg(height, 1, 1, 2) - height = await self._simulate_reorg(height, 2, 1, 10) - height = await self._simulate_reorg(height, 4, 1, 3) - # lagged fork (rewind+batch catch up with immediate best) - height = await self._simulate_reorg(height, 4, 2, 3) - await self._simulate_reorg(height, 4, 4, 3) - - async def _simulate_reorg(self, height, rewind, winners, progress): - for i in range(rewind): - await self.blockchain.invalidateblock(self.ledger.headers.hash(height - i).decode()) - await self.blockchain.generate(rewind + winners) - height = height + winners - await self.on_header(height) - for i in range(progress): - await self.blockchain.generate(1) - height += 1 - await self.on_header(height) - self.assertEqual(height, self.ledger.headers.height) - return height + # invalidate current block, move forward 3 + await self.blockchain.invalidate_block(self.ledger.headers.hash(200).decode()) + await self.blockchain.generate(3) + await self.ledger.on_header.where(lambda e: e.height == 202) + self.assertEqual(self.ledger.headers.height, 202) diff --git a/torba/client/baseheader.py b/torba/client/baseheader.py index 1d992654f..21880fb44 100644 --- a/torba/client/baseheader.py +++ b/torba/client/baseheader.py @@ -39,7 +39,10 @@ class BaseHeaders: async def open(self): if self.path != ':memory:': - self.io = open(self.path, 'a+b') + if not os.path.exists(self.path): + self.io = open(self.path, 'w+b') + else: + self.io = open(self.path, 'r+b') async def close(self): self.io.close() @@ -105,7 +108,7 @@ class BaseHeaders: await loop.run_in_executor(None, self.validate_chunk, height, chunk) except InvalidHeader as e: bail = True - chunk = chunk[:(height-e.height+1)*self.header_size] + chunk = chunk[:(height-e.height)*self.header_size] written = 0 if chunk: self.io.seek(height * self.header_size, os.SEEK_SET) diff --git a/torba/orchstr8/node.py b/torba/orchstr8/node.py index 554021961..885e78508 100644 --- a/torba/orchstr8/node.py +++ b/torba/orchstr8/node.py @@ -364,9 +364,12 @@ class BlockchainNode: self._block_expected += blocks return self._cli_cmnd('generate', str(blocks)) - def invalidateblock(self, blockhash): + def invalidate_block(self, blockhash): return self._cli_cmnd('invalidateblock', blockhash) + def get_block_hash(self, block): + return self._cli_cmnd('getblockhash', str(block)) + def get_raw_change_address(self): return self._cli_cmnd('getrawchangeaddress') diff --git a/torba/server/block_processor.py b/torba/server/block_processor.py index 49bb30cda..0d81366d5 100644 --- a/torba/server/block_processor.py +++ b/torba/server/block_processor.py @@ -457,13 +457,13 @@ class BlockProcessor: hash_to_hex_str(self.tip), self.height)) self.tip = coin.header_prevhash(block.header) - self.backup_txs(block.transactions) + self.backup_txs(self.height, block.transactions) self.height -= 1 self.db.tx_counts.pop() self.logger.info('backed up to height {:,d}'.format(self.height)) - def backup_txs(self, txs): + def backup_txs(self, height, txs): # Prevout values, in order down the block (coinbase first if present) # undo_info is in reverse block order undo_info = self.db.read_undo_info(self.height)