From 4e81bfe23072ebbbfe36a09e202918d6170b9bbf Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 3 Oct 2023 15:34:44 -0400 Subject: [PATCH] remove test classes from `test/clvm/` and switch to pytest (#16488) --- tests/clvm/test_chialisp_deserialization.py | 116 ++- tests/clvm/test_clvm_step.py | 36 +- tests/clvm/test_program.py | 67 +- tests/clvm/test_puzzle_compression.py | 209 +++-- tests/clvm/test_puzzles.py | 196 +++-- tests/clvm/test_singletons.py | 925 ++++++++++---------- tests/clvm/test_spend_sim.py | 241 +++-- 7 files changed, 906 insertions(+), 884 deletions(-) diff --git a/tests/clvm/test_chialisp_deserialization.py b/tests/clvm/test_chialisp_deserialization.py index 57a2d5c06814..6b2a9d0e0826 100644 --- a/tests/clvm/test_chialisp_deserialization.py +++ b/tests/clvm/test_chialisp_deserialization.py @@ -1,7 +1,5 @@ from __future__ import annotations -from unittest import TestCase - from chia.types.blockchain_format.program import INFINITE_COST, Program from chia.util.byte_types import hexstr_to_bytes from chia.wallet.puzzles.load_clvm import load_clvm @@ -52,65 +50,63 @@ def serialized_atom_overflow(size): return size_blob.hex() + extra_str -class TestClvmNativeDeserialization(TestCase): - """ - Test clvm deserialization done from within the clvm - """ +def test_deserialization_simple_list(): + # ("hello" "friend") + b = hexstr_to_bytes("ff8568656c6c6fff86667269656e6480") + cost, output = DESERIALIZE_MOD.run_with_cost(INFINITE_COST, [b]) + print(cost, output) + prog = Program.to(output) + assert prog == Program.from_bytes(b) - def test_deserialization_simple_list(self): - # ("hello" "friend") - b = hexstr_to_bytes("ff8568656c6c6fff86667269656e6480") - cost, output = DESERIALIZE_MOD.run_with_cost(INFINITE_COST, [b]) - print(cost, output) - prog = Program.to(output) - assert prog == Program.from_bytes(b) - def test_deserialization_password_coin(self): - # (i (= (sha256 2) (q 0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824)) (c (q 51) (c 5 (c (q 100) (q ())))) (q "wrong password")) # noqa - b = hexstr_to_bytes( - "ff04ffff0affff0bff0280ffff01ffa02cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b98248080ffff05ffff01ff3380ffff05ff05ffff05ffff01ff6480ffff01ff8080808080ffff01ff8e77726f6e672070617373776f72648080" # noqa - ) # noqa - cost, output = DESERIALIZE_MOD.run_with_cost(INFINITE_COST, [b]) - print(cost, output) - prog = Program.to(output) - assert prog == Program.from_bytes(b) +def test_deserialization_password_coin(): + # (i (= (sha256 2) (q 0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824)) (c (q 51) (c 5 (c (q 100) (q ())))) (q "wrong password")) # noqa + b = hexstr_to_bytes( + "ff04ffff0affff0bff0280ffff01ffa02cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b98248080ffff05ffff01ff3380ffff05ff05ffff05ffff01ff6480ffff01ff8080808080ffff01ff8e77726f6e672070617373776f72648080" # noqa + ) # noqa + cost, output = DESERIALIZE_MOD.run_with_cost(INFINITE_COST, [b]) + print(cost, output) + prog = Program.to(output) + assert prog == Program.from_bytes(b) - def test_deserialization_large_numbers(self): - # '(99999999999999999999999999999999999999999999999999999999999999999 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -99999999999999999999999999999999999999999999999999999999999999999999999999999)' # noqa - b = hexstr_to_bytes( - "ff9c00f316271c7fc3908a8bef464e3945ef7a253609ffffffffffffffffffb00fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1ff22ea0179500526edb610f148ec0c614155678491902d6000000000000000000180" # noqa - ) # noqa - cost, output = DESERIALIZE_MOD.run_with_cost(INFINITE_COST, [b]) - print(cost, output) - prog = Program.to(output) - assert prog == Program.from_bytes(b) - def test_overflow_atoms(self): - b = hexstr_to_bytes(serialized_atom_overflow(0xFFFFFFFF)) - try: - cost, output = DESERIALIZE_MOD.run_with_cost(INFINITE_COST, [b]) - except Exception: - assert True - else: - assert False - b = hexstr_to_bytes(serialized_atom_overflow(0x3FFFFFFFF)) - try: - cost, output = DESERIALIZE_MOD.run_with_cost(INFINITE_COST, [b]) - except Exception: - assert True - else: - assert False - b = hexstr_to_bytes(serialized_atom_overflow(0xFFFFFFFFFF)) - try: - cost, output = DESERIALIZE_MOD.run_with_cost(INFINITE_COST, [b]) - except Exception: - assert True - else: - assert False - b = hexstr_to_bytes(serialized_atom_overflow(0x1FFFFFFFFFF)) - try: - cost, output = DESERIALIZE_MOD.run_with_cost(INFINITE_COST, [b]) - except Exception: - assert True - else: - assert False +def test_deserialization_large_numbers(): + # '(99999999999999999999999999999999999999999999999999999999999999999 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -99999999999999999999999999999999999999999999999999999999999999999999999999999)' # noqa + b = hexstr_to_bytes( + "ff9c00f316271c7fc3908a8bef464e3945ef7a253609ffffffffffffffffffb00fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1ff22ea0179500526edb610f148ec0c614155678491902d6000000000000000000180" # noqa + ) # noqa + cost, output = DESERIALIZE_MOD.run_with_cost(INFINITE_COST, [b]) + print(cost, output) + prog = Program.to(output) + assert prog == Program.from_bytes(b) + + +def test_overflow_atoms(): + b = hexstr_to_bytes(serialized_atom_overflow(0xFFFFFFFF)) + try: + cost, output = DESERIALIZE_MOD.run_with_cost(INFINITE_COST, [b]) + except Exception: + assert True + else: + assert False + b = hexstr_to_bytes(serialized_atom_overflow(0x3FFFFFFFF)) + try: + cost, output = DESERIALIZE_MOD.run_with_cost(INFINITE_COST, [b]) + except Exception: + assert True + else: + assert False + b = hexstr_to_bytes(serialized_atom_overflow(0xFFFFFFFFFF)) + try: + cost, output = DESERIALIZE_MOD.run_with_cost(INFINITE_COST, [b]) + except Exception: + assert True + else: + assert False + b = hexstr_to_bytes(serialized_atom_overflow(0x1FFFFFFFFFF)) + try: + cost, output = DESERIALIZE_MOD.run_with_cost(INFINITE_COST, [b]) + except Exception: + assert True + else: + assert False diff --git a/tests/clvm/test_clvm_step.py b/tests/clvm/test_clvm_step.py index 9948b601d1e9..d63f4848ed3b 100644 --- a/tests/clvm/test_clvm_step.py +++ b/tests/clvm/test_clvm_step.py @@ -1,7 +1,6 @@ from __future__ import annotations from typing import Any, Optional -from unittest import TestCase from clvm_tools_rs import start_clvm_program @@ -15,25 +14,24 @@ factorial_sym = {factorial_function_hash: "factorial"} -class TestRunProgram(TestCase): - def test_simple_program_run(self) -> None: - p = start_clvm_program(factorial, "ff0580", factorial_sym) +def test_simple_program_run() -> None: + p = start_clvm_program(factorial, "ff0580", factorial_sym) - last: Optional[Any] = None - location: Optional[Any] = None + last: Optional[Any] = None + location: Optional[Any] = None - while not p.is_ended(): - step_result = p.step() - if step_result is not None: - last = step_result - self.assertTrue("Failure" not in last) + while not p.is_ended(): + step_result = p.step() + if step_result is not None: + last = step_result + assert "Failure" not in last - if "Operator-Location" in last: - location = last["Operator-Location"] + if "Operator-Location" in last: + location = last["Operator-Location"] - self.assertTrue(last is not None) - self.assertTrue(location is not None) - if last is not None and location is not None: - self.assertTrue("Final" in last) - self.assertEqual(int(last["Final"]), 120) - self.assertTrue(location.startswith("factorial")) + assert last is not None + assert location is not None + if last is not None and location is not None: + assert "Final" in last + assert int(last["Final"]) == 120 + assert location.startswith("factorial") diff --git a/tests/clvm/test_program.py b/tests/clvm/test_program.py index 38273926e43e..ce392d9dc879 100644 --- a/tests/clvm/test_program.py +++ b/tests/clvm/test_program.py @@ -1,7 +1,6 @@ from __future__ import annotations -from unittest import TestCase - +import pytest from clvm.EvalError import EvalError from clvm.operators import KEYWORD_TO_ATOM from clvm_tools.binutils import assemble, disassemble @@ -9,41 +8,51 @@ from chia.types.blockchain_format.program import Program -class TestProgram(TestCase): - def test_at(self): - p = Program.to([10, 20, 30, [15, 17], 40, 50]) +def test_at(): + p = Program.to([10, 20, 30, [15, 17], 40, 50]) + + assert p.first() == p.at("f") + assert Program.to(10) == p.at("f") + + assert p.rest() == p.at("r") + assert Program.to([20, 30, [15, 17], 40, 50]) == p.at("r") + + assert p.rest().rest().rest().first().rest().first() == p.at("rrrfrf") + assert Program.to(17) == p.at("rrrfrf") + + with pytest.raises(ValueError): + p.at("q") + + with pytest.raises(EvalError): + p.at("ff") - self.assertEqual(p.first(), p.at("f")) - self.assertEqual(Program.to(10), p.at("f")) - self.assertEqual(p.rest(), p.at("r")) - self.assertEqual(Program.to([20, 30, [15, 17], 40, 50]), p.at("r")) +def test_replace(): + p1 = Program.to([100, 200, 300]) + assert p1.replace(f=105) == Program.to([105, 200, 300]) + assert p1.replace(rrf=[301, 302]) == Program.to([100, 200, [301, 302]]) + assert p1.replace(f=105, rrf=[301, 302]) == Program.to([105, 200, [301, 302]]) + assert p1.replace(f=100, r=200) == Program.to((100, 200)) - self.assertEqual(p.rest().rest().rest().first().rest().first(), p.at("rrrfrf")) - self.assertEqual(Program.to(17), p.at("rrrfrf")) - self.assertRaises(ValueError, lambda: p.at("q")) - self.assertRaises(EvalError, lambda: p.at("ff")) +def test_replace_conflicts(): + p1 = Program.to([100, 200, 300]) + with pytest.raises(ValueError): + p1.replace(rr=105, rrf=200) - def test_replace(self): - p1 = Program.to([100, 200, 300]) - self.assertEqual(p1.replace(f=105), Program.to([105, 200, 300])) - self.assertEqual(p1.replace(rrf=[301, 302]), Program.to([100, 200, [301, 302]])) - self.assertEqual(p1.replace(f=105, rrf=[301, 302]), Program.to([105, 200, [301, 302]])) - self.assertEqual(p1.replace(f=100, r=200), Program.to((100, 200))) - def test_replace_conflicts(self): - p1 = Program.to([100, 200, 300]) - self.assertRaises(ValueError, lambda: p1.replace(rr=105, rrf=200)) +def test_replace_conflicting_paths(): + p1 = Program.to([100, 200, 300]) + with pytest.raises(ValueError): + p1.replace(ff=105) - def test_replace_conflicting_paths(self): - p1 = Program.to([100, 200, 300]) - self.assertRaises(ValueError, lambda: p1.replace(ff=105)) - def test_replace_bad_path(self): - p1 = Program.to([100, 200, 300]) - self.assertRaises(ValueError, lambda: p1.replace(q=105)) - self.assertRaises(ValueError, lambda: p1.replace(rq=105)) +def test_replace_bad_path(): + p1 = Program.to([100, 200, 300]) + with pytest.raises(ValueError): + p1.replace(q=105) + with pytest.raises(ValueError): + p1.replace(rq=105) def check_idempotency(f, *args): diff --git a/tests/clvm/test_puzzle_compression.py b/tests/clvm/test_puzzle_compression.py index 64302af98edc..cc7ba609f42f 100644 --- a/tests/clvm/test_puzzle_compression.py +++ b/tests/clvm/test_puzzle_compression.py @@ -1,7 +1,10 @@ from __future__ import annotations -from typing import Dict +import logging +from dataclasses import dataclass +from typing import Callable, SupportsBytes +import pytest from blspy import G1Element, G2Element from chia.types.blockchain_format.coin import Coin @@ -27,95 +30,115 @@ SOLUTION = Program.to([]) -class TestPuzzleCompression: - compression_factors: Dict[str, float] = {} - - def test_standard_puzzle(self): - coin_spend = CoinSpend( - COIN, - puzzle_for_pk(G1Element()), - SOLUTION, - ) - compressed = compress_object_with_puzzles(bytes(coin_spend), LATEST_VERSION) - assert len(bytes(coin_spend)) > len(compressed) - assert coin_spend == CoinSpend.from_bytes(decompress_object_with_puzzles(compressed)) - self.compression_factors["standard_puzzle"] = len(bytes(compressed)) / len(bytes(coin_spend)) - - def test_decompress_limit(self): - buffer = bytearray(10 * 1024 * 1024) - compressed = compress_object_with_puzzles(buffer, LATEST_VERSION) - print(len(compressed)) - decompressed = decompress_object_with_puzzles(compressed) - print(len(decompressed)) - assert len(decompressed) <= 6 * 1024 * 1024 - - def test_cat_puzzle(self): - coin_spend = CoinSpend( - COIN, - construct_cat_puzzle(CAT_MOD, Program.to([]).get_tree_hash(), Program.to(1)), - SOLUTION, - ) - compressed = compress_object_with_puzzles(bytes(coin_spend), LATEST_VERSION) - assert len(bytes(coin_spend)) > len(compressed) - assert coin_spend == CoinSpend.from_bytes(decompress_object_with_puzzles(compressed)) - self.compression_factors["cat_puzzle"] = len(bytes(compressed)) / len(bytes(coin_spend)) - - def test_offer_puzzle(self): - coin_spend = CoinSpend( - COIN, - OFFER_MOD, - SOLUTION, - ) - compressed = compress_object_with_puzzles(bytes(coin_spend), LATEST_VERSION) - assert len(bytes(coin_spend)) > len(compressed) - assert coin_spend == CoinSpend.from_bytes(decompress_object_with_puzzles(compressed)) - self.compression_factors["offer_puzzle"] = len(bytes(compressed)) / len(bytes(coin_spend)) - - def test_nesting_puzzles(self): - coin_spend = CoinSpend( - COIN, - construct_cat_puzzle(CAT_MOD, Program.to([]).get_tree_hash(), puzzle_for_pk(G1Element())), - SOLUTION, - ) - compressed = compress_object_with_puzzles(bytes(coin_spend), LATEST_VERSION) - assert len(bytes(coin_spend)) > len(compressed) - assert coin_spend == CoinSpend.from_bytes(decompress_object_with_puzzles(compressed)) - self.compression_factors["cat_w_standard_puzzle"] = len(bytes(compressed)) / len(bytes(coin_spend)) - - def test_unknown_wrapper(self): - unknown = Program.to([2, 2, []]) # (a 2 ()) - coin_spend = CoinSpend( - COIN, - unknown.curry(puzzle_for_pk(G1Element())), - SOLUTION, - ) - compressed = compress_object_with_puzzles(bytes(coin_spend), LATEST_VERSION) - assert len(bytes(coin_spend)) > len(compressed) - assert coin_spend == CoinSpend.from_bytes(decompress_object_with_puzzles(compressed)) - self.compression_factors["unknown_and_standard"] = len(bytes(compressed)) / len(bytes(coin_spend)) - - def test_lowest_best_version(self): - assert lowest_best_version([bytes(CAT_MOD)]) == 4 - assert lowest_best_version([bytes(OFFER_MOD_OLD)]) == 2 - assert lowest_best_version([bytes(OFFER_MOD)]) == 5 - - def test_version_override(self): - coin_spend = CoinSpend( - COIN, - OFFER_MOD, - SOLUTION, - ) - spend_bundle = SpendBundle([coin_spend], G2Element()) - compressed = compress_object_with_puzzles(bytes(spend_bundle), LATEST_VERSION) - compressed_earlier = compress_object_with_puzzles(bytes(spend_bundle), 1) - assert len(bytes(spend_bundle)) > len(bytes(compressed)) - assert spend_bundle == SpendBundle.from_bytes(decompress_object_with_puzzles(compressed)) - assert spend_bundle == SpendBundle.from_bytes(decompress_object_with_puzzles(compressed_earlier)) - assert len(bytes(compressed_earlier)) > len(bytes(compressed)) - - def test_compression_factors(self): - import json - import logging - - log = logging.getLogger(__name__) - log.warning(json.dumps(self.compression_factors)) +log = logging.getLogger(__name__) + + +@dataclass +class CompressionReporter: + record_property: Callable + + def __call__(self, name: str, original: SupportsBytes, compressed: SupportsBytes): + ratio = len(bytes(compressed)) / len(bytes(original)) + self.record_property(name="compression_ratio", value=ratio) + log.warning(f"{name} compression ratio: {ratio}") + + +@pytest.fixture(name="report_compression") +def report_compression_fixture(record_property): + return CompressionReporter(record_property=record_property) + + +def test_standard_puzzle(report_compression): + coin_spend = CoinSpend( + COIN, + puzzle_for_pk(G1Element()), + SOLUTION, + ) + compressed = compress_object_with_puzzles(bytes(coin_spend), LATEST_VERSION) + assert len(bytes(coin_spend)) > len(compressed) + assert coin_spend == CoinSpend.from_bytes(decompress_object_with_puzzles(compressed)) + + report_compression(name="standard puzzle", original=coin_spend, compressed=compressed) + + +def test_decompress_limit(): + buffer = bytearray(10 * 1024 * 1024) + compressed = compress_object_with_puzzles(buffer, LATEST_VERSION) + print(len(compressed)) + decompressed = decompress_object_with_puzzles(compressed) + print(len(decompressed)) + assert len(decompressed) <= 6 * 1024 * 1024 + + +def test_cat_puzzle(report_compression): + coin_spend = CoinSpend( + COIN, + construct_cat_puzzle(CAT_MOD, Program.to([]).get_tree_hash(), Program.to(1)), + SOLUTION, + ) + compressed = compress_object_with_puzzles(bytes(coin_spend), LATEST_VERSION) + assert len(bytes(coin_spend)) > len(compressed) + assert coin_spend == CoinSpend.from_bytes(decompress_object_with_puzzles(compressed)) + + report_compression(name="CAT puzzle", original=coin_spend, compressed=compressed) + + +def test_offer_puzzle(report_compression): + coin_spend = CoinSpend( + COIN, + OFFER_MOD, + SOLUTION, + ) + compressed = compress_object_with_puzzles(bytes(coin_spend), LATEST_VERSION) + assert len(bytes(coin_spend)) > len(compressed) + assert coin_spend == CoinSpend.from_bytes(decompress_object_with_puzzles(compressed)) + + report_compression(name="offer puzzle", original=coin_spend, compressed=compressed) + + +def test_nesting_puzzles(report_compression): + coin_spend = CoinSpend( + COIN, + construct_cat_puzzle(CAT_MOD, Program.to([]).get_tree_hash(), puzzle_for_pk(G1Element())), + SOLUTION, + ) + compressed = compress_object_with_puzzles(bytes(coin_spend), LATEST_VERSION) + assert len(bytes(coin_spend)) > len(compressed) + assert coin_spend == CoinSpend.from_bytes(decompress_object_with_puzzles(compressed)) + + report_compression(name="nesting puzzle", original=coin_spend, compressed=compressed) + + +def test_unknown_wrapper(report_compression): + unknown = Program.to([2, 2, []]) # (a 2 ()) + coin_spend = CoinSpend( + COIN, + unknown.curry(puzzle_for_pk(G1Element())), + SOLUTION, + ) + compressed = compress_object_with_puzzles(bytes(coin_spend), LATEST_VERSION) + assert len(bytes(coin_spend)) > len(compressed) + assert coin_spend == CoinSpend.from_bytes(decompress_object_with_puzzles(compressed)) + + report_compression(name="unknown wrapper", original=coin_spend, compressed=compressed) + + +def test_lowest_best_version(): + assert lowest_best_version([bytes(CAT_MOD)]) == 4 + assert lowest_best_version([bytes(OFFER_MOD_OLD)]) == 2 + assert lowest_best_version([bytes(OFFER_MOD)]) == 5 + + +def test_version_override(): + coin_spend = CoinSpend( + COIN, + OFFER_MOD, + SOLUTION, + ) + spend_bundle = SpendBundle([coin_spend], G2Element()) + compressed = compress_object_with_puzzles(bytes(spend_bundle), LATEST_VERSION) + compressed_earlier = compress_object_with_puzzles(bytes(spend_bundle), 1) + assert len(bytes(spend_bundle)) > len(bytes(compressed)) + assert spend_bundle == SpendBundle.from_bytes(decompress_object_with_puzzles(compressed)) + assert spend_bundle == SpendBundle.from_bytes(decompress_object_with_puzzles(compressed_earlier)) + assert len(bytes(compressed_earlier)) > len(bytes(compressed)) diff --git a/tests/clvm/test_puzzles.py b/tests/clvm/test_puzzles.py index 0d69e8ae6e35..d89010b46701 100644 --- a/tests/clvm/test_puzzles.py +++ b/tests/clvm/test_puzzles.py @@ -1,7 +1,6 @@ from __future__ import annotations from typing import Iterable, List, Tuple -from unittest import TestCase from blspy import AugSchemeMPL, G1Element, G2Element @@ -107,137 +106,142 @@ def default_payments_and_conditions( return payments, conditions -class TestPuzzles(TestCase): - def test_p2_conditions(self): - key_lookup = KeyTool() - payments, conditions = default_payments_and_conditions(1, key_lookup) +def test_p2_conditions(): + key_lookup = KeyTool() + payments, conditions = default_payments_and_conditions(1, key_lookup) - puzzle = p2_conditions.puzzle_for_conditions(conditions) - solution = p2_conditions.solution_for_conditions(conditions) + puzzle = p2_conditions.puzzle_for_conditions(conditions) + solution = p2_conditions.solution_for_conditions(conditions) - do_test_spend(puzzle, solution, payments, key_lookup) + do_test_spend(puzzle, solution, payments, key_lookup) - def test_p2_delegated_conditions(self): - key_lookup = KeyTool() - payments, conditions = default_payments_and_conditions(1, key_lookup) - pk = public_key_for_index(1, key_lookup) +def test_p2_delegated_conditions(): + key_lookup = KeyTool() + payments, conditions = default_payments_and_conditions(1, key_lookup) - puzzle = p2_delegated_conditions.puzzle_for_pk(pk) - solution = p2_delegated_conditions.solution_for_conditions(conditions) + pk = public_key_for_index(1, key_lookup) - do_test_spend(puzzle, solution, payments, key_lookup) + puzzle = p2_delegated_conditions.puzzle_for_pk(pk) + solution = p2_delegated_conditions.solution_for_conditions(conditions) - def test_p2_delegated_puzzle_simple(self): - key_lookup = KeyTool() - payments, conditions = default_payments_and_conditions(1, key_lookup) + do_test_spend(puzzle, solution, payments, key_lookup) - pk = public_key_for_index(1, key_lookup) - puzzle = p2_delegated_puzzle.puzzle_for_pk(pk) - solution = p2_delegated_puzzle.solution_for_conditions(conditions) +def test_p2_delegated_puzzle_simple(): + key_lookup = KeyTool() + payments, conditions = default_payments_and_conditions(1, key_lookup) - do_test_spend(puzzle, solution, payments, key_lookup) + pk = public_key_for_index(1, key_lookup) - def test_p2_delegated_puzzle_graftroot(self): - key_lookup = KeyTool() - payments, conditions = default_payments_and_conditions(1, key_lookup) + puzzle = p2_delegated_puzzle.puzzle_for_pk(pk) + solution = p2_delegated_puzzle.solution_for_conditions(conditions) - delegated_puzzle = p2_delegated_conditions.puzzle_for_pk(public_key_for_index(8, key_lookup)) - delegated_solution = p2_delegated_conditions.solution_for_conditions(conditions) + do_test_spend(puzzle, solution, payments, key_lookup) - puzzle_program = p2_delegated_puzzle.puzzle_for_pk(public_key_for_index(1, key_lookup)) - solution = p2_delegated_puzzle.solution_for_delegated_puzzle(delegated_puzzle, delegated_solution) - do_test_spend(puzzle_program, solution, payments, key_lookup) +def test_p2_delegated_puzzle_graftroot(): + key_lookup = KeyTool() + payments, conditions = default_payments_and_conditions(1, key_lookup) - def test_p2_puzzle_hash(self): - key_lookup = KeyTool() - payments, conditions = default_payments_and_conditions(1, key_lookup) + delegated_puzzle = p2_delegated_conditions.puzzle_for_pk(public_key_for_index(8, key_lookup)) + delegated_solution = p2_delegated_conditions.solution_for_conditions(conditions) - inner_puzzle = p2_delegated_conditions.puzzle_for_pk(public_key_for_index(4, key_lookup)) - inner_solution = p2_delegated_conditions.solution_for_conditions(conditions) - inner_puzzle_hash = inner_puzzle.get_tree_hash() + puzzle_program = p2_delegated_puzzle.puzzle_for_pk(public_key_for_index(1, key_lookup)) + solution = p2_delegated_puzzle.solution_for_delegated_puzzle(delegated_puzzle, delegated_solution) - puzzle_program = p2_puzzle_hash.puzzle_for_inner_puzzle_hash(inner_puzzle_hash) - assert puzzle_program == p2_puzzle_hash.puzzle_for_inner_puzzle(inner_puzzle) - solution = p2_puzzle_hash.solution_for_inner_puzzle_and_inner_solution(inner_puzzle, inner_solution) + do_test_spend(puzzle_program, solution, payments, key_lookup) - do_test_spend(puzzle_program, solution, payments, key_lookup) - def test_p2_m_of_n_delegated_puzzle(self): - key_lookup = KeyTool() - payments, conditions = default_payments_and_conditions(1, key_lookup) +def test_p2_puzzle_hash(): + key_lookup = KeyTool() + payments, conditions = default_payments_and_conditions(1, key_lookup) - pks = [public_key_for_index(_, key_lookup) for _ in range(1, 6)] - M = 3 + inner_puzzle = p2_delegated_conditions.puzzle_for_pk(public_key_for_index(4, key_lookup)) + inner_solution = p2_delegated_conditions.solution_for_conditions(conditions) + inner_puzzle_hash = inner_puzzle.get_tree_hash() - delegated_puzzle = p2_conditions.puzzle_for_conditions(conditions) - delegated_solution = [] + puzzle_program = p2_puzzle_hash.puzzle_for_inner_puzzle_hash(inner_puzzle_hash) + assert puzzle_program == p2_puzzle_hash.puzzle_for_inner_puzzle(inner_puzzle) + solution = p2_puzzle_hash.solution_for_inner_puzzle_and_inner_solution(inner_puzzle, inner_solution) - puzzle_program = p2_m_of_n_delegate_direct.puzzle_for_m_of_public_key_list(M, pks) - selectors = [1, [], [], 1, 1] - solution = p2_m_of_n_delegate_direct.solution_for_delegated_puzzle( - M, selectors, delegated_puzzle, delegated_solution - ) + do_test_spend(puzzle_program, solution, payments, key_lookup) - do_test_spend(puzzle_program, solution, payments, key_lookup) - def test_p2_delegated_puzzle_or_hidden_puzzle_with_hidden_puzzle(self): - key_lookup = KeyTool() - payments, conditions = default_payments_and_conditions(1, key_lookup) +def test_p2_m_of_n_delegated_puzzle(): + key_lookup = KeyTool() + payments, conditions = default_payments_and_conditions(1, key_lookup) - hidden_puzzle = p2_conditions.puzzle_for_conditions(conditions) - hidden_public_key = public_key_for_index(10, key_lookup) + pks = [public_key_for_index(_, key_lookup) for _ in range(1, 6)] + M = 3 - puzzle = p2_delegated_puzzle_or_hidden_puzzle.puzzle_for_public_key_and_hidden_puzzle( - G1Element.from_bytes_unchecked(hidden_public_key), hidden_puzzle - ) - solution = p2_delegated_puzzle_or_hidden_puzzle.solution_for_hidden_puzzle( - G1Element.from_bytes_unchecked(hidden_public_key), hidden_puzzle, Program.to(0) - ) + delegated_puzzle = p2_conditions.puzzle_for_conditions(conditions) + delegated_solution = [] - do_test_spend(puzzle, solution, payments, key_lookup) + puzzle_program = p2_m_of_n_delegate_direct.puzzle_for_m_of_public_key_list(M, pks) + selectors = [1, [], [], 1, 1] + solution = p2_m_of_n_delegate_direct.solution_for_delegated_puzzle( + M, selectors, delegated_puzzle, delegated_solution + ) - def do_test_spend_p2_delegated_puzzle_or_hidden_puzzle_with_delegated_puzzle(self, hidden_pub_key_index): - key_lookup = KeyTool() - payments, conditions = default_payments_and_conditions(1, key_lookup) + do_test_spend(puzzle_program, solution, payments, key_lookup) - hidden_puzzle = p2_conditions.puzzle_for_conditions(conditions) - hidden_public_key = public_key_for_index(hidden_pub_key_index, key_lookup) - hidden_pub_key_point = G1Element.from_bytes(hidden_public_key) - puzzle = p2_delegated_puzzle_or_hidden_puzzle.puzzle_for_public_key_and_hidden_puzzle( - hidden_pub_key_point, hidden_puzzle - ) - payable_payments, payable_conditions = default_payments_and_conditions(5, key_lookup) +def test_p2_delegated_puzzle_or_hidden_puzzle_with_hidden_puzzle(): + key_lookup = KeyTool() + payments, conditions = default_payments_and_conditions(1, key_lookup) - delegated_puzzle = p2_conditions.puzzle_for_conditions(payable_conditions) - delegated_solution = [] + hidden_puzzle = p2_conditions.puzzle_for_conditions(conditions) + hidden_public_key = public_key_for_index(10, key_lookup) - synthetic_public_key = p2_delegated_puzzle_or_hidden_puzzle.calculate_synthetic_public_key( - G1Element.from_bytes(hidden_public_key), hidden_puzzle.get_tree_hash() - ) + puzzle = p2_delegated_puzzle_or_hidden_puzzle.puzzle_for_public_key_and_hidden_puzzle( + G1Element.from_bytes_unchecked(hidden_public_key), hidden_puzzle + ) + solution = p2_delegated_puzzle_or_hidden_puzzle.solution_for_hidden_puzzle( + G1Element.from_bytes_unchecked(hidden_public_key), hidden_puzzle, Program.to(0) + ) - solution = p2_delegated_puzzle_or_hidden_puzzle.solution_for_delegated_puzzle( - delegated_puzzle, delegated_solution - ) + do_test_spend(puzzle, solution, payments, key_lookup) - hidden_puzzle_hash = hidden_puzzle.get_tree_hash() - synthetic_offset = p2_delegated_puzzle_or_hidden_puzzle.calculate_synthetic_offset( - hidden_pub_key_point, hidden_puzzle_hash - ) - assert synthetic_public_key == int_to_public_key(synthetic_offset) + hidden_pub_key_point +def do_test_spend_p2_delegated_puzzle_or_hidden_puzzle_with_delegated_puzzle(hidden_pub_key_index): + key_lookup = KeyTool() + payments, conditions = default_payments_and_conditions(1, key_lookup) - secret_exponent = key_lookup.get(hidden_public_key) - assert int_to_public_key(secret_exponent) == hidden_pub_key_point + hidden_puzzle = p2_conditions.puzzle_for_conditions(conditions) + hidden_public_key = public_key_for_index(hidden_pub_key_index, key_lookup) + hidden_pub_key_point = G1Element.from_bytes(hidden_public_key) - synthetic_secret_exponent = secret_exponent + synthetic_offset - key_lookup.add_secret_exponents([synthetic_secret_exponent]) + puzzle = p2_delegated_puzzle_or_hidden_puzzle.puzzle_for_public_key_and_hidden_puzzle( + hidden_pub_key_point, hidden_puzzle + ) + payable_payments, payable_conditions = default_payments_and_conditions(5, key_lookup) - do_test_spend(puzzle, solution, payable_payments, key_lookup) + delegated_puzzle = p2_conditions.puzzle_for_conditions(payable_conditions) + delegated_solution = [] - def test_p2_delegated_puzzle_or_hidden_puzzle_with_delegated_puzzle(self): - for hidden_pub_key_index in range(1, 10): - self.do_test_spend_p2_delegated_puzzle_or_hidden_puzzle_with_delegated_puzzle(hidden_pub_key_index) + synthetic_public_key = p2_delegated_puzzle_or_hidden_puzzle.calculate_synthetic_public_key( + G1Element.from_bytes(hidden_public_key), hidden_puzzle.get_tree_hash() + ) + + solution = p2_delegated_puzzle_or_hidden_puzzle.solution_for_delegated_puzzle(delegated_puzzle, delegated_solution) + + hidden_puzzle_hash = hidden_puzzle.get_tree_hash() + synthetic_offset = p2_delegated_puzzle_or_hidden_puzzle.calculate_synthetic_offset( + hidden_pub_key_point, hidden_puzzle_hash + ) + + assert synthetic_public_key == int_to_public_key(synthetic_offset) + hidden_pub_key_point + + secret_exponent = key_lookup.get(hidden_public_key) + assert int_to_public_key(secret_exponent) == hidden_pub_key_point + + synthetic_secret_exponent = secret_exponent + synthetic_offset + key_lookup.add_secret_exponents([synthetic_secret_exponent]) + + do_test_spend(puzzle, solution, payable_payments, key_lookup) + + +def test_p2_delegated_puzzle_or_hidden_puzzle_with_delegated_puzzle(): + for hidden_pub_key_index in range(1, 10): + do_test_spend_p2_delegated_puzzle_or_hidden_puzzle_with_delegated_puzzle(hidden_pub_key_index) diff --git a/tests/clvm/test_singletons.py b/tests/clvm/test_singletons.py index 24526096dba7..950e3a477bfe 100644 --- a/tests/clvm/test_singletons.py +++ b/tests/clvm/test_singletons.py @@ -35,509 +35,506 @@ class TransactionPushError(Exception): pass -class TestSingleton: - # Helper function - def sign_delegated_puz(self, del_puz: Program, coin: Coin) -> G2Element: - synthetic_secret_key: PrivateKey = p2_delegated_puzzle_or_hidden_puzzle.calculate_synthetic_secret_key( # noqa - PrivateKey.from_bytes( - secret_exponent_for_index(1).to_bytes(32, "big"), - ), - p2_delegated_puzzle_or_hidden_puzzle.DEFAULT_HIDDEN_PUZZLE_HASH, - ) - return AugSchemeMPL.sign( - synthetic_secret_key, - (del_puz.get_tree_hash() + coin.name() + DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA), # noqa - ) - - # Helper function - async def make_and_spend_bundle( - self, - sim: SpendSim, - sim_client: SimClient, - coin: Coin, - delegated_puzzle: Program, - coinsols: List[CoinSpend], - ex_error: Optional[Err] = None, - fail_msg: str = "", - cost_logger: Optional[CostLogger] = None, - cost_log_msg: str = "", - ): - signature: G2Element = self.sign_delegated_puz(delegated_puzzle, coin) - spend_bundle = SpendBundle( - coinsols, - signature, - ) - if cost_logger is not None: - spend_bundle = cost_logger.add_cost(cost_log_msg, spend_bundle) - +def sign_delegated_puz(del_puz: Program, coin: Coin) -> G2Element: + synthetic_secret_key: PrivateKey = p2_delegated_puzzle_or_hidden_puzzle.calculate_synthetic_secret_key( # noqa + PrivateKey.from_bytes( + secret_exponent_for_index(1).to_bytes(32, "big"), + ), + p2_delegated_puzzle_or_hidden_puzzle.DEFAULT_HIDDEN_PUZZLE_HASH, + ) + return AugSchemeMPL.sign( + synthetic_secret_key, + (del_puz.get_tree_hash() + coin.name() + DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA), # noqa + ) + + +# Helper function +async def make_and_spend_bundle( + sim: SpendSim, + sim_client: SimClient, + coin: Coin, + delegated_puzzle: Program, + coinsols: List[CoinSpend], + ex_error: Optional[Err] = None, + fail_msg: str = "", + cost_logger: Optional[CostLogger] = None, + cost_log_msg: str = "", +): + signature: G2Element = sign_delegated_puz(delegated_puzzle, coin) + spend_bundle = SpendBundle( + coinsols, + signature, + ) + if cost_logger is not None: + spend_bundle = cost_logger.add_cost(cost_log_msg, spend_bundle) + + try: + result, error = await sim_client.push_tx(spend_bundle) + if error is None: + await sim.farm_block() + elif ex_error is not None: + assert error == ex_error + else: + raise TransactionPushError(error) + except AssertionError: + raise AssertionError(fail_msg) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("version", [0, 1]) +async def test_singleton_top_layer(version, cost_logger): + async with sim_and_client() as (sim, sim_client): + # START TESTS + # Generate starting info + key_lookup = KeyTool() + pk: G1Element = G1Element.from_bytes(public_key_for_index(1, key_lookup)) + starting_puzzle: Program = p2_delegated_puzzle_or_hidden_puzzle.puzzle_for_pk(pk) # noqa + + if version == 0: + from chia.wallet.puzzles import singleton_top_layer + + adapted_puzzle: Program = singleton_top_layer.adapt_inner_to_singleton(starting_puzzle) # noqa + else: + from chia.wallet.puzzles import singleton_top_layer_v1_1 as singleton_top_layer + + adapted_puzzle = starting_puzzle + adapted_puzzle_hash: bytes32 = adapted_puzzle.get_tree_hash() + + # Get our starting standard coin created + START_AMOUNT: uint64 = 1023 + await sim.farm_block(starting_puzzle.get_tree_hash()) + starting_coin: Coin = await sim_client.get_coin_records_by_puzzle_hash(starting_puzzle.get_tree_hash()) + starting_coin = starting_coin[0].coin + comment: List[Tuple[str, str]] = [("hello", "world")] + + # LAUNCHING + # Try to create an even singleton (driver test) try: - result, error = await sim_client.push_tx(spend_bundle) - if error is None: - await sim.farm_block() - elif ex_error is not None: - assert error == ex_error - else: - raise TransactionPushError(error) - except AssertionError: - raise AssertionError(fail_msg) - - @pytest.mark.asyncio - @pytest.mark.parametrize("version", [0, 1]) - async def test_singleton_top_layer(self, version, cost_logger): - async with sim_and_client() as (sim, sim_client): - # START TESTS - # Generate starting info - key_lookup = KeyTool() - pk: G1Element = G1Element.from_bytes(public_key_for_index(1, key_lookup)) - starting_puzzle: Program = p2_delegated_puzzle_or_hidden_puzzle.puzzle_for_pk(pk) # noqa - - if version == 0: - from chia.wallet.puzzles import singleton_top_layer - - adapted_puzzle: Program = singleton_top_layer.adapt_inner_to_singleton(starting_puzzle) # noqa - else: - from chia.wallet.puzzles import singleton_top_layer_v1_1 as singleton_top_layer - - adapted_puzzle = starting_puzzle - adapted_puzzle_hash: bytes32 = adapted_puzzle.get_tree_hash() - - # Get our starting standard coin created - START_AMOUNT: uint64 = 1023 - await sim.farm_block(starting_puzzle.get_tree_hash()) - starting_coin: Coin = await sim_client.get_coin_records_by_puzzle_hash(starting_puzzle.get_tree_hash()) - starting_coin = starting_coin[0].coin - comment: List[Tuple[str, str]] = [("hello", "world")] - - # LAUNCHING - # Try to create an even singleton (driver test) - try: - conditions, launcher_coinsol = singleton_top_layer.launch_conditions_and_coinsol( # noqa - starting_coin, adapted_puzzle, comment, (START_AMOUNT - 1) - ) - raise AssertionError("This should fail due to an even amount") - except ValueError as msg: - assert str(msg) == "Coin amount cannot be even. Subtract one mojo." - conditions, launcher_coinsol = singleton_top_layer.launch_conditions_and_coinsol( # noqa - starting_coin, adapted_puzzle, comment, START_AMOUNT - ) - - # Creating solution for standard transaction - delegated_puzzle: Program = p2_conditions.puzzle_for_conditions(conditions) # noqa - full_solution: Program = p2_delegated_puzzle_or_hidden_puzzle.solution_for_conditions(conditions) # noqa - - starting_coinsol = CoinSpend( - starting_coin, - starting_puzzle, - full_solution, + conditions, launcher_coinsol = singleton_top_layer.launch_conditions_and_coinsol( # noqa + starting_coin, adapted_puzzle, comment, (START_AMOUNT - 1) ) - - await self.make_and_spend_bundle( - sim, - sim_client, - starting_coin, - delegated_puzzle, - [starting_coinsol, launcher_coinsol], - cost_logger=cost_logger, - cost_log_msg="Singleton Launch + Standard TX", + raise AssertionError("This should fail due to an even amount") + except ValueError as msg: + assert str(msg) == "Coin amount cannot be even. Subtract one mojo." + conditions, launcher_coinsol = singleton_top_layer.launch_conditions_and_coinsol( # noqa + starting_coin, adapted_puzzle, comment, START_AMOUNT ) - # EVE - singleton_eve: Coin = (await sim.all_non_reward_coins())[0] - launcher_coin: Coin = singleton_top_layer.generate_launcher_coin( - starting_coin, - START_AMOUNT, - ) - launcher_id: bytes32 = launcher_coin.name() - # This delegated puzzle just recreates the coin exactly - delegated_puzzle: Program = Program.to( - ( - 1, + # Creating solution for standard transaction + delegated_puzzle: Program = p2_conditions.puzzle_for_conditions(conditions) # noqa + full_solution: Program = p2_delegated_puzzle_or_hidden_puzzle.solution_for_conditions(conditions) # noqa + + starting_coinsol = CoinSpend( + starting_coin, + starting_puzzle, + full_solution, + ) + + await make_and_spend_bundle( + sim, + sim_client, + starting_coin, + delegated_puzzle, + [starting_coinsol, launcher_coinsol], + cost_logger=cost_logger, + cost_log_msg="Singleton Launch + Standard TX", + ) + + # EVE + singleton_eve: Coin = (await sim.all_non_reward_coins())[0] + launcher_coin: Coin = singleton_top_layer.generate_launcher_coin( + starting_coin, + START_AMOUNT, + ) + launcher_id: bytes32 = launcher_coin.name() + # This delegated puzzle just recreates the coin exactly + delegated_puzzle: Program = Program.to( + ( + 1, + [ [ - [ - ConditionOpcode.CREATE_COIN, - adapted_puzzle_hash, - singleton_eve.amount, - ] - ], - ) - ) - inner_solution: Program = Program.to([[], delegated_puzzle, []]) - # Generate the lineage proof we will need from the launcher coin - lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(launcher_coinsol) # noqa - puzzle_reveal: Program = singleton_top_layer.puzzle_for_singleton( - launcher_id, - adapted_puzzle, - ) - full_solution: Program = singleton_top_layer.solution_for_singleton( - lineage_proof, - singleton_eve.amount, - inner_solution, + ConditionOpcode.CREATE_COIN, + adapted_puzzle_hash, + singleton_eve.amount, + ] + ], ) + ) + inner_solution: Program = Program.to([[], delegated_puzzle, []]) + # Generate the lineage proof we will need from the launcher coin + lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(launcher_coinsol) # noqa + puzzle_reveal: Program = singleton_top_layer.puzzle_for_singleton( + launcher_id, + adapted_puzzle, + ) + full_solution: Program = singleton_top_layer.solution_for_singleton( + lineage_proof, + singleton_eve.amount, + inner_solution, + ) - singleton_eve_coinsol = CoinSpend( - singleton_eve, - puzzle_reveal, - full_solution, - ) + singleton_eve_coinsol = CoinSpend( + singleton_eve, + puzzle_reveal, + full_solution, + ) - await self.make_and_spend_bundle( - sim, - sim_client, - singleton_eve, - delegated_puzzle, - [singleton_eve_coinsol], - cost_logger=cost_logger, - cost_log_msg="Singleton Eve Spend w/ Standard TX", - ) + await make_and_spend_bundle( + sim, + sim_client, + singleton_eve, + delegated_puzzle, + [singleton_eve_coinsol], + cost_logger=cost_logger, + cost_log_msg="Singleton Eve Spend w/ Standard TX", + ) - # POST-EVE - singleton: Coin = (await sim.all_non_reward_coins())[0] - # Same delegated_puzzle / inner_solution. We're just recreating ourself - lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(singleton_eve_coinsol) # noqa - # Same puzzle_reveal too - full_solution: Program = singleton_top_layer.solution_for_singleton( - lineage_proof, - singleton.amount, - inner_solution, - ) + # POST-EVE + singleton: Coin = (await sim.all_non_reward_coins())[0] + # Same delegated_puzzle / inner_solution. We're just recreating ourself + lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(singleton_eve_coinsol) # noqa + # Same puzzle_reveal too + full_solution: Program = singleton_top_layer.solution_for_singleton( + lineage_proof, + singleton.amount, + inner_solution, + ) - singleton_coinsol = CoinSpend( - singleton, - puzzle_reveal, - full_solution, - ) + singleton_coinsol = CoinSpend( + singleton, + puzzle_reveal, + full_solution, + ) - await self.make_and_spend_bundle( - sim, - sim_client, - singleton, - delegated_puzzle, - [singleton_coinsol], - cost_logger=cost_logger, - cost_log_msg="Singleton Spend + Standard TX", - ) + await make_and_spend_bundle( + sim, + sim_client, + singleton, + delegated_puzzle, + [singleton_coinsol], + cost_logger=cost_logger, + cost_log_msg="Singleton Spend + Standard TX", + ) - # CLAIM A P2_SINGLETON - singleton_child: Coin = (await sim.all_non_reward_coins())[0] - p2_singleton_puz: Program = singleton_top_layer.pay_to_singleton_puzzle(launcher_id) - p2_singleton_ph: bytes32 = p2_singleton_puz.get_tree_hash() - await sim.farm_block(p2_singleton_ph) - p2_singleton_coin: Coin = await sim_client.get_coin_records_by_puzzle_hash(p2_singleton_ph) - p2_singleton_coin = p2_singleton_coin[0].coin - assertion, announcement, claim_coinsol = singleton_top_layer.claim_p2_singleton( - p2_singleton_coin, - adapted_puzzle_hash, - launcher_id, - ) - delegated_puzzle: Program = Program.to( - ( - 1, - [ - [ConditionOpcode.CREATE_COIN, adapted_puzzle_hash, singleton_eve.amount], - assertion, - announcement, - ], - ) - ) - inner_solution: Program = Program.to([[], delegated_puzzle, []]) - lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(singleton_coinsol) - puzzle_reveal: Program = singleton_top_layer.puzzle_for_singleton( - launcher_id, - adapted_puzzle, - ) - full_solution: Program = singleton_top_layer.solution_for_singleton( - lineage_proof, - singleton_eve.amount, - inner_solution, - ) - singleton_claim_coinsol = CoinSpend( - singleton_child, - puzzle_reveal, - full_solution, + # CLAIM A P2_SINGLETON + singleton_child: Coin = (await sim.all_non_reward_coins())[0] + p2_singleton_puz: Program = singleton_top_layer.pay_to_singleton_puzzle(launcher_id) + p2_singleton_ph: bytes32 = p2_singleton_puz.get_tree_hash() + await sim.farm_block(p2_singleton_ph) + p2_singleton_coin: Coin = await sim_client.get_coin_records_by_puzzle_hash(p2_singleton_ph) + p2_singleton_coin = p2_singleton_coin[0].coin + assertion, announcement, claim_coinsol = singleton_top_layer.claim_p2_singleton( + p2_singleton_coin, + adapted_puzzle_hash, + launcher_id, + ) + delegated_puzzle: Program = Program.to( + ( + 1, + [ + [ConditionOpcode.CREATE_COIN, adapted_puzzle_hash, singleton_eve.amount], + assertion, + announcement, + ], ) + ) + inner_solution: Program = Program.to([[], delegated_puzzle, []]) + lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(singleton_coinsol) + puzzle_reveal: Program = singleton_top_layer.puzzle_for_singleton( + launcher_id, + adapted_puzzle, + ) + full_solution: Program = singleton_top_layer.solution_for_singleton( + lineage_proof, + singleton_eve.amount, + inner_solution, + ) + singleton_claim_coinsol = CoinSpend( + singleton_child, + puzzle_reveal, + full_solution, + ) - await self.make_and_spend_bundle( - sim, - sim_client, - singleton_child, - delegated_puzzle, - [singleton_claim_coinsol, claim_coinsol], - cost_logger=cost_logger, - cost_log_msg="Singleton w/ Standard TX claim p2_singleton", - ) + await make_and_spend_bundle( + sim, + sim_client, + singleton_child, + delegated_puzzle, + [singleton_claim_coinsol, claim_coinsol], + cost_logger=cost_logger, + cost_log_msg="Singleton w/ Standard TX claim p2_singleton", + ) - # CLAIM A P2_SINGLETON_OR_DELAYED - singleton_child: Coin = (await sim.all_non_reward_coins())[0] - DELAY_TIME: uint64 = 1 - DELAY_PH: bytes32 = adapted_puzzle_hash - p2_singleton_puz: Program = singleton_top_layer.pay_to_singleton_or_delay_puzzle( - launcher_id, - DELAY_TIME, - DELAY_PH, - ) - p2_singleton_ph: bytes32 = p2_singleton_puz.get_tree_hash() - ARBITRARY_AMOUNT: uint64 = 250000000000 - await sim.farm_block(p2_singleton_ph) - p2_singleton_coin: Coin = await sim_client.get_coin_records_by_puzzle_hash(p2_singleton_ph) - p2_singleton_coin = sorted(p2_singleton_coin, key=lambda x: x.coin.amount)[0].coin - assertion, announcement, claim_coinsol = singleton_top_layer.claim_p2_singleton( - p2_singleton_coin, - adapted_puzzle_hash, - launcher_id, - DELAY_TIME, - DELAY_PH, - ) - delegated_puzzle: Program = Program.to( - ( - 1, - [ - [ConditionOpcode.CREATE_COIN, adapted_puzzle_hash, singleton_eve.amount], - assertion, - announcement, - ], - ) - ) - inner_solution: Program = Program.to([[], delegated_puzzle, []]) - lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(singleton_claim_coinsol) - puzzle_reveal: Program = singleton_top_layer.puzzle_for_singleton( - launcher_id, - adapted_puzzle, - ) - full_solution: Program = singleton_top_layer.solution_for_singleton( - lineage_proof, - singleton_eve.amount, - inner_solution, - ) - delay_claim_coinsol = CoinSpend( - singleton_child, - puzzle_reveal, - full_solution, + # CLAIM A P2_SINGLETON_OR_DELAYED + singleton_child: Coin = (await sim.all_non_reward_coins())[0] + DELAY_TIME: uint64 = 1 + DELAY_PH: bytes32 = adapted_puzzle_hash + p2_singleton_puz: Program = singleton_top_layer.pay_to_singleton_or_delay_puzzle( + launcher_id, + DELAY_TIME, + DELAY_PH, + ) + p2_singleton_ph: bytes32 = p2_singleton_puz.get_tree_hash() + ARBITRARY_AMOUNT: uint64 = 250000000000 + await sim.farm_block(p2_singleton_ph) + p2_singleton_coin: Coin = await sim_client.get_coin_records_by_puzzle_hash(p2_singleton_ph) + p2_singleton_coin = sorted(p2_singleton_coin, key=lambda x: x.coin.amount)[0].coin + assertion, announcement, claim_coinsol = singleton_top_layer.claim_p2_singleton( + p2_singleton_coin, + adapted_puzzle_hash, + launcher_id, + DELAY_TIME, + DELAY_PH, + ) + delegated_puzzle: Program = Program.to( + ( + 1, + [ + [ConditionOpcode.CREATE_COIN, adapted_puzzle_hash, singleton_eve.amount], + assertion, + announcement, + ], ) + ) + inner_solution: Program = Program.to([[], delegated_puzzle, []]) + lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(singleton_claim_coinsol) + puzzle_reveal: Program = singleton_top_layer.puzzle_for_singleton( + launcher_id, + adapted_puzzle, + ) + full_solution: Program = singleton_top_layer.solution_for_singleton( + lineage_proof, + singleton_eve.amount, + inner_solution, + ) + delay_claim_coinsol = CoinSpend( + singleton_child, + puzzle_reveal, + full_solution, + ) - # Save the height so we can rewind after this - save_height: uint64 = ( - sim.get_height() - ) # The last coin solution before this point is singleton_claim_coinsol - await self.make_and_spend_bundle( - sim, - sim_client, - singleton_child, - delegated_puzzle, - [delay_claim_coinsol, claim_coinsol], - cost_logger=cost_logger, - cost_log_msg="Singleton w/ Standard TX claim p2_singleton_or_delayed", - ) + # Save the height so we can rewind after this + save_height: uint64 = sim.get_height() # The last coin solution before this point is singleton_claim_coinsol + await make_and_spend_bundle( + sim, + sim_client, + singleton_child, + delegated_puzzle, + [delay_claim_coinsol, claim_coinsol], + cost_logger=cost_logger, + cost_log_msg="Singleton w/ Standard TX claim p2_singleton_or_delayed", + ) - # TRY TO SPEND AWAY TOO SOON (Negative Test) - await sim.rewind(save_height) - to_delay_ph_coinsol: CoinSpend = singleton_top_layer.spend_to_delayed_puzzle( - p2_singleton_coin, - ARBITRARY_AMOUNT, - launcher_id, - DELAY_TIME, - DELAY_PH, - ) - result, error = await sim_client.push_tx(SpendBundle([to_delay_ph_coinsol], G2Element())) - assert error == Err.ASSERT_SECONDS_RELATIVE_FAILED - - # SPEND TO DELAYED PUZZLE HASH - await sim.rewind(save_height) - sim.pass_time(10000005) - sim.pass_blocks(100) - await sim_client.push_tx(SpendBundle([to_delay_ph_coinsol], G2Element())) - - # CREATE MULTIPLE ODD CHILDREN (Negative Test) - singleton_child: Coin = (await sim.all_non_reward_coins())[0] - delegated_puzzle: Program = Program.to( - ( - 1, - [ - [ConditionOpcode.CREATE_COIN, adapted_puzzle_hash, 3], - [ConditionOpcode.CREATE_COIN, adapted_puzzle_hash, 7], - ], - ) - ) - inner_solution: Program = Program.to([[], delegated_puzzle, []]) - lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(singleton_claim_coinsol) - puzzle_reveal: Program = singleton_top_layer.puzzle_for_singleton( - launcher_id, - adapted_puzzle, - ) - full_solution: Program = singleton_top_layer.solution_for_singleton( - lineage_proof, singleton_child.amount, inner_solution + # TRY TO SPEND AWAY TOO SOON (Negative Test) + await sim.rewind(save_height) + to_delay_ph_coinsol: CoinSpend = singleton_top_layer.spend_to_delayed_puzzle( + p2_singleton_coin, + ARBITRARY_AMOUNT, + launcher_id, + DELAY_TIME, + DELAY_PH, + ) + result, error = await sim_client.push_tx(SpendBundle([to_delay_ph_coinsol], G2Element())) + assert error == Err.ASSERT_SECONDS_RELATIVE_FAILED + + # SPEND TO DELAYED PUZZLE HASH + await sim.rewind(save_height) + sim.pass_time(10000005) + sim.pass_blocks(100) + await sim_client.push_tx(SpendBundle([to_delay_ph_coinsol], G2Element())) + + # CREATE MULTIPLE ODD CHILDREN (Negative Test) + singleton_child: Coin = (await sim.all_non_reward_coins())[0] + delegated_puzzle: Program = Program.to( + ( + 1, + [ + [ConditionOpcode.CREATE_COIN, adapted_puzzle_hash, 3], + [ConditionOpcode.CREATE_COIN, adapted_puzzle_hash, 7], + ], ) + ) + inner_solution: Program = Program.to([[], delegated_puzzle, []]) + lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(singleton_claim_coinsol) + puzzle_reveal: Program = singleton_top_layer.puzzle_for_singleton( + launcher_id, + adapted_puzzle, + ) + full_solution: Program = singleton_top_layer.solution_for_singleton( + lineage_proof, singleton_child.amount, inner_solution + ) - multi_odd_coinsol = CoinSpend( - singleton_child, - puzzle_reveal, - full_solution, - ) + multi_odd_coinsol = CoinSpend( + singleton_child, + puzzle_reveal, + full_solution, + ) - await self.make_and_spend_bundle( - sim, - sim_client, - singleton_child, - delegated_puzzle, - [multi_odd_coinsol], - ex_error=Err.GENERATOR_RUNTIME_ERROR, - fail_msg="Too many odd children were allowed", - ) + await make_and_spend_bundle( + sim, + sim_client, + singleton_child, + delegated_puzzle, + [multi_odd_coinsol], + ex_error=Err.GENERATOR_RUNTIME_ERROR, + fail_msg="Too many odd children were allowed", + ) - # CREATE NO ODD CHILDREN (Negative Test) - delegated_puzzle: Program = Program.to( - ( - 1, - [ - [ConditionOpcode.CREATE_COIN, adapted_puzzle_hash, 4], - [ConditionOpcode.CREATE_COIN, adapted_puzzle_hash, 10], - ], - ) - ) - inner_solution: Program = Program.to([[], delegated_puzzle, []]) - lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(singleton_claim_coinsol) - puzzle_reveal: Program = singleton_top_layer.puzzle_for_singleton( - launcher_id, - adapted_puzzle, - ) - full_solution: Program = singleton_top_layer.solution_for_singleton( - lineage_proof, singleton_child.amount, inner_solution + # CREATE NO ODD CHILDREN (Negative Test) + delegated_puzzle: Program = Program.to( + ( + 1, + [ + [ConditionOpcode.CREATE_COIN, adapted_puzzle_hash, 4], + [ConditionOpcode.CREATE_COIN, adapted_puzzle_hash, 10], + ], ) + ) + inner_solution: Program = Program.to([[], delegated_puzzle, []]) + lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(singleton_claim_coinsol) + puzzle_reveal: Program = singleton_top_layer.puzzle_for_singleton( + launcher_id, + adapted_puzzle, + ) + full_solution: Program = singleton_top_layer.solution_for_singleton( + lineage_proof, singleton_child.amount, inner_solution + ) - no_odd_coinsol = CoinSpend( - singleton_child, - puzzle_reveal, - full_solution, - ) + no_odd_coinsol = CoinSpend( + singleton_child, + puzzle_reveal, + full_solution, + ) - await self.make_and_spend_bundle( - sim, - sim_client, - singleton_child, - delegated_puzzle, - [no_odd_coinsol], - ex_error=Err.GENERATOR_RUNTIME_ERROR, - fail_msg="Need at least one odd child", - ) + await make_and_spend_bundle( + sim, + sim_client, + singleton_child, + delegated_puzzle, + [no_odd_coinsol], + ex_error=Err.GENERATOR_RUNTIME_ERROR, + fail_msg="Need at least one odd child", + ) - # ATTEMPT TO CREATE AN EVEN SINGLETON (Negative test) - await sim.rewind(save_height) + # ATTEMPT TO CREATE AN EVEN SINGLETON (Negative test) + await sim.rewind(save_height) - delegated_puzzle: Program = Program.to( - ( - 1, + delegated_puzzle: Program = Program.to( + ( + 1, + [ [ - [ - ConditionOpcode.CREATE_COIN, - singleton_child.puzzle_hash, - 2, - ], - [ConditionOpcode.CREATE_COIN, adapted_puzzle_hash, 1], + ConditionOpcode.CREATE_COIN, + singleton_child.puzzle_hash, + 2, ], - ) - ) - inner_solution: Program = Program.to([[], delegated_puzzle, []]) - lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(singleton_claim_coinsol) - puzzle_reveal: Program = singleton_top_layer.puzzle_for_singleton( - launcher_id, - adapted_puzzle, - ) - full_solution: Program = singleton_top_layer.solution_for_singleton( - lineage_proof, singleton_child.amount, inner_solution + [ConditionOpcode.CREATE_COIN, adapted_puzzle_hash, 1], + ], ) + ) + inner_solution: Program = Program.to([[], delegated_puzzle, []]) + lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(singleton_claim_coinsol) + puzzle_reveal: Program = singleton_top_layer.puzzle_for_singleton( + launcher_id, + adapted_puzzle, + ) + full_solution: Program = singleton_top_layer.solution_for_singleton( + lineage_proof, singleton_child.amount, inner_solution + ) - singleton_even_coinsol = CoinSpend( - singleton_child, - puzzle_reveal, - full_solution, - ) + singleton_even_coinsol = CoinSpend( + singleton_child, + puzzle_reveal, + full_solution, + ) - await self.make_and_spend_bundle( - sim, - sim_client, - singleton_child, - delegated_puzzle, - [singleton_even_coinsol], - ) + await make_and_spend_bundle( + sim, + sim_client, + singleton_child, + delegated_puzzle, + [singleton_even_coinsol], + ) - # Now try a perfectly innocent spend - evil_coin: Coin = next(filter(lambda c: c.amount == 2, (await sim.all_non_reward_coins()))) - delegated_puzzle: Program = Program.to( - ( - 1, + # Now try a perfectly innocent spend + evil_coin: Coin = next(filter(lambda c: c.amount == 2, (await sim.all_non_reward_coins()))) + delegated_puzzle: Program = Program.to( + ( + 1, + [ [ - [ - ConditionOpcode.CREATE_COIN, - adapted_puzzle_hash, - 1, - ], + ConditionOpcode.CREATE_COIN, + adapted_puzzle_hash, + 1, ], - ) - ) - inner_solution: Program = Program.to([[], delegated_puzzle, []]) - lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(singleton_even_coinsol) # noqa - puzzle_reveal: Program = singleton_top_layer.puzzle_for_singleton( - launcher_id, - adapted_puzzle, - ) - full_solution: Program = singleton_top_layer.solution_for_singleton( - lineage_proof, - 1, - inner_solution, + ], ) + ) + inner_solution: Program = Program.to([[], delegated_puzzle, []]) + lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(singleton_even_coinsol) # noqa + puzzle_reveal: Program = singleton_top_layer.puzzle_for_singleton( + launcher_id, + adapted_puzzle, + ) + full_solution: Program = singleton_top_layer.solution_for_singleton( + lineage_proof, + 1, + inner_solution, + ) - evil_coinsol = CoinSpend( - evil_coin, - puzzle_reveal, - full_solution, - ) + evil_coinsol = CoinSpend( + evil_coin, + puzzle_reveal, + full_solution, + ) - await self.make_and_spend_bundle( - sim, - sim_client, - evil_coin, - delegated_puzzle, - [evil_coinsol], - ex_error=Err.ASSERT_MY_COIN_ID_FAILED if version == 0 else Err.ASSERT_MY_AMOUNT_FAILED, - fail_msg="This coin is even!", - ) + await make_and_spend_bundle( + sim, + sim_client, + evil_coin, + delegated_puzzle, + [evil_coinsol], + ex_error=Err.ASSERT_MY_COIN_ID_FAILED if version == 0 else Err.ASSERT_MY_AMOUNT_FAILED, + fail_msg="This coin is even!", + ) - # MELTING - # Remember, we're still spending singleton_child - await sim.rewind(save_height) - conditions = [ - singleton_top_layer.MELT_CONDITION, - [ - ConditionOpcode.CREATE_COIN, - adapted_puzzle_hash, - (singleton_child.amount - 1), - ], - ] - delegated_puzzle: Program = p2_conditions.puzzle_for_conditions(conditions) - inner_solution: Program = p2_delegated_puzzle_or_hidden_puzzle.solution_for_conditions(conditions) - lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(singleton_claim_coinsol) - puzzle_reveal: Program = singleton_top_layer.puzzle_for_singleton( - launcher_id, - adapted_puzzle, - ) - full_solution: Program = singleton_top_layer.solution_for_singleton( - lineage_proof, singleton_child.amount, inner_solution - ) + # MELTING + # Remember, we're still spending singleton_child + await sim.rewind(save_height) + conditions = [ + singleton_top_layer.MELT_CONDITION, + [ + ConditionOpcode.CREATE_COIN, + adapted_puzzle_hash, + (singleton_child.amount - 1), + ], + ] + delegated_puzzle: Program = p2_conditions.puzzle_for_conditions(conditions) + inner_solution: Program = p2_delegated_puzzle_or_hidden_puzzle.solution_for_conditions(conditions) + lineage_proof: LineageProof = singleton_top_layer.lineage_proof_for_coinsol(singleton_claim_coinsol) + puzzle_reveal: Program = singleton_top_layer.puzzle_for_singleton( + launcher_id, + adapted_puzzle, + ) + full_solution: Program = singleton_top_layer.solution_for_singleton( + lineage_proof, singleton_child.amount, inner_solution + ) - melt_coinsol = CoinSpend( - singleton_child, - puzzle_reveal, - full_solution, - ) + melt_coinsol = CoinSpend( + singleton_child, + puzzle_reveal, + full_solution, + ) - await self.make_and_spend_bundle( - sim, - sim_client, - singleton_child, - delegated_puzzle, - [melt_coinsol], - cost_logger=cost_logger, - cost_log_msg="Singleton w/ Standard TX melt", - ) + await make_and_spend_bundle( + sim, + sim_client, + singleton_child, + delegated_puzzle, + [melt_coinsol], + cost_logger=cost_logger, + cost_log_msg="Singleton w/ Standard TX melt", + ) - melted_coin: Coin = (await sim.all_non_reward_coins())[0] - assert melted_coin.puzzle_hash == adapted_puzzle_hash + melted_coin: Coin = (await sim.all_non_reward_coins())[0] + assert melted_coin.puzzle_hash == adapted_puzzle_hash diff --git a/tests/clvm/test_spend_sim.py b/tests/clvm/test_spend_sim.py index c20aac3dbdf9..2510c1b04637 100644 --- a/tests/clvm/test_spend_sim.py +++ b/tests/clvm/test_spend_sim.py @@ -10,128 +10,123 @@ from chia.types.spend_bundle import SpendBundle -class TestSpendSim: - @pytest.mark.asyncio - async def test_farming(self): - async with sim_and_client(pass_prefarm=False) as (sim, _): - for i in range(0, 5): - await sim.farm_block() - - assert len(sim.blocks) == 5 - assert sim.blocks[-1].height == 4 - assert sim.block_records[0].reward_claims_incorporated[0].amount == 18375000000000000000 - - @pytest.mark.asyncio - async def test_rewind(self): - async with sim_and_client() as (sim, _): - for i in range(0, 5): - await sim.farm_block() - - save_height = sim.get_height() +@pytest.mark.asyncio +async def test_farming(): + async with sim_and_client(pass_prefarm=False) as (sim, _): + for i in range(0, 5): await sim.farm_block() - await sim.rewind(save_height) - - assert len(sim.blocks) == 6 - assert sim.blocks[-1].height == 5 - - -class TestSimClient: - @pytest.mark.asyncio - async def test_all_endpoints(self): - async with sim_and_client() as (sim, sim_client): - for i in range(0, 5): - await sim.farm_block() - await sim.farm_block(bytes32([0] * 32)) - await sim.farm_block(bytes32([1] * 32)) - for i in range(0, 5): - await sim.farm_block() - - # get_coin_records_by_puzzle_hash - coin_records = await sim_client.get_coin_records_by_puzzle_hash(bytes32([0] * 32)) - coin_record_name = coin_records[0].coin.name() - assert len(coin_records) == 2 - - coin_records = await sim_client.get_coin_records_by_puzzle_hash( - bytes32([0] * 32), start_height=0, end_height=2 - ) - assert len(coin_records) == 0 - - # get_coin_records_by_puzzle_hashes - coin_records = await sim_client.get_coin_records_by_puzzle_hashes([bytes32([0] * 32), bytes32([1] * 32)]) - assert len(coin_records) == 4 - - coin_records = await sim_client.get_coin_records_by_puzzle_hashes( - [bytes32([0] * 32), bytes32([1] * 32)], start_height=0, end_height=2 - ) - assert len(coin_records) == 0 - - # get_coin_record_by_name - assert await sim_client.get_coin_record_by_name(coin_record_name) - - # get_block_records - block_records = await sim_client.get_block_records(0, 5) - assert len(block_records) == 5 - - # get_block_record_by_height - block_record = await sim_client.get_block_record_by_height(0) - assert block_record - assert block_record == block_records[0] - - # get_block_record - same_block_record = await sim_client.get_block_record(block_record.header_hash) - assert same_block_record == block_record - - # get_block - full_block = await sim_client.get_block(block_record.header_hash) - assert full_block.transactions_generator is None - - # get_all_block - full_blocks = await sim_client.get_all_block(0, 5) - assert full_blocks[0] == full_block - - # push_tx - puzzle_hash = bytes.fromhex( - "9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2" - ) # Program.to(1) - await sim.farm_block(puzzle_hash) - spendable_coin = await sim_client.get_coin_records_by_puzzle_hash(puzzle_hash) - spendable_coin = spendable_coin[0].coin - bundle = SpendBundle( - [ - CoinSpend( - spendable_coin, - Program.to(1), - Program.to([[51, puzzle_hash, 1]]), - ) - ], - G2Element(), - ) - result, error = await sim_client.push_tx(bundle) - - # get_all_mempool_tx_ids - mempool_items = await sim_client.get_all_mempool_tx_ids() - assert len(mempool_items) == 1 - - # get_mempool_item_by_tx_id - mempool_item = await sim_client.get_mempool_item_by_tx_id(mempool_items[0]) - assert mempool_item - - # get_all_mempool_items - mempool_items = await sim_client.get_all_mempool_items() - assert len(mempool_items) == 1 - - # get_additions_and_removals + + assert len(sim.blocks) == 5 + assert sim.blocks[-1].height == 4 + assert sim.block_records[0].reward_claims_incorporated[0].amount == 18375000000000000000 + + +@pytest.mark.asyncio +async def test_rewind(): + async with sim_and_client() as (sim, _): + for i in range(0, 5): + await sim.farm_block() + + save_height = sim.get_height() + await sim.farm_block() + await sim.rewind(save_height) + + assert len(sim.blocks) == 6 + assert sim.blocks[-1].height == 5 + + +@pytest.mark.asyncio +async def test_all_endpoints(): + async with sim_and_client() as (sim, sim_client): + for i in range(0, 5): await sim.farm_block() - latest_block = sim.block_records[-1] - additions, removals = await sim_client.get_additions_and_removals(latest_block.header_hash) - assert additions - assert removals - - # get_puzzle_and_solution - coin_spend = await sim_client.get_puzzle_and_solution(spendable_coin.name(), latest_block.height) - assert coin_spend == bundle.coin_spends[0] - - # get_coin_records_by_parent_ids - new_coin = next(x.coin for x in additions if x.coin.puzzle_hash == puzzle_hash) - coin_records = await sim_client.get_coin_records_by_parent_ids([spendable_coin.name()]) - assert coin_records[0].coin.name() == new_coin.name() + await sim.farm_block(bytes32([0] * 32)) + await sim.farm_block(bytes32([1] * 32)) + for i in range(0, 5): + await sim.farm_block() + + # get_coin_records_by_puzzle_hash + coin_records = await sim_client.get_coin_records_by_puzzle_hash(bytes32([0] * 32)) + coin_record_name = coin_records[0].coin.name() + assert len(coin_records) == 2 + + coin_records = await sim_client.get_coin_records_by_puzzle_hash(bytes32([0] * 32), start_height=0, end_height=2) + assert len(coin_records) == 0 + + # get_coin_records_by_puzzle_hashes + coin_records = await sim_client.get_coin_records_by_puzzle_hashes([bytes32([0] * 32), bytes32([1] * 32)]) + assert len(coin_records) == 4 + + coin_records = await sim_client.get_coin_records_by_puzzle_hashes( + [bytes32([0] * 32), bytes32([1] * 32)], start_height=0, end_height=2 + ) + assert len(coin_records) == 0 + + # get_coin_record_by_name + assert await sim_client.get_coin_record_by_name(coin_record_name) + + # get_block_records + block_records = await sim_client.get_block_records(0, 5) + assert len(block_records) == 5 + + # get_block_record_by_height + block_record = await sim_client.get_block_record_by_height(0) + assert block_record + assert block_record == block_records[0] + + # get_block_record + same_block_record = await sim_client.get_block_record(block_record.header_hash) + assert same_block_record == block_record + + # get_block + full_block = await sim_client.get_block(block_record.header_hash) + assert full_block.transactions_generator is None + + # get_all_block + full_blocks = await sim_client.get_all_block(0, 5) + assert full_blocks[0] == full_block + + # push_tx + puzzle_hash = bytes.fromhex("9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2") # Program.to(1) + await sim.farm_block(puzzle_hash) + spendable_coin = await sim_client.get_coin_records_by_puzzle_hash(puzzle_hash) + spendable_coin = spendable_coin[0].coin + bundle = SpendBundle( + [ + CoinSpend( + spendable_coin, + Program.to(1), + Program.to([[51, puzzle_hash, 1]]), + ) + ], + G2Element(), + ) + result, error = await sim_client.push_tx(bundle) + + # get_all_mempool_tx_ids + mempool_items = await sim_client.get_all_mempool_tx_ids() + assert len(mempool_items) == 1 + + # get_mempool_item_by_tx_id + mempool_item = await sim_client.get_mempool_item_by_tx_id(mempool_items[0]) + assert mempool_item + + # get_all_mempool_items + mempool_items = await sim_client.get_all_mempool_items() + assert len(mempool_items) == 1 + + # get_additions_and_removals + await sim.farm_block() + latest_block = sim.block_records[-1] + additions, removals = await sim_client.get_additions_and_removals(latest_block.header_hash) + assert additions + assert removals + + # get_puzzle_and_solution + coin_spend = await sim_client.get_puzzle_and_solution(spendable_coin.name(), latest_block.height) + assert coin_spend == bundle.coin_spends[0] + + # get_coin_records_by_parent_ids + new_coin = next(x.coin for x in additions if x.coin.puzzle_hash == puzzle_hash) + coin_records = await sim_client.get_coin_records_by_parent_ids([spendable_coin.name()]) + assert coin_records[0].coin.name() == new_coin.name()