Compare commits

...

1 Commits

8 changed files with 26 additions and 16 deletions

View File

@ -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]:

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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":

View File

@ -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)

View File

@ -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

View File

@ -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)