diff --git a/chia/_tests/core/custom_types/test_proof_of_space.py b/chia/_tests/core/custom_types/test_proof_of_space.py index 7bddd83d3696..5a157d0adb80 100644 --- a/chia/_tests/core/custom_types/test_proof_of_space.py +++ b/chia/_tests/core/custom_types/test_proof_of_space.py @@ -114,7 +114,7 @@ def b32(key: str) -> bytes32: pos_challenge=bytes32(b"1" * 32), plot_size=PlotSize.make_v2(0), plot_public_key=G1Element(), - pool_public_key=G1Element(), + pool_contract_puzzle_hash=bytes32(b"1" * 32), expected_error="Plot size is lower than the minimum", ), ProofOfSpaceCase( @@ -122,21 +122,25 @@ def b32(key: str) -> bytes32: pos_challenge=bytes32(b"1" * 32), plot_size=PlotSize.make_v2(34), plot_public_key=G1Element(), - pool_public_key=G1Element(), + pool_contract_puzzle_hash=bytes32(b"1" * 32), expected_error="Plot size is higher than the maximum", ), ProofOfSpaceCase( - id="Not passing the plot filter v2", - pos_challenge=b32("3d29ea79d19b3f7e99ebf764ae53697cbe143603909873946af6ab1ece606861"), + id="v2 Not passing the plot filter", + pos_challenge=b32("8147a0c9f351fb654d5c0054d01bdd70e9def1b5c7b43212ff44acb4378956b3"), plot_size=PlotSize.make_v2(32), - pool_public_key=g1( - "b6449c2c68df97c19e884427e42ee7350982d4020571ead08732615ff39bd216bfd630b6460784982bec98b49fea79d0" - ), - plot_public_key=g1( - "879526b4e7b616cfd64984d8ad140d0798b048392a6f11e2faf09054ef467ea44dc0dab5e5edb2afdfa850c5c8b629cc" - ), + plot_public_key=G1Element(), + pool_contract_puzzle_hash=bytes32(b"1" * 32), expected_error="Did not pass the plot filter", ), + ProofOfSpaceCase( + id="v2 plot with pool pk", + pos_challenge=bytes32(b"1" * 32), + plot_size=PlotSize.make_v2(28), + plot_public_key=G1Element(), + pool_public_key=G1Element(), + expected_error="v2 plots require pool_contract_puzzle_hash, pool public key is not supported", + ), ) def test_verify_and_get_quality_string(caplog: pytest.LogCaptureFixture, case: ProofOfSpaceCase) -> None: pos = make_pos( @@ -160,15 +164,13 @@ def test_verify_and_get_quality_string(caplog: pytest.LogCaptureFixture, case: P @datacases( ProofOfSpaceCase( - id="v2 plot are not implemented", + id="v2 plot", plot_size=PlotSize.make_v2(30), - pos_challenge=b32("47deb938e145d25d7b3b3c85ca9e3972b76c01aeeb78a02fe5d3b040d282317e"), + pos_challenge=b32("a5fd5287b295a3748e8498be03c6ce3d0f682d19613c003911aa6a65527d3ba4"), plot_public_key=g1( "afa3aaf09c03885154be49216ee7fb2e4581b9c4a4d7e9cc402e27280bf0cfdbdf1b9ba674e301fd1d1450234b3b1868" ), - pool_public_key=g1( - "b6449c2c68df97c19e884427e42ee7350982d4020571ead08732615ff39bd216bfd630b6460784982bec98b49fea79d0" - ), + pool_contract_puzzle_hash=bytes32(b"1" * 32), expected_error="NotImplementedError", ), ) @@ -189,7 +191,7 @@ def test_verify_and_get_quality_string_v2(caplog: pytest.LogCaptureFixture, case pos=pos, constants=DEFAULT_CONSTANTS, original_challenge_hash=b32("0x73490e166d0b88347c37d921660b216c27316aae9a3450933d3ff3b854e5831a"), - signage_point=b32("0x7b3e23dbd438f9aceefa9827e2c5538898189987f49b06eceb7a43067e77b531"), + signage_point=b32("0xf7c1bd874da5e709d4713d60c8a70639eb1167b367a9c3787c65c1e582e2e662"), height=case.height, ) except NotImplementedError as e: diff --git a/chia/consensus/block_header_validation.py b/chia/consensus/block_header_validation.py index 3ec214a04736..b5b5acc0fbbe 100644 --- a/chia/consensus/block_header_validation.py +++ b/chia/consensus/block_header_validation.py @@ -756,10 +756,16 @@ def validate_unfinished_header_block( != constants.GENESIS_PRE_FARM_FARMER_PUZZLE_HASH ): return None, ValidationError(Err.INVALID_PREFARM) - # 20b. If pospace has a pool pk, heck pool target signature. Should not check this for genesis block. + # 20b. If pospace has a pool pk, check pool target signature. Should not check this for genesis block. elif header_block.reward_chain_block.proof_of_space.pool_public_key is not None: assert header_block.reward_chain_block.proof_of_space.pool_contract_puzzle_hash is None assert header_block.foliage.foliage_block_data.pool_signature is not None + + # v2 plots require pool contract puzzle hash, not pool pk + # TODO: todo_v2_plots add test coverage of this check + if header_block.reward_chain_block.proof_of_space.size().size_v2 is not None: + return None, ValidationError(Err.INVALID_POOL_TARGET) + if not AugSchemeMPL.verify( header_block.reward_chain_block.proof_of_space.pool_public_key, bytes(header_block.foliage.foliage_block_data.pool_target), diff --git a/chia/types/blockchain_format/proof_of_space.py b/chia/types/blockchain_format/proof_of_space.py index cb1f63128963..5d0c460c99e4 100644 --- a/chia/types/blockchain_format/proof_of_space.py +++ b/chia/types/blockchain_format/proof_of_space.py @@ -64,6 +64,11 @@ def make_pos( def get_plot_id(pos: ProofOfSpace) -> bytes32: + plot_size = pos.size() + if plot_size.size_v2 is not None: + assert pos.pool_contract_puzzle_hash is not None + return calculate_plot_id_v2(pos.pool_contract_puzzle_hash, pos.plot_public_key, plot_size.size_v2) + assert pos.pool_public_key is None or pos.pool_contract_puzzle_hash is None if pos.pool_public_key is None: assert pos.pool_contract_puzzle_hash is not None @@ -114,6 +119,10 @@ def verify_and_get_quality_string( return None plot_size = pos.size() + if plot_size.size_v2 is not None and pos.pool_contract_puzzle_hash is None: + log.error("v2 plots require pool_contract_puzzle_hash, pool public key is not supported") + return None + if not check_plot_size(constants, plot_size): return None @@ -121,7 +130,7 @@ def verify_and_get_quality_string( new_challenge: bytes32 = calculate_pos_challenge(plot_id, original_challenge_hash, signage_point) if new_challenge != pos.challenge: - log.error("Calculated pos challenge doesn't match the provided one") + log.error(f"Calculated pos challenge doesn't match the provided one {new_challenge}") return None # we use different plot filter prefix sizes depending on v1 or v2 plots @@ -204,6 +213,14 @@ def calculate_pos_challenge(plot_id: bytes32, challenge_hash: bytes32, signage_p return std_hash(calculate_plot_filter_input(plot_id, challenge_hash, signage_point)) +def calculate_plot_id_v2( + pool_contract_puzzle_hash: bytes32, + plot_public_key: G1Element, + strength: uint8, +) -> bytes32: + return std_hash(bytes(pool_contract_puzzle_hash) + bytes(plot_public_key) + bytes(strength)) + + def calculate_plot_id_pk( pool_public_key: G1Element, plot_public_key: G1Element,