From 1388be2c424d1f7e369e95b5efaa07a01ad31eed Mon Sep 17 00:00:00 2001 From: arvidn Date: Wed, 15 Oct 2025 10:12:57 +0200 Subject: [PATCH 1/2] minor simplification of block header validation test. Run it for all consensus modes --- chia/_tests/blockchain/test_blockchain.py | 49 ++++++++++++----------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/chia/_tests/blockchain/test_blockchain.py b/chia/_tests/blockchain/test_blockchain.py index e0de389d4d3a..1dd26a27710d 100644 --- a/chia/_tests/blockchain/test_blockchain.py +++ b/chia/_tests/blockchain/test_blockchain.py @@ -160,12 +160,13 @@ async def test_genesis_validate_1(self, empty_blockchain: Blockchain, bt: BlockT class TestBlockHeaderValidation: - @pytest.mark.limit_consensus_modes(reason="save time") @pytest.mark.anyio async def test_long_chain(self, empty_blockchain: Blockchain, default_1000_blocks: list[FullBlock]) -> None: blocks = default_1000_blocks fork_info = ForkInfo(blocks[0].height - 1, blocks[0].height - 1, blocks[0].prev_header_hash) for block in blocks: + # TODO: deduplicate the test code, perhaps by parameterizing the + # test if ( len(block.finished_sub_slots) > 0 and block.finished_sub_slots[0].challenge_chain.subepoch_summary_hash is not None @@ -195,88 +196,88 @@ async def test_long_chain(self, empty_blockchain: Blockchain, default_1000_block empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info ) - new_finished_ss_2 = recursive_replace( + new_finished_ss = recursive_replace( block.finished_sub_slots[0], "challenge_chain.new_difficulty", uint64(10_000_000), ) - block_bad_2 = recursive_replace( - block, "finished_sub_slots", [new_finished_ss_2, *block.finished_sub_slots[1:]] + block_bad = recursive_replace( + block, "finished_sub_slots", [new_finished_ss, *block.finished_sub_slots[1:]] ) - header_block_bad_2 = get_block_header(block_bad_2) + header_block_bad = get_block_header(block_bad) # TODO: Inspect these block values as they are currently None expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0) expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0) expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None) _, error = validate_finished_header_block( - empty_blockchain.constants, empty_blockchain, header_block_bad_2, False, expected_vs + empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs ) assert error is not None assert error.code == Err.INVALID_NEW_DIFFICULTY # Also fails calling the outer methods, but potentially with a different error await _validate_and_add_block( - empty_blockchain, block_bad_2, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info + empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info ) # 3c - new_finished_ss_3: EndOfSubSlotBundle = recursive_replace( + new_finished_ss = recursive_replace( block.finished_sub_slots[0], "challenge_chain.subepoch_summary_hash", bytes([0] * 32), ) - new_finished_ss_3 = recursive_replace( - new_finished_ss_3, + new_finished_ss = recursive_replace( + new_finished_ss, "reward_chain.challenge_chain_sub_slot_hash", - new_finished_ss_3.challenge_chain.get_hash(), + new_finished_ss.challenge_chain.get_hash(), ) log.warning(f"Number of slots: {len(block.finished_sub_slots)}") - block_bad_3 = recursive_replace(block, "finished_sub_slots", [new_finished_ss_3]) + block_bad = recursive_replace(block, "finished_sub_slots", [new_finished_ss]) - header_block_bad_3 = get_block_header(block_bad_3) + header_block_bad = get_block_header(block_bad) # TODO: Inspect these block values as they are currently None expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0) expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0) expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None) _, error = validate_finished_header_block( - empty_blockchain.constants, empty_blockchain, header_block_bad_3, False, expected_vs + empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs ) assert error is not None assert error.code == Err.INVALID_SUB_EPOCH_SUMMARY # Also fails calling the outer methods, but potentially with a different error await _validate_and_add_block( - empty_blockchain, block_bad_3, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info + empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info ) # 3d - new_finished_ss_4 = recursive_replace( + new_finished_ss = recursive_replace( block.finished_sub_slots[0], "challenge_chain.subepoch_summary_hash", std_hash(b"123"), ) - new_finished_ss_4 = recursive_replace( - new_finished_ss_4, + new_finished_ss = recursive_replace( + new_finished_ss, "reward_chain.challenge_chain_sub_slot_hash", - new_finished_ss_4.challenge_chain.get_hash(), + new_finished_ss.challenge_chain.get_hash(), ) - block_bad_4 = recursive_replace(block, "finished_sub_slots", [new_finished_ss_4]) + block_bad = recursive_replace(block, "finished_sub_slots", [new_finished_ss]) - header_block_bad_4 = get_block_header(block_bad_4) + header_block_bad = get_block_header(block_bad) # TODO: Inspect these block values as they are currently None expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0) expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0) expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None) _, error = validate_finished_header_block( - empty_blockchain.constants, empty_blockchain, header_block_bad_4, False, expected_vs + empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs ) assert error is not None assert error.code == Err.INVALID_SUB_EPOCH_SUMMARY # Also fails calling the outer methods, but potentially with a different error await _validate_and_add_block( - empty_blockchain, block_bad_4, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info + empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info ) await _validate_and_add_block(empty_blockchain, block, fork_info=fork_info) log.info( @@ -1443,7 +1444,7 @@ async def test_pool_target_contract( new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key) block_bad = recursive_replace(block_bad, "foliage.foliage_block_data_signature", new_fsb_sig) await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POOL_TARGET) - return None + return attempts += 1 @pytest.mark.anyio From d30bcebd248ec64d6f268bf5bd72fad4a90dc0a6 Mon Sep 17 00:00:00 2001 From: arvidn Date: Wed, 15 Oct 2025 11:14:54 +0200 Subject: [PATCH 2/2] reduce indentation level in test_long_chain() --- chia/_tests/blockchain/test_blockchain.py | 205 +++++++++++----------- 1 file changed, 103 insertions(+), 102 deletions(-) diff --git a/chia/_tests/blockchain/test_blockchain.py b/chia/_tests/blockchain/test_blockchain.py index 1dd26a27710d..503a7b10f3c8 100644 --- a/chia/_tests/blockchain/test_blockchain.py +++ b/chia/_tests/blockchain/test_blockchain.py @@ -165,120 +165,121 @@ async def test_long_chain(self, empty_blockchain: Blockchain, default_1000_block blocks = default_1000_blocks fork_info = ForkInfo(blocks[0].height - 1, blocks[0].height - 1, blocks[0].prev_header_hash) for block in blocks: - # TODO: deduplicate the test code, perhaps by parameterizing the - # test if ( - len(block.finished_sub_slots) > 0 - and block.finished_sub_slots[0].challenge_chain.subepoch_summary_hash is not None + len(block.finished_sub_slots) == 0 + or block.finished_sub_slots[0].challenge_chain.subepoch_summary_hash is None ): - # Sub/Epoch. Try using a bad ssi and difficulty to test 2m and 2n - new_finished_ss = recursive_replace( - block.finished_sub_slots[0], - "challenge_chain.new_sub_slot_iters", - uint64(10_000_000), - ) - block_bad = recursive_replace( - block, "finished_sub_slots", [new_finished_ss, *block.finished_sub_slots[1:]] - ) - header_block_bad = get_block_header(block_bad) - # TODO: Inspect these block values as they are currently None - expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0) - expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0) - expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None) - _, error = validate_finished_header_block( - empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs - ) - assert error is not None - assert error.code == Err.INVALID_NEW_SUB_SLOT_ITERS + await _validate_and_add_block(empty_blockchain, block, fork_info=fork_info) + continue - # Also fails calling the outer methods, but potentially with a different error - await _validate_and_add_block( - empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info - ) + # TODO: deduplicate the test code, perhaps by parameterizing the + # test - new_finished_ss = recursive_replace( - block.finished_sub_slots[0], - "challenge_chain.new_difficulty", - uint64(10_000_000), - ) - block_bad = recursive_replace( - block, "finished_sub_slots", [new_finished_ss, *block.finished_sub_slots[1:]] - ) + # Sub/Epoch. Try using a bad ssi and difficulty to test 2m and 2n + new_finished_ss = recursive_replace( + block.finished_sub_slots[0], + "challenge_chain.new_sub_slot_iters", + uint64(10_000_000), + ) + block_bad = recursive_replace(block, "finished_sub_slots", [new_finished_ss, *block.finished_sub_slots[1:]]) + header_block_bad = get_block_header(block_bad) + # TODO: Inspect these block values as they are currently None + expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0) + expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0) + expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None) + _, error = validate_finished_header_block( + empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs + ) + assert error is not None + assert error.code == Err.INVALID_NEW_SUB_SLOT_ITERS - header_block_bad = get_block_header(block_bad) - # TODO: Inspect these block values as they are currently None - expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0) - expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0) - expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None) - _, error = validate_finished_header_block( - empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs - ) - assert error is not None - assert error.code == Err.INVALID_NEW_DIFFICULTY + # Also fails calling the outer methods, but potentially with a different error + await _validate_and_add_block( + empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info + ) - # Also fails calling the outer methods, but potentially with a different error - await _validate_and_add_block( - empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info - ) + new_finished_ss = recursive_replace( + block.finished_sub_slots[0], + "challenge_chain.new_difficulty", + uint64(10_000_000), + ) + block_bad = recursive_replace(block, "finished_sub_slots", [new_finished_ss, *block.finished_sub_slots[1:]]) + + header_block_bad = get_block_header(block_bad) + # TODO: Inspect these block values as they are currently None + expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0) + expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0) + expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None) + _, error = validate_finished_header_block( + empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs + ) + assert error is not None + assert error.code == Err.INVALID_NEW_DIFFICULTY - # 3c - new_finished_ss = recursive_replace( - block.finished_sub_slots[0], - "challenge_chain.subepoch_summary_hash", - bytes([0] * 32), - ) - new_finished_ss = recursive_replace( - new_finished_ss, - "reward_chain.challenge_chain_sub_slot_hash", - new_finished_ss.challenge_chain.get_hash(), - ) - log.warning(f"Number of slots: {len(block.finished_sub_slots)}") - block_bad = recursive_replace(block, "finished_sub_slots", [new_finished_ss]) + # Also fails calling the outer methods, but potentially with a different error + await _validate_and_add_block( + empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info + ) - header_block_bad = get_block_header(block_bad) - # TODO: Inspect these block values as they are currently None - expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0) - expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0) - expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None) - _, error = validate_finished_header_block( - empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs - ) - assert error is not None - assert error.code == Err.INVALID_SUB_EPOCH_SUMMARY + # 3c + new_finished_ss = recursive_replace( + block.finished_sub_slots[0], + "challenge_chain.subepoch_summary_hash", + bytes([0] * 32), + ) + new_finished_ss = recursive_replace( + new_finished_ss, + "reward_chain.challenge_chain_sub_slot_hash", + new_finished_ss.challenge_chain.get_hash(), + ) + log.warning(f"Number of slots: {len(block.finished_sub_slots)}") + block_bad = recursive_replace(block, "finished_sub_slots", [new_finished_ss]) + + header_block_bad = get_block_header(block_bad) + # TODO: Inspect these block values as they are currently None + expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0) + expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0) + expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None) + _, error = validate_finished_header_block( + empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs + ) + assert error is not None + assert error.code == Err.INVALID_SUB_EPOCH_SUMMARY - # Also fails calling the outer methods, but potentially with a different error - await _validate_and_add_block( - empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info - ) + # Also fails calling the outer methods, but potentially with a different error + await _validate_and_add_block( + empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info + ) - # 3d - new_finished_ss = recursive_replace( - block.finished_sub_slots[0], - "challenge_chain.subepoch_summary_hash", - std_hash(b"123"), - ) - new_finished_ss = recursive_replace( - new_finished_ss, - "reward_chain.challenge_chain_sub_slot_hash", - new_finished_ss.challenge_chain.get_hash(), - ) - block_bad = recursive_replace(block, "finished_sub_slots", [new_finished_ss]) + # 3d + new_finished_ss = recursive_replace( + block.finished_sub_slots[0], + "challenge_chain.subepoch_summary_hash", + std_hash(b"123"), + ) + new_finished_ss = recursive_replace( + new_finished_ss, + "reward_chain.challenge_chain_sub_slot_hash", + new_finished_ss.challenge_chain.get_hash(), + ) + block_bad = recursive_replace(block, "finished_sub_slots", [new_finished_ss]) + + header_block_bad = get_block_header(block_bad) + # TODO: Inspect these block values as they are currently None + expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0) + expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0) + expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None) + _, error = validate_finished_header_block( + empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs + ) + assert error is not None + assert error.code == Err.INVALID_SUB_EPOCH_SUMMARY - header_block_bad = get_block_header(block_bad) - # TODO: Inspect these block values as they are currently None - expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0) - expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0) - expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None) - _, error = validate_finished_header_block( - empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs - ) - assert error is not None - assert error.code == Err.INVALID_SUB_EPOCH_SUMMARY + # Also fails calling the outer methods, but potentially with a different error + await _validate_and_add_block( + empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info + ) - # Also fails calling the outer methods, but potentially with a different error - await _validate_and_add_block( - empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info - ) await _validate_and_add_block(empty_blockchain, block, fork_info=fork_info) log.info( f"Added block {block.height} total iters {block.total_iters} new slot? {len(block.finished_sub_slots)}"