Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc-invalid-chains.py
Show All 12 Lines | |||||
class InvalidChainsTest(BitcoinTestFramework): | class InvalidChainsTest(BitcoinTestFramework): | ||||
def set_test_params(self): | def set_test_params(self): | ||||
self.num_nodes = 1 | self.num_nodes = 1 | ||||
self.setup_clean_chain = True | self.setup_clean_chain = True | ||||
self.tip = None | self.tip = None | ||||
self.blocks = {} | self.blocks = {} | ||||
self.block_heights = {} | self.block_heights = {} | ||||
self.extra_args = [[ | self.extra_args = [ | ||||
[ | |||||
"-whitelist=noban@127.0.0.1", | "-whitelist=noban@127.0.0.1", | ||||
"-automaticunparking=1", | "-automaticunparking=1", | ||||
]] | ] | ||||
] | |||||
def next_block(self, number): | def next_block(self, number): | ||||
if self.tip is None: | if self.tip is None: | ||||
base_block_hash = self.genesis_hash | base_block_hash = self.genesis_hash | ||||
block_time = int(time.time()) + 1 | block_time = int(time.time()) + 1 | ||||
else: | else: | ||||
base_block_hash = self.tip.sha256 | base_block_hash = self.tip.sha256 | ||||
block_time = self.tip.nTime + 1 | block_time = self.tip.nTime + 1 | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
node.invalidateblock(self.blocks[1].hash) | node.invalidateblock(self.blocks[1].hash) | ||||
assert_equal(self.blocks[0].hash, node.getbestblockhash()) | assert_equal(self.blocks[0].hash, node.getbestblockhash()) | ||||
node.invalidateblock(self.blocks[2].hash) | node.invalidateblock(self.blocks[2].hash) | ||||
assert_equal(self.blocks[0].hash, node.getbestblockhash()) | assert_equal(self.blocks[0].hash, node.getbestblockhash()) | ||||
# Mining on top of blocks 1 or 2 is rejected | # Mining on top of blocks 1 or 2 is rejected | ||||
self.set_tip(1) | self.set_tip(1) | ||||
peer.send_blocks_and_test( | peer.send_blocks_and_test( | ||||
[block(11)], node, success=False, force_send=True, reject_reason='bad-prevblk') | [block(11)], | ||||
node, | |||||
success=False, | |||||
force_send=True, | |||||
reject_reason="bad-prevblk", | |||||
) | |||||
self.set_tip(2) | self.set_tip(2) | ||||
peer.send_blocks_and_test( | peer.send_blocks_and_test( | ||||
[block(21)], node, success=False, force_send=True, reject_reason='bad-prevblk') | [block(21)], | ||||
node, | |||||
success=False, | |||||
force_send=True, | |||||
reject_reason="bad-prevblk", | |||||
) | |||||
# Reconsider block 2 to remove invalid status from *both* 1 and 2 | # Reconsider block 2 to remove invalid status from *both* 1 and 2 | ||||
# The goal is to test that block 1 is not retaining any internal state | # The goal is to test that block 1 is not retaining any internal state | ||||
# that prevents us from accepting blocks building on top of block 1 | # that prevents us from accepting blocks building on top of block 1 | ||||
node.reconsiderblock(self.blocks[2].hash) | node.reconsiderblock(self.blocks[2].hash) | ||||
assert_equal(self.blocks[2].hash, node.getbestblockhash()) | assert_equal(self.blocks[2].hash, node.getbestblockhash()) | ||||
# Mining on the block 1 chain should be accepted | # Mining on the block 1 chain should be accepted | ||||
# (needs to mine two blocks because less-work chains are not processed) | # (needs to mine two blocks because less-work chains are not processed) | ||||
self.set_tip(1) | self.set_tip(1) | ||||
peer.send_blocks_and_test([block(12), block(13)], node) | peer.send_blocks_and_test([block(12), block(13)], node) | ||||
# Mining on the block 2 chain should still be accepted | # Mining on the block 2 chain should still be accepted | ||||
# (needs to mine two blocks because less-work chains are not processed) | # (needs to mine two blocks because less-work chains are not processed) | ||||
self.set_tip(2) | self.set_tip(2) | ||||
peer.send_blocks_and_test([block(22), block(221)], node) | peer.send_blocks_and_test([block(22), block(221)], node) | ||||
# Mine more blocks from block 22 to be longest chain | # Mine more blocks from block 22 to be longest chain | ||||
self.set_tip(22) | self.set_tip(22) | ||||
peer.send_blocks_and_test([block(23), block(24)], node) | peer.send_blocks_and_test([block(23), block(24)], node) | ||||
# Sanity checks | # Sanity checks | ||||
assert_equal(self.blocks[24].hash, node.getbestblockhash()) | assert_equal(self.blocks[24].hash, node.getbestblockhash()) | ||||
assert any(self.blocks[221].hash == chaintip["hash"] | assert any( | ||||
for chaintip in node.getchaintips()) | self.blocks[221].hash == chaintip["hash"] | ||||
for chaintip in node.getchaintips() | |||||
) | |||||
# Invalidating the block 2 chain should reject new blocks on that chain | # Invalidating the block 2 chain should reject new blocks on that chain | ||||
node.invalidateblock(self.blocks[2].hash) | node.invalidateblock(self.blocks[2].hash) | ||||
assert_equal(self.blocks[13].hash, node.getbestblockhash()) | assert_equal(self.blocks[13].hash, node.getbestblockhash()) | ||||
# Mining on the block 2 chain should be rejected | # Mining on the block 2 chain should be rejected | ||||
self.set_tip(24) | self.set_tip(24) | ||||
peer.send_blocks_and_test( | peer.send_blocks_and_test( | ||||
[block(25)], node, success=False, force_send=True, reject_reason='bad-prevblk') | [block(25)], | ||||
node, | |||||
success=False, | |||||
force_send=True, | |||||
reject_reason="bad-prevblk", | |||||
) | |||||
# Continued mining on the block 1 chain is still ok | # Continued mining on the block 1 chain is still ok | ||||
self.set_tip(13) | self.set_tip(13) | ||||
peer.send_blocks_and_test([block(14)], node) | peer.send_blocks_and_test([block(14)], node) | ||||
# Mining on a once-valid chain forking from block 2's longest chain, | # Mining on a once-valid chain forking from block 2's longest chain, | ||||
# which is now invalid, should also be rejected. | # which is now invalid, should also be rejected. | ||||
self.set_tip(221) | self.set_tip(221) | ||||
peer.send_blocks_and_test( | peer.send_blocks_and_test( | ||||
[block(222)], node, success=False, force_send=True, reject_reason='bad-prevblk') | [block(222)], | ||||
node, | |||||
success=False, | |||||
force_send=True, | |||||
reject_reason="bad-prevblk", | |||||
) | |||||
self.log.info( | self.log.info( | ||||
"Make sure that reconsidering a block behaves correctly when cousin chains (neither ancestors nor descendants) become available as a result") | "Make sure that reconsidering a block behaves correctly when cousin chains" | ||||
" (neither ancestors nor descendants) become available as a result" | |||||
) | |||||
# Reorg out 14 with four blocks. | # Reorg out 14 with four blocks. | ||||
self.set_tip(13) | self.set_tip(13) | ||||
peer.send_blocks_and_test( | peer.send_blocks_and_test([block(15), block(16), block(17), block(18)], node) | ||||
[block(15), block(16), block(17), block(18)], node) | |||||
# Invalidate 17 (so 18 now has failed parent) | # Invalidate 17 (so 18 now has failed parent) | ||||
node.invalidateblock(self.blocks[17].hash) | node.invalidateblock(self.blocks[17].hash) | ||||
assert_equal(self.blocks[16].hash, node.getbestblockhash()) | assert_equal(self.blocks[16].hash, node.getbestblockhash()) | ||||
# Invalidate 13 (so 14 and 15 and 16 now also have failed parent) | # Invalidate 13 (so 14 and 15 and 16 now also have failed parent) | ||||
node.invalidateblock(self.blocks[13].hash) | node.invalidateblock(self.blocks[13].hash) | ||||
assert_equal(self.blocks[12].hash, node.getbestblockhash()) | assert_equal(self.blocks[12].hash, node.getbestblockhash()) | ||||
# Reconsider 14, which should reconsider 13 and remove failed parent | # Reconsider 14, which should reconsider 13 and remove failed parent | ||||
# from our cousins 15 and 16 as well. Even though we reconsidered | # from our cousins 15 and 16 as well. Even though we reconsidered | ||||
# 14, we end up on a different chain because 15/16 have more work. | # 14, we end up on a different chain because 15/16 have more work. | ||||
# (But, this shouldn't undo our invalidation of 17) | # (But, this shouldn't undo our invalidation of 17) | ||||
node.reconsiderblock(self.blocks[14].hash) | node.reconsiderblock(self.blocks[14].hash) | ||||
assert_equal(self.blocks[16].hash, node.getbestblockhash()) | assert_equal(self.blocks[16].hash, node.getbestblockhash()) | ||||
if __name__ == '__main__': | if __name__ == "__main__": | ||||
InvalidChainsTest().main() | InvalidChainsTest().main() |