Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc-invalid-chains.py
Show First 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | class InvalidChainsTest(BitcoinTestFramework): | ||||
def set_tip(self, number: int): | def set_tip(self, number: int): | ||||
""" | """ | ||||
Move the tip back to a previous block. | Move the tip back to a previous block. | ||||
""" | """ | ||||
self.tip = self.blocks[number] | self.tip = self.blocks[number] | ||||
def run_test(self): | def run_test(self): | ||||
node = self.nodes[0] | node = self.nodes[0] | ||||
node.add_p2p_connection(P2PDataStore()) | peer = node.add_p2p_connection(P2PDataStore()) | ||||
self.genesis_hash = int(node.getbestblockhash(), 16) | self.genesis_hash = int(node.getbestblockhash(), 16) | ||||
self.block_heights[self.genesis_hash] = 0 | self.block_heights[self.genesis_hash] = 0 | ||||
# shorthand for functions | # shorthand for functions | ||||
block = self.next_block | block = self.next_block | ||||
# Reference for blocks mined in this test: | # Reference for blocks mined in this test: | ||||
# | # | ||||
# 11 21 -- 221 - 222 | # 11 21 -- 221 - 222 | ||||
# / / / | # / / / | ||||
# 0 - 1 - 2 - 22 - 23 - 24 - 25 | # 0 - 1 - 2 - 22 - 23 - 24 - 25 | ||||
# \ | # \ | ||||
# -- 12 - 13 - 14 | # -- 12 - 13 - 14 | ||||
# \ | # \ | ||||
# -- 15 - 16 - 17 - 18 | # -- 15 - 16 - 17 - 18 | ||||
# Generate some valid blocks | # Generate some valid blocks | ||||
node.p2p.send_blocks_and_test([block(0), block(1), block(2)], node) | peer.send_blocks_and_test([block(0), block(1), block(2)], node) | ||||
# Explicitly invalidate blocks 1 and 2 | # Explicitly invalidate blocks 1 and 2 | ||||
# See below for why we do this | # See below for why we do this | ||||
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) | ||||
node.p2p.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) | ||||
node.p2p.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) | ||||
node.p2p.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) | ||||
node.p2p.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) | ||||
node.p2p.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(self.blocks[221].hash == chaintip["hash"] | ||||
for chaintip in node.getchaintips()) | 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) | ||||
node.p2p.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) | ||||
node.p2p.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) | ||||
node.p2p.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) | ||||
node.p2p.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) | ||||
Show All 12 Lines |