diff --git a/test/functional/abc-finalize-block.py b/test/functional/abc-finalize-block.py --- a/test/functional/abc-finalize-block.py +++ b/test/functional/abc-finalize-block.py @@ -9,6 +9,7 @@ from test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes_bi, sync_blocks, wait_until RPC_FINALIZE_INVALID_BLOCK_ERROR = 'finalize-invalid-block' +RPC_BLOCK_NOT_FOUND_ERROR = 'Block not found' AUTO_FINALIZATION_DEPTH = 10 @@ -44,29 +45,53 @@ alt_node.invalidateblock(tip) # We will use this later to check auto-finalization during a reorg auto_finalized_tip = alt_node.getbestblockhash() - alt_node.generate(10) - - # Wait for node 0 to invalidate the chain. - def wait_for_invalid_block(node, block): - def check_block(): - for tip in node.getchaintips(): - if tip["hash"] == block: - assert(tip["status"] != "active") - return tip["status"] == "invalid" - return False - wait_until(check_block) - - # node do not accept alt_node's chain due to tip being finalized, - # even though it is longer. - wait_for_invalid_block(node, alt_node.getbestblockhash()) - assert_equal(node.getbestblockhash(), tip) + for i in range(9): + alt_node.generate(1) + current_block = alt_node.getbestblockhash() + + # Node 0 do not accept the whole alt_node's chain due to tip being finalized, + # even though it is longer. + # Headers would not be accepted if previousblock is invalid: + # - First block from alt node has same height than node tip, it will be accepted but inactive + # - Second block from alt node has height > node tip height, will be marked as invalid because node tip is finalized + # - Later blocks from alt node will be rejected because their previous block are invalid + + def wait_for_first_block(node, block): + def check_block(): + for tip in node.getchaintips(): + if tip["hash"] == block: + assert(tip["status"] != "active") + return tip["status"] == "valid-headers" + return False + wait_until(check_block) + + def wait_for_second_block(node, block): + def check_block(): + for tip in node.getchaintips(): + if tip["hash"] == block: + assert(tip["status"] != "active") + return tip["status"] == "invalid" + return False + wait_until(check_block) + + # First block header is accepted as valid-header + if(i == 0): + wait_for_first_block(node, current_block) + # Second block header is accepted but set invalid + elif(i == 1): + # Store for later + wait_for_second_block(node, current_block) + invalid_block = current_block + # Later block headers are rejected + else: + assert_raises_rpc_error(-5, RPC_BLOCK_NOT_FOUND_ERROR, + node.getblockheader, current_block) - # alt_node has mined 10 block, so tip must be invalid due to finalization. - wait_for_invalid_block(alt_node, tip) + assert_equal(node.getbestblockhash(), tip) self.log.info("Test that an invalid block cannot be finalized...") assert_raises_rpc_error(-20, RPC_FINALIZE_INVALID_BLOCK_ERROR, - node.finalizeblock, alt_node.getbestblockhash()) + node.finalizeblock, invalid_block) self.log.info( "Test that invalidating a finalized block moves the finalization backward...") @@ -80,7 +105,11 @@ finalized_block) # The node will now accept that chain as the finalized block moved back. - node.reconsiderblock(alt_node.getbestblockhash()) + node.reconsiderblock(invalid_block) + # Generate a new block on alt_node to trigger getheader from node + # Previous 212-219 height blocks have been droped because their previous was invalid + alt_node.generate(1) + sync_blocks(self.nodes[0:2]) assert_equal(node.getbestblockhash(), alt_node.getbestblockhash()) assert_equal(node.getfinalizedblockhash(), auto_finalized_tip)