support backrefs in the clvm serialization passed in- and out of get_puzzle_solution()
This commit is contained in:
parent
17dcb71b8a
commit
cb04e96d94
|
@ -418,7 +418,7 @@ class SimClient:
|
|||
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)
|
||||
spend_info = get_puzzle_and_solution_for_coin(generator, coin_record.coin, 0)
|
||||
return CoinSpend(coin_record.coin, spend_info.puzzle, spend_info.solution)
|
||||
|
||||
async def get_all_mempool_tx_ids(self) -> List[bytes32]:
|
||||
|
|
|
@ -12,7 +12,9 @@ from secrets import token_bytes
|
|||
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 packaging.version import Version
|
||||
|
||||
from chia.consensus.block_creation import create_unfinished_block
|
||||
from chia.consensus.block_record import BlockRecord
|
||||
|
@ -1279,8 +1281,10 @@ class FullNodeAPI:
|
|||
response = wallet_protocol.TransactionAck(spend_name, uint8(status.value), error_name)
|
||||
return make_msg(ProtocolMessageTypes.transaction_ack, response)
|
||||
|
||||
@api_request()
|
||||
async def request_puzzle_solution(self, request: wallet_protocol.RequestPuzzleSolution) -> Optional[Message]:
|
||||
@api_request(peer_required=True)
|
||||
async def request_puzzle_solution(
|
||||
self, request: wallet_protocol.RequestPuzzleSolution, peer: WSChiaConnection
|
||||
) -> Optional[Message]:
|
||||
coin_name = request.coin_name
|
||||
height = request.height
|
||||
coin_record = await self.full_node.coin_store.get_coin_record(coin_name)
|
||||
|
@ -1301,8 +1305,13 @@ class FullNodeAPI:
|
|||
block_generator: Optional[BlockGenerator] = await self.full_node.blockchain.get_block_generator(block)
|
||||
assert block_generator is not None
|
||||
try:
|
||||
flags = 0
|
||||
# allow backrefs in puzzle and solution serializations in the next
|
||||
# version of the full node protocol
|
||||
if peer.protocol_version > Version("0.0.34"):
|
||||
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
|
||||
self.executor, get_puzzle_and_solution_for_coin, block_generator, coin_record.coin, flags
|
||||
)
|
||||
except ValueError:
|
||||
return reject_msg
|
||||
|
|
|
@ -59,7 +59,7 @@ 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) -> SpendInfo:
|
||||
def get_puzzle_and_solution_for_coin(generator: BlockGenerator, coin: Coin, flags: int) -> SpendInfo:
|
||||
try:
|
||||
args = bytearray(b"\xff")
|
||||
args += bytes(DESERIALIZE_MOD)
|
||||
|
@ -74,7 +74,7 @@ def get_puzzle_and_solution_for_coin(generator: BlockGenerator, coin: Coin) -> S
|
|||
coin.parent_coin_info,
|
||||
coin.amount,
|
||||
coin.puzzle_hash,
|
||||
0,
|
||||
flags,
|
||||
)
|
||||
return SpendInfo(SerializedProgram.from_bytes(puzzle), SerializedProgram.from_bytes(solution))
|
||||
except Exception as e:
|
||||
|
|
|
@ -695,7 +695,7 @@ class FullNodeRpcApi:
|
|||
|
||||
block_generator: Optional[BlockGenerator] = await self.service.blockchain.get_block_generator(block)
|
||||
assert block_generator is not None
|
||||
spend_info = get_puzzle_and_solution_for_coin(block_generator, coin_record.coin)
|
||||
spend_info = get_puzzle_and_solution_for_coin(block_generator, coin_record.coin, 0)
|
||||
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:
|
||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||
import io
|
||||
from typing import Any, Callable, Dict, Set, Tuple
|
||||
|
||||
from chia_rs import run_chia_program, tree_hash
|
||||
from chia_rs import ALLOW_BACKREFS, run_chia_program, tree_hash
|
||||
from clvm import SExp
|
||||
from clvm.casts import int_from_bytes
|
||||
from clvm.EvalError import EvalError
|
||||
|
@ -40,7 +40,7 @@ class Program(SExp):
|
|||
b"\x01",
|
||||
blob,
|
||||
50,
|
||||
0,
|
||||
ALLOW_BACKREFS,
|
||||
)
|
||||
return Program.to(ret)
|
||||
|
||||
|
@ -110,7 +110,7 @@ class Program(SExp):
|
|||
|
||||
def run_with_cost(self, max_cost: int, args) -> Tuple[int, "Program"]:
|
||||
prog_args = Program.to(args)
|
||||
cost, r = run_chia_program(self.as_bin(), prog_args.as_bin(), max_cost, 0)
|
||||
cost, r = run_chia_program(self.as_bin(), prog_args.as_bin(), max_cost, ALLOW_BACKREFS)
|
||||
return cost, Program.to(r)
|
||||
|
||||
def run(self, args) -> "Program":
|
||||
|
|
|
@ -2944,4 +2944,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)
|
||||
get_puzzle_and_solution_for_coin(BlockGenerator(SerializedProgram(), [], []), TEST_COIN, 0)
|
||||
|
|
|
@ -85,7 +85,7 @@ class TestCostCalculation:
|
|||
|
||||
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)
|
||||
spend_info = get_puzzle_and_solution_for_coin(program, coin_spend.coin, 0)
|
||||
assert spend_info.puzzle == coin_spend.puzzle_reveal
|
||||
assert spend_info.solution == coin_spend.solution
|
||||
|
||||
|
@ -155,7 +155,7 @@ class TestCostCalculation:
|
|||
bytes32.fromhex("14947eb0e69ee8fc8279190fc2d38cb4bbb61ba28f1a270cfd643a0e8d759576"),
|
||||
300,
|
||||
)
|
||||
spend_info = get_puzzle_and_solution_for_coin(generator, coin)
|
||||
spend_info = get_puzzle_and_solution_for_coin(generator, coin, 0)
|
||||
assert spend_info.puzzle.to_program() == puzzle
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
@ -273,5 +273,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)
|
||||
spend_info = get_puzzle_and_solution_for_coin(generator, c, 0)
|
||||
assert spend_info.puzzle.get_tree_hash() == c.puzzle_hash
|
||||
|
|
|
@ -6,6 +6,7 @@ from dataclasses import dataclass
|
|||
from typing import Any, List
|
||||
|
||||
import pytest
|
||||
from chia_rs import ALLOW_BACKREFS
|
||||
from clvm import SExp
|
||||
from clvm.serialize import sexp_from_stream
|
||||
from clvm_tools import binutils
|
||||
|
@ -158,12 +159,12 @@ class TestCompression:
|
|||
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)
|
||||
spend_info = get_puzzle_and_solution_for_coin(c, removal, 0)
|
||||
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)
|
||||
spend_info = get_puzzle_and_solution_for_coin(s, removal, 0)
|
||||
assert bytes(spend_info.puzzle) == bytes(sb.coin_spends[0].puzzle_reveal)
|
||||
assert bytes(spend_info.solution) == bytes(sb.coin_spends[0].solution)
|
||||
|
||||
|
|
Loading…
Reference in New Issue