Repository: bitcoin/bitcoin
File: test/functional/feature_assumevalid.py (Python)

Code before:
        self.blocks.append(block102)
        self.tip = block102.hash_int
        self.block_time += 1
        height += 1

        # Bury the assumed valid block 2100 deep
        for _ in range(2100):
            block = create_block(self.tip, create_coinbase(height), self.block_time)
            block.solve()
            self.blocks.append(block)
            self.tip = block.hash_int
            self.block_time += 1
            height += 1

        # Start node1 and node2 with assumevalid so they accept a block with a bad signature.
        self.start_node(1, extra_args=["-assumevalid=" + block102.hash_hex])
        self.start_node(2, extra_args=["-assumevalid=" + block102.hash_hex])

        p2p0 = self.nodes[0].add_p2p_connection(BaseNode())
        p2p0.send_header_for_blocks(self.blocks[0:2000])
        p2p0.send_header_for_blocks(self.blocks[2000:])

        # Send blocks to node0. Block 102 will be rejected.
        self.send_blocks_until_disconnected(p2p0)
        self.wait_until(lambda: self.nodes[0].getblockcount() >= COINBASE_MATURITY + 1)
        assert_equal(self.nodes[0].getblockcount(), COINBASE_MATURITY + 1)

        p2p1 = self.nodes[1].add_p2p_connection(BaseNode())
        p2p1.send_header_for_blocks(self.blocks[0:2000])
        p2p1.send_header_for_blocks(self.blocks[2000:])
        with self.nodes[1].assert_debug_log(expected_msgs=['Disabling signature validations at block #1', 'Enabling signature validations at block #103']):
            # Send all blocks to node1. All blocks will be accepted.
            for i in range(2202):
                p2p1.send_without_ping(msg_block(self.blocks[i]))
            # Syncing 2200 blocks can take a while on slow systems. Give it plenty of time to sync.
            p2p1.sync_with_ping(timeout=960)
        assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202)

        p2p2 = self.nodes[2].add_p2p_connection(BaseNode())
        p2p2.send_header_for_blocks(self.blocks[0:200])

        # Send blocks to node2. Block 102 will be rejected.
        self.send_blocks_until_disconnected(p2p2)
        self.wait_until(lambda: self.nodes[2].getblockcount() >= COINBASE_MATURITY + 1)
        assert_equal(self.nodes[2].getblockcount(), COINBASE_MATURITY + 1)


if __name__ == '__main__':
    AssumeValidTest(__file__).main()


Review comment (suggestion):
nit: In case we are ever able to send away all blocks before detecting the expected log message, we could also wait for the block height before stopping the search of the log:
```suggestion
            self.wait_until(lambda: self.nodes[0].getblockcount() >= COINBASE_MATURITY + 1)
```

(Edit: I was modifying `send_blocks_until_disconnected()` and noticed a fairly high variability in how many blocks would be sent off, CI probably would have higher variability).

Code after:
        tx.vout.append(CTxOut(49 * 100000000, CScript([OP_TRUE])))

        block102 = create_block(self.tip, create_coinbase(height), self.block_time, txlist=[tx])
        self.block_time += 1
        block102.solve()
        self.blocks.append(block102)
        self.tip = block102.hash_int
        self.block_time += 1
        height += 1

        # Bury the assumed valid block 2100 deep
        for _ in range(2100):
            block = create_block(self.tip, create_coinbase(height), self.block_time)
            block.solve()
            self.blocks.append(block)
            self.tip = block.hash_int
            self.block_time += 1
            height += 1
        block_1_hash = self.blocks[0].hash_hex

        self.start_node(1, extra_args=[f"-assumevalid={block102.hash_hex}"])
        self.start_node(2, extra_args=[f"-assumevalid={block102.hash_hex}"])
        self.start_node(3, extra_args=[f"-assumevalid={block102.hash_hex}"])
        self.start_node(4, extra_args=[f"-assumevalid={block102.hash_hex}"])
        self.start_node(5)


        # nodes[0]
        # Send blocks to node0. Block 102 will be rejected.
        with self.nodes[0].assert_debug_log(expected_msgs=[
            f"Enabling script verification at block #1 ({block_1_hash}): assumevalid=0 (always verify).",
            "Block validation error: block-script-verify-flag-failed",
        ]):
            p2p0 = self.nodes[0].add_p2p_connection(BaseNode())

            p2p0.send_header_for_blocks(self.blocks[0:2000])
            p2p0.send_header_for_blocks(self.blocks[2000:])

            self.send_blocks_until_disconnected(p2p0)
            self.wait_until(lambda: self.nodes[0].getblockcount() >= COINBASE_MATURITY + 1)
            assert_equal(self.nodes[0].getblockcount(), COINBASE_MATURITY + 1)


        # nodes[1]
        with self.nodes[1].assert_debug_log(expected_msgs=[
            f"Disabling script verification at block #1 ({self.blocks[0].hash_hex}).",
            f"Enabling script verification at block #103 ({self.blocks[102].hash_hex}): block height above assumevalid height.",
        ]):
            p2p1 = self.nodes[1].add_p2p_connection(BaseNode())

            p2p1.send_header_for_blocks(self.blocks[0:2000])