forked from LBRYCommunity/lbry-sdk
fixed reorg issue with headers
This commit is contained in:
parent
794eac0519
commit
ecebbc86c6
4 changed files with 28 additions and 30 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue