diff --git a/chia/clvm/spend_sim.py b/chia/clvm/spend_sim.py index 08fa238ed179..55c7de28d95d 100644 --- a/chia/clvm/spend_sim.py +++ b/chia/clvm/spend_sim.py @@ -422,7 +422,7 @@ async def get_puzzle_and_solution(self, coin_id: bytes32, height: uint32) -> Coi generator: BlockGenerator = filtered_generators[0].transactions_generator # type: ignore[assignment] coin_record = await self.service.coin_store.get_coin_record(coin_id) assert coin_record is not None - spend_info = get_puzzle_and_solution_for_coin(generator, coin_record.coin, 0) + spend_info = get_puzzle_and_solution_for_coin(generator, coin_record.coin, height, self.service.defaults) return CoinSpend(coin_record.coin, spend_info.puzzle, spend_info.solution) async def get_all_mempool_tx_ids(self) -> List[bytes32]: diff --git a/chia/full_node/full_node_api.py b/chia/full_node/full_node_api.py index bac43bc41091..38f014137e4a 100644 --- a/chia/full_node/full_node_api.py +++ b/chia/full_node/full_node_api.py @@ -12,7 +12,6 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple from blspy import AugSchemeMPL, G1Element, G2Element -from chia_rs import ALLOW_BACKREFS from chiabip158 import PyBIP158 from chia.consensus.block_creation import create_unfinished_block @@ -1323,12 +1322,13 @@ async def request_puzzle_solution(self, request: wallet_protocol.RequestPuzzleSo block_generator: Optional[BlockGenerator] = await self.full_node.blockchain.get_block_generator(block) assert block_generator is not None try: - flags = 0 - if height >= self.full_node.constants.HARD_FORK_HEIGHT: - flags = ALLOW_BACKREFS - spend_info = await asyncio.get_running_loop().run_in_executor( - self.executor, get_puzzle_and_solution_for_coin, block_generator, coin_record.coin, flags + self.executor, + get_puzzle_and_solution_for_coin, + block_generator, + coin_record.coin, + height, + self.full_node.constants, ) except ValueError: return reject_msg diff --git a/chia/full_node/mempool_check_conditions.py b/chia/full_node/mempool_check_conditions.py index 5c77b540424b..289e97a45157 100644 --- a/chia/full_node/mempool_check_conditions.py +++ b/chia/full_node/mempool_check_conditions.py @@ -43,19 +43,8 @@ log = logging.getLogger(__name__) -def get_name_puzzle_conditions( - generator: BlockGenerator, - max_cost: int, - *, - mempool_mode: bool, - height: uint32, - constants: ConsensusConstants, -) -> NPCResult: - run_block = run_block_generator - - flags = 0 - if mempool_mode: - flags = flags | MEMPOOL_MODE +def get_flags_for_height_and_constants(height: int, constants: ConsensusConstants) -> int: + flags = ENABLE_ASSERT_BEFORE | NO_RELATIVE_CONDITIONS_ON_EPHEMERAL if height >= constants.SOFT_FORK2_HEIGHT: flags = flags | ENABLE_ASSERT_BEFORE | NO_RELATIVE_CONDITIONS_ON_EPHEMERAL @@ -93,6 +82,23 @@ def get_name_puzzle_conditions( | ALLOW_BACKREFS ) + return flags + + +def get_name_puzzle_conditions( + generator: BlockGenerator, + max_cost: int, + *, + mempool_mode: bool, + height: uint32, + constants: ConsensusConstants, +) -> NPCResult: + run_block = run_block_generator + flags = get_flags_for_height_and_constants(height, constants) + + if mempool_mode: + flags = flags | MEMPOOL_MODE + if height >= constants.HARD_FORK_FIX_HEIGHT: run_block = run_block_generator2 @@ -110,7 +116,9 @@ def get_name_puzzle_conditions( return NPCResult(uint16(Err.GENERATOR_RUNTIME_ERROR.value), None, uint64(0)) -def get_puzzle_and_solution_for_coin(generator: BlockGenerator, coin: Coin, flags: int) -> SpendInfo: +def get_puzzle_and_solution_for_coin( + generator: BlockGenerator, coin: Coin, height: int, constants: ConsensusConstants +) -> SpendInfo: try: args = bytearray(b"\xff") args += bytes(DESERIALIZE_MOD) @@ -125,14 +133,14 @@ def get_puzzle_and_solution_for_coin(generator: BlockGenerator, coin: Coin, flag coin.parent_coin_info, coin.amount, coin.puzzle_hash, - flags, + get_flags_for_height_and_constants(height, constants), ) return SpendInfo(SerializedProgram.from_bytes(puzzle), SerializedProgram.from_bytes(solution)) except Exception as e: raise ValueError(f"Failed to get puzzle and solution for coin {coin}, error: {e}") from e -def get_spends_for_block(generator: BlockGenerator) -> List[CoinSpend]: +def get_spends_for_block(generator: BlockGenerator, height: int, constants: ConsensusConstants) -> List[CoinSpend]: args = bytearray(b"\xff") args += bytes(DESERIALIZE_MOD) args += b"\xff" @@ -143,7 +151,7 @@ def get_spends_for_block(generator: BlockGenerator) -> List[CoinSpend]: bytes(generator.program), bytes(args), DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM, - 0, + get_flags_for_height_and_constants(height, constants), ) spends: List[CoinSpend] = [] diff --git a/chia/rpc/full_node_rpc_api.py b/chia/rpc/full_node_rpc_api.py index 9ee1be05c659..8627986f708c 100644 --- a/chia/rpc/full_node_rpc_api.py +++ b/chia/rpc/full_node_rpc_api.py @@ -3,8 +3,6 @@ from datetime import datetime, timezone from typing import Any, Dict, List, Optional -from chia_rs import ALLOW_BACKREFS - from chia.consensus.block_record import BlockRecord from chia.consensus.blockchain import Blockchain, BlockchainMutexPriority from chia.consensus.cost_calculator import NPCResult @@ -478,7 +476,7 @@ async def get_block_spends(self, request: Dict[str, Any]) -> EndpointResult: if block_generator is None: # if block is not a transaction block. return {"block_spends": spends} - spends = get_spends_for_block(block_generator) + spends = get_spends_for_block(block_generator, full_block.height, self.service.constants) return {"block_spends": spends} @@ -745,11 +743,10 @@ async def get_puzzle_and_solution(self, request: Dict[str, Any]) -> EndpointResu block_generator: Optional[BlockGenerator] = await self.service.blockchain.get_block_generator(block) assert block_generator is not None - flags = 0 - if height >= self.service.constants.HARD_FORK_HEIGHT: - flags = ALLOW_BACKREFS - spend_info = get_puzzle_and_solution_for_coin(block_generator, coin_record.coin, flags) + spend_info = get_puzzle_and_solution_for_coin( + block_generator, coin_record.coin, block.height, self.service.constants + ) return {"coin_solution": CoinSpend(coin_record.coin, spend_info.puzzle, spend_info.solution)} async def get_additions_and_removals(self, request: Dict[str, Any]) -> EndpointResult: diff --git a/tests/core/mempool/test_mempool.py b/tests/core/mempool/test_mempool.py index 2775658e6f51..b03c987c1848 100644 --- a/tests/core/mempool/test_mempool.py +++ b/tests/core/mempool/test_mempool.py @@ -2971,4 +2971,4 @@ def test_get_puzzle_and_solution_for_coin_failure(): with pytest.raises( ValueError, match=f"Failed to get puzzle and solution for coin {TEST_COIN}, error: failed to fill whole buffer" ): - get_puzzle_and_solution_for_coin(BlockGenerator(SerializedProgram(), [], []), TEST_COIN, 0) + get_puzzle_and_solution_for_coin(BlockGenerator(SerializedProgram(), [], []), TEST_COIN, 0, test_constants) diff --git a/tests/core/test_cost_calculation.py b/tests/core/test_cost_calculation.py index e9b4f5d84a55..ea4a73852dff 100644 --- a/tests/core/test_cost_calculation.py +++ b/tests/core/test_cost_calculation.py @@ -89,7 +89,7 @@ async def test_basics(self, softfork_height, bt): coin_spend = spend_bundle.coin_spends[0] assert coin_spend.coin.name() == npc_result.conds.spends[0].coin_id - spend_info = get_puzzle_and_solution_for_coin(program, coin_spend.coin, 0) + spend_info = get_puzzle_and_solution_for_coin(program, coin_spend.coin, softfork_height, bt.constants) assert spend_info.puzzle == coin_spend.puzzle_reveal assert spend_info.solution == coin_spend.solution @@ -170,7 +170,7 @@ async def test_mempool_mode(self, softfork_height, bt): bytes32.fromhex("14947eb0e69ee8fc8279190fc2d38cb4bbb61ba28f1a270cfd643a0e8d759576"), 300, ) - spend_info = get_puzzle_and_solution_for_coin(generator, coin, 0) + spend_info = get_puzzle_and_solution_for_coin(generator, coin, softfork_height, bt.constants) assert spend_info.puzzle.to_program() == puzzle @pytest.mark.asyncio @@ -304,5 +304,5 @@ async def test_get_puzzle_and_solution_for_coin_performance(): with assert_runtime(seconds=7, label="get_puzzle_and_solution_for_coin"): for i in range(3): for c in spends: - spend_info = get_puzzle_and_solution_for_coin(generator, c, 0) + spend_info = get_puzzle_and_solution_for_coin(generator, c, 0, test_constants) assert spend_info.puzzle.get_tree_hash() == c.puzzle_hash diff --git a/tests/core/test_full_node_rpc.py b/tests/core/test_full_node_rpc.py index e6eb7a1f4ac9..80e0c601ce20 100644 --- a/tests/core/test_full_node_rpc.py +++ b/tests/core/test_full_node_rpc.py @@ -29,14 +29,14 @@ from chia.util.hash import std_hash from chia.util.ints import uint8 from tests.blockchain.blockchain_test_utils import _validate_and_add_block +from tests.conftest import ConsensusMode from tests.connection_utils import connect_and_get_peer from tests.util.rpc import validate_get_routes class TestRpc: - @pytest.mark.limit_consensus_modes(reason="does not depend on consensus rules") @pytest.mark.asyncio - async def test1(self, two_nodes_sim_and_wallets_services, self_hostname): + async def test1(self, two_nodes_sim_and_wallets_services, self_hostname, consensus_mode): num_blocks = 5 nodes, _, bt = two_nodes_sim_and_wallets_services full_node_service_1, full_node_service_2 = nodes @@ -222,7 +222,10 @@ async def test1(self, two_nodes_sim_and_wallets_services, self_hostname): await full_node_api_1.farm_new_transaction_block(FarmNewBlockProtocol(ph_2)) block: FullBlock = (await full_node_api_1.get_all_full_blocks())[-1] - assert len(block.transactions_generator_ref_list) > 0 # compression has occurred + if consensus_mode != ConsensusMode.HARD_FORK_2_0: + # after the hard fork, we don't compress blocks using + # block references anymore + assert len(block.transactions_generator_ref_list) > 0 # compression has occurred block_spends = await client.get_block_spends(block.header_hash) diff --git a/tests/generator/test_compression.py b/tests/generator/test_compression.py index 3c4221fe8ef6..fb3a5b8acaf9 100644 --- a/tests/generator/test_compression.py +++ b/tests/generator/test_compression.py @@ -20,6 +20,7 @@ simple_solution_generator_backrefs, ) from chia.full_node.mempool_check_conditions import get_puzzle_and_solution_for_coin +from chia.simulator.block_tools import test_constants from chia.types.blockchain_format.program import INFINITE_COST, Program from chia.types.blockchain_format.serialized_program import SerializedProgram from chia.types.generator_types import BlockGenerator, CompressorArg @@ -161,18 +162,18 @@ def test_get_removals_for_single_coin(self) -> None: ca = CompressorArg(uint32(0), SerializedProgram.from_bytes(original_generator), start, end) c = compressed_spend_bundle_solution(ca, sb) removal = sb.coin_spends[0].coin - spend_info = get_puzzle_and_solution_for_coin(c, removal, 0) + spend_info = get_puzzle_and_solution_for_coin(c, removal, 0, test_constants) assert bytes(spend_info.puzzle) == bytes(sb.coin_spends[0].puzzle_reveal) assert bytes(spend_info.solution) == bytes(sb.coin_spends[0].solution) # Test non compressed generator as well s = simple_solution_generator(sb) - spend_info = get_puzzle_and_solution_for_coin(s, removal, 0) + spend_info = get_puzzle_and_solution_for_coin(s, removal, 0, test_constants) assert bytes(spend_info.puzzle) == bytes(sb.coin_spends[0].puzzle_reveal) assert bytes(spend_info.solution) == bytes(sb.coin_spends[0].solution) # test with backrefs (2.0 hard-fork) s = simple_solution_generator_backrefs(sb) - spend_info = get_puzzle_and_solution_for_coin(s, removal, ALLOW_BACKREFS) + spend_info = get_puzzle_and_solution_for_coin(s, removal, test_constants.HARD_FORK_HEIGHT + 1, test_constants) assert Program.from_bytes(bytes(spend_info.puzzle)) == Program.from_bytes( bytes(sb.coin_spends[0].puzzle_reveal) )