mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2024-09-20 16:08:51 +03:00
Leave programs in SpendBundle serialized (#2380)
This commit is contained in:
parent
a2401ccfd4
commit
8717ca4b02
@ -1,5 +1,5 @@
|
||||
import re
|
||||
from typing import Optional, Tuple, List, Any
|
||||
from typing import Optional, Tuple, List, Union
|
||||
|
||||
from clvm import SExp
|
||||
from clvm_tools import binutils
|
||||
@ -10,19 +10,19 @@ from chia.types.coin_solution import CoinSolution
|
||||
from chia.types.generator_types import BlockGenerator, CompressorArg
|
||||
from chia.types.spend_bundle import SpendBundle
|
||||
from chia.util.byte_types import hexstr_to_bytes
|
||||
from chia.util.ints import uint32
|
||||
from chia.util.ints import uint32, uint64
|
||||
|
||||
|
||||
def spend_bundle_to_coin_solution_entry_list(bundle: SpendBundle) -> List[Any]:
|
||||
r = []
|
||||
def spend_bundle_to_serialized_coin_solution_entry_list(bundle: SpendBundle) -> bytes:
|
||||
r = b""
|
||||
for coin_solution in bundle.coin_solutions:
|
||||
entry = [
|
||||
coin_solution.coin.parent_coin_info,
|
||||
coin_solution.puzzle_reveal,
|
||||
coin_solution.coin.amount,
|
||||
coin_solution.solution,
|
||||
]
|
||||
r.append(entry)
|
||||
r += b"\xff"
|
||||
r += b"\xff" + SExp.to(coin_solution.coin.parent_coin_info).as_bin()
|
||||
r += b"\xff" + bytes(coin_solution.puzzle_reveal)
|
||||
r += b"\xff" + SExp.to(coin_solution.coin.amount).as_bin()
|
||||
r += b"\xff" + bytes(coin_solution.solution)
|
||||
r += b"\x80"
|
||||
r += b"\x80"
|
||||
return r
|
||||
|
||||
|
||||
@ -30,10 +30,14 @@ def simple_solution_generator(bundle: SpendBundle) -> BlockGenerator:
|
||||
"""
|
||||
Simply quotes the solutions we know.
|
||||
"""
|
||||
cse_list = spend_bundle_to_coin_solution_entry_list(bundle)
|
||||
block_program = SerializedProgram.from_bytes(SExp.to((binutils.assemble("#q"), [cse_list])).as_bin())
|
||||
generator = BlockGenerator(block_program, [])
|
||||
return generator
|
||||
cse_list = spend_bundle_to_serialized_coin_solution_entry_list(bundle)
|
||||
block_program = b"\xff"
|
||||
|
||||
block_program += SExp.to(binutils.assemble("#q")).as_bin()
|
||||
|
||||
block_program += b"\xff" + cse_list + b"\x80"
|
||||
|
||||
return BlockGenerator(SerializedProgram.from_bytes(block_program), [])
|
||||
|
||||
|
||||
STANDARD_TRANSACTION_PUZZLE_PREFIX = r"""ff02ffff01ff02ffff01ff02ffff03ff0bffff01ff02ffff03ffff09ff05ffff1dff0bffff1effff0bff0bffff02ff06ffff04ff02ffff04ff17ff8080808080808080ffff01ff02ff17ff2f80ffff01ff088080ff0180ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff17ff80808080ff80808080ffff02ff17ff2f808080ff0180ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080ffff04ffff01""" # noqa
|
||||
@ -59,12 +63,12 @@ def match_standard_transaction_at_any_index(generator_body: bytes) -> Optional[T
|
||||
return None
|
||||
|
||||
|
||||
def match_standard_transaction_exactly_and_return_pubkey(puzzle: Program) -> Optional[bytes]:
|
||||
def match_standard_transaction_exactly_and_return_pubkey(puzzle: SerializedProgram) -> Optional[bytes]:
|
||||
m = STANDARD_TRANSACTION_PUZZLE_PATTERN.fullmatch(bytes(puzzle).hex())
|
||||
return None if m is None else hexstr_to_bytes(m.group(1))
|
||||
|
||||
|
||||
def compress_cse_puzzle(puzzle: Program):
|
||||
def compress_cse_puzzle(puzzle: SerializedProgram) -> Optional[bytes]:
|
||||
return match_standard_transaction_exactly_and_return_pubkey(puzzle)
|
||||
|
||||
|
||||
@ -72,11 +76,11 @@ def compress_coin_solution(coin_solution: CoinSolution):
|
||||
compressed_puzzle = compress_cse_puzzle(coin_solution.puzzle_reveal)
|
||||
return [
|
||||
[coin_solution.coin.parent_coin_info, coin_solution.coin.amount],
|
||||
[compressed_puzzle, coin_solution.solution],
|
||||
[compressed_puzzle, Program.from_bytes(bytes(coin_solution.solution))],
|
||||
]
|
||||
|
||||
|
||||
def puzzle_suitable_for_compression(puzzle: Program):
|
||||
def puzzle_suitable_for_compression(puzzle: SerializedProgram) -> bool:
|
||||
return True if match_standard_transaction_exactly_and_return_pubkey(puzzle) else False
|
||||
|
||||
|
||||
@ -88,7 +92,7 @@ def bundle_suitable_for_compression(bundle: SpendBundle):
|
||||
|
||||
|
||||
def compressed_coin_solution_entry_list(bundle: SpendBundle) -> List:
|
||||
compressed_cse_list = []
|
||||
compressed_cse_list: List[List[Union[List[uint64], List[Union[bytes, None, Program]]]]] = []
|
||||
for coin_solution in bundle.coin_solutions:
|
||||
compressed_cse_list.append(compress_coin_solution(coin_solution))
|
||||
return compressed_cse_list
|
||||
|
@ -57,7 +57,7 @@ def create_compressed_generator(
|
||||
return BlockGenerator(program, [generator_arg])
|
||||
|
||||
|
||||
def setup_generator_args(self: BlockGenerator):
|
||||
def setup_generator_args(self: BlockGenerator) -> Tuple[SerializedProgram, Program]:
|
||||
args = create_generator_args(self.generator_refs())
|
||||
return self.program, args
|
||||
|
||||
|
@ -2,7 +2,7 @@ from dataclasses import dataclass
|
||||
from typing import List
|
||||
|
||||
from chia.types.blockchain_format.coin import Coin
|
||||
from chia.types.blockchain_format.program import Program, INFINITE_COST
|
||||
from chia.types.blockchain_format.program import SerializedProgram, INFINITE_COST
|
||||
from chia.util.chain_utils import additions_for_solution
|
||||
from chia.util.streamable import Streamable, streamable
|
||||
|
||||
@ -17,8 +17,8 @@ class CoinSolution(Streamable):
|
||||
"""
|
||||
|
||||
coin: Coin
|
||||
puzzle_reveal: Program
|
||||
solution: Program
|
||||
puzzle_reveal: SerializedProgram
|
||||
solution: SerializedProgram
|
||||
|
||||
def additions(self) -> List[Coin]:
|
||||
return additions_for_solution(self.coin.name(), self.puzzle_reveal, self.solution, INFINITE_COST)
|
||||
|
@ -1,7 +1,7 @@
|
||||
from typing import List
|
||||
|
||||
from chia.types.blockchain_format.coin import Coin
|
||||
from chia.types.blockchain_format.program import Program
|
||||
from chia.types.blockchain_format.program import SerializedProgram
|
||||
from chia.types.blockchain_format.sized_bytes import bytes32
|
||||
from chia.util.condition_tools import (
|
||||
conditions_dict_for_solution,
|
||||
@ -9,7 +9,9 @@ from chia.util.condition_tools import (
|
||||
)
|
||||
|
||||
|
||||
def additions_for_solution(coin_name: bytes32, puzzle_reveal: Program, solution: Program, max_cost: int) -> List[Coin]:
|
||||
def additions_for_solution(
|
||||
coin_name: bytes32, puzzle_reveal: SerializedProgram, solution: SerializedProgram, max_cost: int
|
||||
) -> List[Coin]:
|
||||
"""
|
||||
Checks the conditions created by CoinSolution and returns the list of all coins created
|
||||
"""
|
||||
|
@ -4,7 +4,7 @@ from blspy import G1Element
|
||||
|
||||
from chia.types.announcement import Announcement
|
||||
from chia.types.blockchain_format.coin import Coin
|
||||
from chia.types.blockchain_format.program import Program
|
||||
from chia.types.blockchain_format.program import Program, SerializedProgram
|
||||
from chia.types.blockchain_format.sized_bytes import bytes32
|
||||
from chia.types.condition_opcodes import ConditionOpcode
|
||||
from chia.types.condition_with_args import ConditionWithArgs
|
||||
@ -176,8 +176,8 @@ def puzzle_announcement_names_for_conditions_dict(
|
||||
|
||||
|
||||
def conditions_dict_for_solution(
|
||||
puzzle_reveal: Program,
|
||||
solution: Program,
|
||||
puzzle_reveal: SerializedProgram,
|
||||
solution: SerializedProgram,
|
||||
max_cost: int,
|
||||
) -> Tuple[Optional[Err], Optional[Dict[ConditionOpcode, List[ConditionWithArgs]]], uint64]:
|
||||
error, result, cost = conditions_for_solution(puzzle_reveal, solution, max_cost)
|
||||
@ -187,8 +187,8 @@ def conditions_dict_for_solution(
|
||||
|
||||
|
||||
def conditions_for_solution(
|
||||
puzzle_reveal: Program,
|
||||
solution: Program,
|
||||
puzzle_reveal: SerializedProgram,
|
||||
solution: SerializedProgram,
|
||||
max_cost: int,
|
||||
) -> Tuple[Optional[Err], Optional[List[ConditionWithArgs]], uint64]:
|
||||
# get the standard script for a puzzle hash and feed in the solution
|
||||
|
@ -224,7 +224,7 @@ def spendable_cc_list_from_coin_solution(coin_solution: CoinSolution, hash_to_pu
|
||||
spendable_cc_list = []
|
||||
|
||||
coin = coin_solution.coin
|
||||
puzzle = coin_solution.puzzle_reveal
|
||||
puzzle = Program.from_bytes(bytes(coin_solution.puzzle_reveal))
|
||||
r = uncurry_cc(puzzle)
|
||||
if r:
|
||||
mod_hash, genesis_coin_checker, inner_puzzle = r
|
||||
|
@ -72,7 +72,7 @@ def debug_spend_bundle(spend_bundle: SpendBundle) -> None:
|
||||
pks.append(pk)
|
||||
msgs.append(m)
|
||||
print()
|
||||
r = puzzle_reveal.run(solution)
|
||||
r = puzzle_reveal.run_with_cost(INFINITE_COST, solution)
|
||||
print(disassemble(r))
|
||||
print()
|
||||
if conditions and len(conditions) > 0:
|
||||
|
@ -549,7 +549,7 @@ class RLWallet:
|
||||
sigs = []
|
||||
for coin_solution in spends:
|
||||
pubkey, secretkey = await self.get_keys(coin_solution.coin.puzzle_hash)
|
||||
signature = AugSchemeMPL.sign(secretkey, Program.to(coin_solution.solution).get_tree_hash())
|
||||
signature = AugSchemeMPL.sign(secretkey, coin_solution.solution.get_tree_hash())
|
||||
sigs.append(signature)
|
||||
|
||||
aggsig = AugSchemeMPL.aggregate(sigs)
|
||||
|
@ -11,6 +11,7 @@ from chia.types.blockchain_format.coin import Coin
|
||||
from chia.types.blockchain_format.program import Program
|
||||
from chia.types.blockchain_format.sized_bytes import bytes32
|
||||
from chia.types.spend_bundle import SpendBundle
|
||||
from chia.types.coin_solution import CoinSolution
|
||||
from chia.util.byte_types import hexstr_to_bytes
|
||||
from chia.util.db_wrapper import DBWrapper
|
||||
from chia.util.hash import std_hash
|
||||
@ -361,16 +362,16 @@ class TradeManager:
|
||||
if trade_offer is not None:
|
||||
offer_spend_bundle: SpendBundle = trade_offer.spend_bundle
|
||||
|
||||
coinsols = [] # [] of CoinSolutions
|
||||
cc_coinsol_outamounts: Dict[bytes32, List[Tuple[Any, int]]] = dict()
|
||||
coinsols: List[CoinSolution] = [] # [] of CoinSolutions
|
||||
cc_coinsol_outamounts: Dict[bytes32, List[Tuple[CoinSolution, int]]] = dict()
|
||||
aggsig = offer_spend_bundle.aggregated_signature
|
||||
cc_discrepancies: Dict[bytes32, int] = dict()
|
||||
chia_discrepancy = None
|
||||
wallets: Dict[bytes32, Any] = dict() # colour to wallet dict
|
||||
|
||||
for coinsol in offer_spend_bundle.coin_solutions:
|
||||
puzzle: Program = coinsol.puzzle_reveal
|
||||
solution: Program = coinsol.solution
|
||||
puzzle: Program = Program.from_bytes(bytes(coinsol.puzzle_reveal))
|
||||
solution: Program = Program.from_bytes(bytes(coinsol.solution))
|
||||
|
||||
# work out the deficits between coin amount and expected output for each
|
||||
r = cc_utils.uncurry_cc(puzzle)
|
||||
@ -473,8 +474,8 @@ class TradeManager:
|
||||
# Create SpendableCC for each of the coloured coins received
|
||||
for cc_coinsol_out in cc_coinsol_outamounts[colour]:
|
||||
cc_coinsol = cc_coinsol_out[0]
|
||||
puzzle = cc_coinsol.puzzle_reveal
|
||||
solution = cc_coinsol.solution
|
||||
puzzle = Program.from_bytes(bytes(cc_coinsol.puzzle_reveal))
|
||||
solution = Program.from_bytes(bytes(cc_coinsol.solution))
|
||||
|
||||
r = uncurry_cc(puzzle)
|
||||
if r:
|
||||
|
@ -64,8 +64,8 @@ def get_discrepancies_for_spend_bundle(
|
||||
try:
|
||||
cc_discrepancies: Dict[str, int] = dict()
|
||||
for coinsol in trade_offer.coin_solutions:
|
||||
puzzle = coinsol.puzzle_reveal
|
||||
solution = coinsol.solution
|
||||
puzzle: Program = Program.from_bytes(bytes(coinsol.puzzle_reveal))
|
||||
solution: Program = Program.from_bytes(bytes(coinsol.solution))
|
||||
# work out the deficits between coin amount and expected output for each
|
||||
r = cc_utils.uncurry_cc(puzzle)
|
||||
if r:
|
||||
|
@ -1,6 +1,6 @@
|
||||
# flake8: noqa: F501
|
||||
from dataclasses import dataclass
|
||||
from typing import List
|
||||
from typing import List, Any
|
||||
from unittest import TestCase
|
||||
|
||||
from chia.full_node.bundle_tools import (
|
||||
@ -9,6 +9,7 @@ from chia.full_node.bundle_tools import (
|
||||
compressed_spend_bundle_solution,
|
||||
match_standard_transaction_at_any_index,
|
||||
simple_solution_generator,
|
||||
spend_bundle_to_serialized_coin_solution_entry_list,
|
||||
)
|
||||
from chia.full_node.generator import run_generator, create_generator_args
|
||||
from chia.types.blockchain_format.program import Program, SerializedProgram, INFINITE_COST
|
||||
@ -21,6 +22,10 @@ from chia.wallet.puzzles.load_clvm import load_clvm
|
||||
|
||||
from tests.core.make_block_generator import make_spend_bundle
|
||||
|
||||
from clvm import SExp
|
||||
import io
|
||||
from clvm.serialize import sexp_from_stream
|
||||
|
||||
from clvm_tools import binutils
|
||||
|
||||
TEST_GEN_DESERIALIZE = load_clvm("test_generator_deserialize.clvm", package_or_requirement="chia.wallet.puzzles")
|
||||
@ -77,6 +82,19 @@ def create_multiple_ref_generator(args: MultipleCompressorArg, spend_bundle: Spe
|
||||
return BlockGenerator(program, generator_args)
|
||||
|
||||
|
||||
def spend_bundle_to_coin_solution_entry_list(bundle: SpendBundle) -> List[Any]:
|
||||
r = []
|
||||
for coin_solution in bundle.coin_solutions:
|
||||
entry = [
|
||||
coin_solution.coin.parent_coin_info,
|
||||
sexp_from_stream(io.BytesIO(bytes(coin_solution.puzzle_reveal)), SExp.to),
|
||||
coin_solution.coin.amount,
|
||||
sexp_from_stream(io.BytesIO(bytes(coin_solution.solution)), SExp.to),
|
||||
]
|
||||
r.append(entry)
|
||||
return r
|
||||
|
||||
|
||||
class TestCompression(TestCase):
|
||||
def test_spend_bundle_suitable(self):
|
||||
sb: SpendBundle = make_spend_bundle(1)
|
||||
@ -120,6 +138,13 @@ class TestCompression(TestCase):
|
||||
assert result_s is not None
|
||||
assert result_c == result_s
|
||||
|
||||
def test_spend_byndle_coin_solution(self):
|
||||
for i in range(0, 10):
|
||||
sb: SpendBundle = make_spend_bundle(i)
|
||||
cs1 = SExp.to(spend_bundle_to_coin_solution_entry_list(sb)).as_bin()
|
||||
cs2 = spend_bundle_to_serialized_coin_solution_entry_list(sb)
|
||||
assert cs1 == cs2
|
||||
|
||||
|
||||
class TestDecompression(TestCase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
Loading…
Reference in New Issue
Block a user