async def test_standard_tx(self):
        # this isn't a real public key, but we don't care
        public_key = bytes.fromhex(
            "af949b78fa6a957602c3593a3d6cb7711e08720415dad83"
            "1ab18adacaa9b27ec3dda508ee32e24bc811c0abc5781ae21")
        puzzle_program = SerializedProgram.from_bytes(
            p2_delegated_puzzle_or_hidden_puzzle.puzzle_for_pk(public_key))
        conditions = binutils.assemble(
            "((51 0x699eca24f2b6f4b25b16f7a418d0dc4fc5fce3b9145aecdda184158927738e3e 10)"
            " (51 0x847bb2385534070c39a39cc5dfdc7b35e2db472dc0ab10ab4dec157a2178adbf 0x00cbba106df6))"
        )
        solution_program = SerializedProgram.from_bytes(
            p2_delegated_puzzle_or_hidden_puzzle.solution_for_conditions(
                conditions))

        time_start = time.time()
        total_cost = 0
        for i in range(0, 1000):
            cost, result = puzzle_program.run_with_cost(
                test_constants.MAX_BLOCK_COST_CLVM, solution_program)
            total_cost += cost

        time_end = time.time()
        duration = time_end - time_start

        log.info(f"Time spent: {duration}")
        assert duration < 3
예제 #2
0
 async def test_clvm_strict_mode(self, rust_checker: bool):
     block = Program.from_bytes(bytes(SMALL_BLOCK_GENERATOR.program))
     disassembly = binutils.disassemble(block)
     # this is a valid generator program except the first clvm
     # if-condition, that depends on executing an unknown operator
     # ("0xfe"). In strict mode, this should fail, but in non-strict
     # mode, the unknown operator should be treated as if it returns ().
     program = SerializedProgram.from_bytes(
         binutils.assemble(
             f"(i (0xfe (q . 0)) (q . ()) {disassembly})").as_bin())
     generator = BlockGenerator(program, [])
     npc_result: NPCResult = get_name_puzzle_conditions(
         generator,
         test_constants.MAX_BLOCK_COST_CLVM,
         cost_per_byte=test_constants.COST_PER_BYTE,
         safe_mode=True,
         rust_checker=rust_checker,
     )
     assert npc_result.error is not None
     npc_result = get_name_puzzle_conditions(
         generator,
         test_constants.MAX_BLOCK_COST_CLVM,
         cost_per_byte=test_constants.COST_PER_BYTE,
         safe_mode=False,
         rust_checker=rust_checker,
     )
     assert npc_result.error is None
예제 #3
0
def load_serialized_clvm(clvm_filename,
                         package_or_requirement=__name__) -> SerializedProgram:
    """
    This function takes a .clvm file in the given package and compiles it to a
    .clvm.hex file if the .hex file is missing or older than the .clvm file, then
    returns the contents of the .hex file as a `Program`.

    clvm_filename: file name
    package_or_requirement: usually `__name__` if the clvm file is in the same package
    """

    hex_filename = f"{clvm_filename}.hex"

    try:
        if pkg_resources.resource_exists(package_or_requirement,
                                         clvm_filename):
            full_path = pathlib.Path(
                pkg_resources.resource_filename(package_or_requirement,
                                                clvm_filename))
            output = full_path.parent / hex_filename
            compile_clvm(full_path, output, search_paths=[full_path.parent])
    except NotImplementedError:
        # pyinstaller doesn't support `pkg_resources.resource_exists`
        # so we just fall through to loading the hex clvm
        pass

    clvm_hex = pkg_resources.resource_string(package_or_requirement,
                                             hex_filename).decode("utf8")
    clvm_blob = bytes.fromhex(clvm_hex)
    return SerializedProgram.from_bytes(clvm_blob)
    async def test_clvm_max_cost(self):

        block = Program.from_bytes(bytes(SMALL_BLOCK_GENERATOR.program))
        disassembly = binutils.disassemble(block)
        # this is a valid generator program except the first clvm
        # if-condition, that depends on executing an unknown operator
        # ("0xfe"). In strict mode, this should fail, but in non-strict
        # mode, the unknown operator should be treated as if it returns ().
        # the CLVM program has a cost of 391969
        program = SerializedProgram.from_bytes(
            binutils.assemble(
                f"(i (softfork (q . 10000000)) (q . ()) {disassembly})").
            as_bin())

        # ensure we fail if the program exceeds the cost
        generator = BlockGenerator(program, [])
        npc_result: NPCResult = get_name_puzzle_conditions(
            generator, 10000000, False)

        assert npc_result.error is not None
        assert npc_result.clvm_cost == 0

        # raise the max cost to make sure this passes
        # ensure we pass if the program does not exceeds the cost
        npc_result: NPCResult = get_name_puzzle_conditions(
            generator, 20000000, False)

        assert npc_result.error is None
        assert npc_result.clvm_cost > 10000000
    def test_shatrees_match(self):
        """Checks to see that all .sha256tree files match their .hex files"""
        for prog_path in wallet_program_files:
            # load the .hex file as a program
            hex_filename = path_with_ext(prog_path, ".hex")
            clvm_hex = hex_filename.read_text()  # .decode("utf8")
            clvm_blob = bytes.fromhex(clvm_hex)
            s = SerializedProgram.from_bytes(clvm_blob)
            p = Program.from_bytes(clvm_blob)

            # load the checked-in shatree
            existing_sha = path_with_ext(
                prog_path, ".hex.sha256tree").read_text().strip()

            self.assertEqual(
                s.get_tree_hash().hex(),
                existing_sha,
                msg=
                f"Checked-in shatree hash file does not match shatree hash of loaded SerializedProgram: {prog_path}",  # noqa
            )
            self.assertEqual(
                p.get_tree_hash().hex(),
                existing_sha,
                msg=
                f"Checked-in shatree hash file does not match shatree hash of loaded Program: {prog_path}",
            )
예제 #6
0
def make_generator_args(
        generator_ref_list: List[SerializedProgram]) -> SerializedProgram:
    """
    `make_generator_args`: The format and contents of these arguments affect consensus.
    """
    gen_ref_list = [Program.from_bytes(bytes(g)) for g in generator_ref_list]
    return SerializedProgram.from_bytes(
        bytes(Program.to([DESERIALIZE_MOD, gen_ref_list])))
예제 #7
0
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
예제 #8
0
def get_puzzle_and_solution_for_coin(block_program: SerializedProgram, coin_name: bytes):
    try:
        block_program_args = SerializedProgram.from_bytes(b"\x80")
        cost, result = GENERATOR_FOR_SINGLE_COIN_MOD.run_with_cost(block_program, block_program_args, coin_name)
        puzzle = result.first()
        solution = result.rest().first()
        return None, puzzle, solution
    except Exception as e:
        return e, None, None
예제 #9
0
    async def test_strict_mode(self, rust_checker: bool):
        wallet_tool = bt.get_pool_wallet_tool()
        ph = wallet_tool.get_new_puzzlehash()

        num_blocks = 3
        blocks = bt.get_consecutive_blocks(num_blocks, [],
                                           guarantee_transaction_block=True,
                                           pool_reward_puzzle_hash=ph,
                                           farmer_reward_puzzle_hash=ph)

        coinbase = None
        for coin in blocks[2].get_included_reward_coins():
            if coin.puzzle_hash == ph:
                coinbase = coin
                break
        assert coinbase is not None
        spend_bundle = wallet_tool.generate_signed_transaction(
            coinbase.amount,
            BURN_PUZZLE_HASH,
            coinbase,
        )
        assert spend_bundle is not None

        pk = bytes.fromhex(
            "88bc9360319e7c54ab42e19e974288a2d7a817976f7633f4b43f36ce72074e59c4ab8ddac362202f3e366f0aebbb6280"
        )
        puzzle = p2_delegated_puzzle_or_hidden_puzzle.puzzle_for_pk(pk)
        disassembly = binutils.disassemble(puzzle)
        program = SerializedProgram.from_bytes(
            binutils.assemble(
                f"(q ((0x3d2331635a58c0d49912bc1427d7db51afe3f20a7b4bcaffa17ee250dcbcbfaa {disassembly} 300"
                f"  (() (q . ((65 '00000000000000000000000000000000' 0x0cbba106e000))) ()))))"
            ).as_bin())
        generator = BlockGenerator(program, [])
        npc_result: NPCResult = get_name_puzzle_conditions(
            generator,
            test_constants.MAX_BLOCK_COST_CLVM,
            cost_per_byte=test_constants.COST_PER_BYTE,
            safe_mode=True,
            rust_checker=rust_checker,
        )
        assert npc_result.error is not None
        npc_result = get_name_puzzle_conditions(
            generator,
            test_constants.MAX_BLOCK_COST_CLVM,
            cost_per_byte=test_constants.COST_PER_BYTE,
            safe_mode=False,
            rust_checker=rust_checker,
        )
        assert npc_result.error is None

        coin_name = npc_result.npc_list[0].coin_name
        error, puzzle, solution = get_puzzle_and_solution_for_coin(
            generator, coin_name, test_constants.MAX_BLOCK_COST_CLVM)
        assert error is None
예제 #10
0
def simple_solution_generator(bundle: SpendBundle) -> BlockGenerator:
    """
    Simply quotes the solutions we know.
    """
    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), [])
예제 #11
0
    def test_multiple_input_gen_refs(self):
        start1, end1 = match_standard_transaction_at_any_index(gen1)
        start2, end2 = match_standard_transaction_at_any_index(gen2)
        ca1 = CompressorArg(FAKE_BLOCK_HEIGHT1,
                            SerializedProgram.from_bytes(gen1), start1, end1)
        ca2 = CompressorArg(FAKE_BLOCK_HEIGHT2,
                            SerializedProgram.from_bytes(gen2), start2, end2)

        prefix_len1 = end1 - start1
        prefix_len2 = end2 - start2
        assert prefix_len1 == prefix_len2
        prefix_len = prefix_len1
        results = []
        for split_offset in range(prefix_len):
            gen_args = MultipleCompressorArg([ca1, ca2], split_offset)
            spend_bundle: SpendBundle = make_spend_bundle(1)
            multi_gen = create_multiple_ref_generator(gen_args, spend_bundle)
            cost, result = run_generator(multi_gen, INFINITE_COST)
            results.append(result)
            assert result is not None
            assert cost > 0
        assert all(r == results[0] for r in results)
예제 #12
0
    async def test_tx_generator_speed(self):
        LARGE_BLOCK_COIN_CONSUMED_COUNT = 687
        generator = large_block_generator(LARGE_BLOCK_COIN_CONSUMED_COUNT)
        program = SerializedProgram.from_bytes(generator)

        start_time = time.time()
        err, npc, cost = get_name_puzzle_conditions(program, False)
        end_time = time.time()
        duration = end_time - start_time
        assert err is None
        assert len(npc) == LARGE_BLOCK_COIN_CONSUMED_COUNT
        log.info(f"Time spent: {duration}")

        assert duration < 3
예제 #13
0
    def test_block_program_zero_with_curry(self):
        self.maxDiff = None
        cse1 = binutils.assemble(
            "(((0x0000000000000000000000000000000000000000000000000000000000000000 0x0186a0) (0xb081963921826355dcb6c355ccf9c2637c18adf7d38ee44d803ea9ca41587e48c913d8d46896eb830aeadfc13144a8eac3 (() (q (51 0x6b7a83babea1eec790c947db4464ab657dbe9b887fe9acc247062847b8c2a8a9 0x0186a0)) ()))))"
        )  # noqa
        cse2 = binutils.assemble("""
(
  ((0x0000000000000000000000000000000000000000000000000000000000000000 0x0186a0)
   (0xb081963921826355dcb6c355ccf9c2637c18adf7d38ee44d803ea9ca41587e48c913d8d46896eb830aeadfc13144a8eac3
    (() (q (51 0x6b7a83babea1eec790c947db4464ab657dbe9b887fe9acc247062847b8c2a8a9 0x0186a0)) ()))
  )

  ((0x0000000000000000000000000000000000000000000000000000000000000001 0x0186a0)
   (0xb0a6207f5173ec41491d9f2c1b8fff5579e13703077e0eaca8fe587669dcccf51e9209a6b65576845ece5f7c2f3229e7e3
   (() (q (51 0x24254a3efc3ebfac9979bbe0d615e2eda043aa329905f65b63846fa24149e2b6 0x0186a0)) ())))

)
        """)  # noqa

        start = 2 + 44
        end = start + 238

        # (mod (decompress_puzzle decompress_coin_solution_entry start end compressed_cses deserialize generator_list reserved_arg)
        # cost, out = DECOMPRESS_BLOCK.run_with_cost(INFINITE_COST, [DECOMPRESS_PUZZLE, DECOMPRESS_CSE, start, Program.to(end), cse0, DESERIALIZE_MOD, bytes(original_generator)])
        p = DECOMPRESS_BLOCK.curry(DECOMPRESS_PUZZLE,
                                   DECOMPRESS_CSE_WITH_PREFIX, start,
                                   Program.to(end))
        cost, out = p.run_with_cost(
            INFINITE_COST,
            [cse2, DESERIALIZE_MOD, [bytes(original_generator)]])

        print()
        print(p)
        print(out)

        p_with_cses = DECOMPRESS_BLOCK.curry(
            DECOMPRESS_PUZZLE,
            DECOMPRESS_CSE_WITH_PREFIX,
            start,
            Program.to(end),
            cse2,
            DESERIALIZE_MOD,
        )
        generator_args = create_generator_args(
            [SerializedProgram.from_bytes(original_generator)])
        cost, out = p_with_cses.run_with_cost(INFINITE_COST, generator_args)

        print()
        print(p_with_cses)
        print(out)
예제 #14
0
 async def test_clvm_strict_mode(self):
     block = Program.from_bytes(bytes(SMALL_BLOCK_GENERATOR))
     disassembly = binutils.disassemble(block)
     # this is a valid generator program except the first clvm
     # if-condition, that depends on executing an unknown operator
     # ("0xfe"). In strict mode, this should fail, but in non-strict
     # mode, the unknown operator should be treated as if it returns ().
     program = SerializedProgram.from_bytes(
         binutils.assemble(
             f"(i (0xfe (q . 0)) (q . ()) {disassembly})").as_bin())
     error, npc_list, cost = get_name_puzzle_conditions(program, True)
     assert error is not None
     error, npc_list, cost = get_name_puzzle_conditions(program, False)
     assert error is None
예제 #15
0
def get_name_puzzle_conditions(
    block_program: SerializedProgram, safe_mode: bool
) -> Tuple[Optional[str], Optional[List[NPC]], Optional[uint64]]:
    # TODO: allow generator mod to take something (future)
    # TODO: write more tests
    block_program_args = SerializedProgram.from_bytes(b"\x80")

    try:
        if safe_mode:
            cost, result = GENERATOR_MOD.run_safe_with_cost(
                block_program, block_program_args)
        else:
            cost, result = GENERATOR_MOD.run_with_cost(block_program,
                                                       block_program_args)
        npc_list: List[NPC] = []
        opcodes: Set[bytes] = set(item.value for item in ConditionOpcode)

        for res in result.as_iter():
            conditions_list: List[ConditionWithArgs] = []

            spent_coin_parent_id: bytes32 = res.first().first().as_atom()
            spent_coin_puzzle_hash: bytes32 = res.first().rest().first(
            ).as_atom()
            spent_coin_amount: uint64 = uint64(
                res.first().rest().rest().first().as_int())
            spent_coin: Coin = Coin(spent_coin_parent_id,
                                    spent_coin_puzzle_hash, spent_coin_amount)

            for cond in res.rest().first().as_iter():
                if cond.first().as_atom() in opcodes:
                    opcode: ConditionOpcode = ConditionOpcode(
                        cond.first().as_atom())
                elif not safe_mode:
                    opcode = ConditionOpcode.UNKNOWN
                else:
                    return "Unknown operator in safe mode.", None, None
                conditions_list.append(
                    ConditionWithArgs(opcode,
                                      cond.rest().as_atom_list()))
            conditions_dict = conditions_by_opcode(conditions_list)
            if conditions_dict is None:
                conditions_dict = {}
            npc_list.append(
                NPC(spent_coin.name(), spent_coin.puzzle_hash,
                    [(a, b) for a, b in conditions_dict.items()]))
        return None, npc_list, uint64(cost)
    except Exception:
        tb = traceback.format_exc()
        return tb, None, None
def batch_pre_validate_blocks(
    constants_dict: Dict,
    blocks_pickled: Dict[bytes, bytes],
    header_blocks_pickled: List[bytes],
    transaction_generators: List[Optional[bytes]],
    check_filter: bool,
    expected_difficulty: List[uint64],
    expected_sub_slot_iters: List[uint64],
    validate_transactions: bool,
) -> List[bytes]:
    assert len(header_blocks_pickled) == len(transaction_generators)
    blocks = {}
    for k, v in blocks_pickled.items():
        blocks[k] = BlockRecord.from_bytes(v)
    results: List[PreValidationResult] = []
    constants: ConsensusConstants = dataclass_from_dict(
        ConsensusConstants, constants_dict)
    for i in range(len(header_blocks_pickled)):
        try:
            header_block: HeaderBlock = HeaderBlock.from_bytes(
                header_blocks_pickled[i])
            generator: Optional[bytes] = transaction_generators[i]
            required_iters, error = validate_finished_header_block(
                constants,
                BlockCache(blocks),
                header_block,
                check_filter,
                expected_difficulty[i],
                expected_sub_slot_iters[i],
            )
            cost_result: Optional[CostResult] = None
            error_int: Optional[uint16] = None
            if error is not None:
                error_int = uint16(error.code.value)
            if constants_dict["NETWORK_TYPE"] == NetworkType.MAINNET.value:
                cost_result = None
            else:
                if not error and generator is not None and validate_transactions:
                    cost_result = calculate_cost_of_program(
                        SerializedProgram.from_bytes(generator),
                        constants.CLVM_COST_RATIO_CONSTANT)
            results.append(
                PreValidationResult(error_int, required_iters, cost_result))
        except Exception:
            error_stack = traceback.format_exc()
            log.error(f"Exception: {error_stack}")
            results.append(
                PreValidationResult(uint16(Err.UNKNOWN.value), None, None))
    return [bytes(r) for r in results]
예제 #17
0
    async def test_tx_generator_speed(self):
        LARGE_BLOCK_COIN_CONSUMED_COUNT = 687
        generator_bytes = large_block_generator(LARGE_BLOCK_COIN_CONSUMED_COUNT)
        program = SerializedProgram.from_bytes(generator_bytes)

        start_time = time.time()
        generator = BlockGenerator(program, [])
        npc_result = get_name_puzzle_conditions(generator, False)
        end_time = time.time()
        duration = end_time - start_time
        assert npc_result.error is None
        assert len(npc_result.npc_list) == LARGE_BLOCK_COIN_CONSUMED_COUNT
        log.info(f"Time spent: {duration}")

        assert duration < 3
예제 #18
0
def best_solution_program(bundle: SpendBundle) -> SerializedProgram:
    """
    This could potentially do a lot of clever and complicated compression
    optimizations in conjunction with choosing the set of SpendBundles to include.

    For now, we just quote the solutions we know.
    """
    r = []
    for coin_solution in bundle.coin_solutions:
        entry = [
            [coin_solution.coin.parent_coin_info, coin_solution.coin.amount],
            [coin_solution.puzzle_reveal, coin_solution.solution],
        ]
        r.append(entry)
    return SerializedProgram.from_bytes(
        SExp.to((binutils.assemble("#q"), r)).as_bin())
예제 #19
0
 def test_compressed_block_results(self):
     sb: SpendBundle = make_spend_bundle(1)
     start, end = match_standard_transaction_at_any_index(
         original_generator)
     ca = CompressorArg(uint32(0),
                        SerializedProgram.from_bytes(original_generator),
                        start, end)
     c = compressed_spend_bundle_solution(ca, sb)
     s = simple_solution_generator(sb)
     assert c != s
     cost_c, result_c = run_generator(c)
     cost_s, result_s = run_generator(s)
     print(result_c)
     assert result_c is not None
     assert result_s is not None
     assert result_c == result_s
예제 #20
0
def get_generator():

    # args0 is generate_npc_pair_list, args1 is coin_solutions, args2 is output_list
    programs = args(0)
    coin_solutions = args(1)
    output_list = args(2)
    # coin_solution = first(coin_solutions)
    # coin_name = first(coin_solution)
    # puzzle_solution_pair = first(rest(coin_solution))
    # puzzle = first(puzzle_solution_pair)
    # solution = first(rest(puzzle_solution_pair))
    # coin_tuple = args(0, 0, 1)
    coin_parent = args(0, 0, 0, 1)
    coin_amount = args(1, 0, 0, 1)
    coin_puzzle = args(0, 1, 0, 1)
    coin_solution = args(1, 1, 0, 1)

    get_npc = make_list(
        make_list(coin_parent, sha256tree(coin_puzzle), coin_amount),
        eval(coin_puzzle, coin_solution))

    recursive_call = eval(
        programs,
        make_list(programs, rest(coin_solutions), cons(get_npc, output_list)))

    generate_npc_pair_list = make_if(coin_solutions, recursive_call,
                                     output_list)

    # Run the block_program and enter loop over the results
    # args0 is generate_npc_pair_list, args1 is block_program being passed in

    programs = args(0)
    coin_solutions = args(1)
    execute_generate_npc_pair = eval(
        programs, make_list(programs, coin_solutions, sexp()))

    # Bootstrap the execution by passing functions in as parameters before the actual data arguments
    get_coinsols = eval(args(0), args(1))
    core = eval(quote(execute_generate_npc_pair),
                make_list(quote(generate_npc_pair_list), get_coinsols))

    # The below string is exactly the same as the value of 'core' above, except '(r 5)' is replaced with '13'
    # test = "(a (q . (a 2 (c 2 (c 5 (c () ()))))) (c (q . (a (i 5 (q . (a 2 (c 2 (c 13 (c (c (c 17 (c (a (q . (a 2 (c 2 (c 3 0)))) (c (q . (a (i (l 5) (q . (sha256 (q . 2) (a 2 (c 2 (c 9 0))) (a 2 (c 2 (c 13 0))))) (q . (sha256 (q . 1) 5))) 1)) 73)) (c (a 73 169) ()))) 11) ()))))) (q . 11)) 1)) (c (a 2 5) ())))"  # noqa
    ret = SerializedProgram.from_bytes(
        bytes(Program.to(binutils.assemble(core))))

    return ret
def get_name_puzzle_conditions(block_program: SerializedProgram,
                               safe_mode: bool):
    # TODO: allow generator mod to take something (future)
    # TODO: write more tests
    block_program_args = SerializedProgram.from_bytes(b"\x80")

    try:
        if safe_mode:
            cost, result = GENERATOR_MOD.run_safe_with_cost(
                block_program, block_program_args)
        else:
            cost, result = GENERATOR_MOD.run_with_cost(block_program,
                                                       block_program_args)
        npc_list = []
        opcodes = set(item.value for item in ConditionOpcode)
        for res in result.as_iter():
            conditions_list = []
            name = std_hash(
                bytes(res.first().first().as_atom() +
                      res.first().rest().first().as_atom() +
                      res.first().rest().rest().first().as_atom()))
            puzzle_hash = bytes32(res.first().rest().first().as_atom())
            for cond in res.rest().first().as_iter():
                if cond.first().as_atom() in opcodes:
                    opcode = ConditionOpcode(cond.first().as_atom())
                elif not safe_mode:
                    opcode = ConditionOpcode.UNKNOWN
                else:
                    return "Unknown operator in safe mode.", None, None
                if len(list(cond.as_iter())) > 1:
                    cond_var_list = []
                    for cond_1 in cond.rest().as_iter():
                        cond_var_list.append(cond_1.as_atom())
                    cvl = ConditionVarPair(opcode, cond_var_list)
                else:
                    cvl = ConditionVarPair(opcode, [])
                conditions_list.append(cvl)
            conditions_dict = conditions_by_opcode(conditions_list)
            if conditions_dict is None:
                conditions_dict = {}
            npc_list.append(
                NPC(name, puzzle_hash,
                    [(a, b) for a, b in conditions_dict.items()]))
        return None, npc_list, uint64(cost)
    except Exception:
        tb = traceback.format_exc()
        return tb, None, None
예제 #22
0
 def test_get_removals_for_single_coin(self):
     sb: SpendBundle = make_spend_bundle(1)
     start, end = match_standard_transaction_at_any_index(
         original_generator)
     ca = CompressorArg(uint32(0),
                        SerializedProgram.from_bytes(original_generator),
                        start, end)
     c = compressed_spend_bundle_solution(ca, sb)
     removal = sb.coin_spends[0].coin.name()
     error, puzzle, solution = get_puzzle_and_solution_for_coin(
         c, removal, INFINITE_COST)
     assert error is None
     assert bytes(puzzle) == bytes(sb.coin_spends[0].puzzle_reveal)
     assert bytes(solution) == bytes(sb.coin_spends[0].solution)
     # Test non compressed generator as well
     s = simple_solution_generator(sb)
     error, puzzle, solution = get_puzzle_and_solution_for_coin(
         s, removal, INFINITE_COST)
     assert error is None
     assert bytes(puzzle) == bytes(sb.coin_spends[0].puzzle_reveal)
     assert bytes(solution) == bytes(sb.coin_spends[0].solution)
예제 #23
0
    async def test_tx_generator_speed(self, rust_checker: bool):
        LARGE_BLOCK_COIN_CONSUMED_COUNT = 687
        generator_bytes = large_block_generator(
            LARGE_BLOCK_COIN_CONSUMED_COUNT)
        program = SerializedProgram.from_bytes(generator_bytes)

        start_time = time.time()
        generator = BlockGenerator(program, [])
        npc_result = get_name_puzzle_conditions(
            generator,
            test_constants.MAX_BLOCK_COST_CLVM,
            cost_per_byte=test_constants.COST_PER_BYTE,
            safe_mode=False,
            rust_checker=rust_checker,
        )
        end_time = time.time()
        duration = end_time - start_time
        assert npc_result.error is None
        assert len(npc_result.npc_list) == LARGE_BLOCK_COIN_CONSUMED_COUNT
        log.info(f"Time spent: {duration}")

        assert duration < 1
예제 #24
0
    async def create_absorb_transaction(
            self, farmer_record: FarmerRecord, singleton_coin: Coin,
            reward_coin_records: List[CoinRecord]) -> SpendBundle:
        # We assume that the farmer record singleton state is updated to the latest
        escape_inner_puzzle: Program = POOL_ESCAPING_MOD.curry(
            farmer_record.pool_puzzle_hash,
            self.relative_lock_height,
            bytes(farmer_record.owner_public_key),
            farmer_record.p2_singleton_puzzle_hash,
        )
        committed_inner_puzzle: Program = POOL_COMMITED_MOD.curry(
            farmer_record.pool_puzzle_hash,
            escape_inner_puzzle.get_tree_hash(),
            farmer_record.p2_singleton_puzzle_hash,
            bytes(farmer_record.owner_public_key),
        )

        aggregate_spend_bundle: SpendBundle = SpendBundle([], G2Element())
        for reward_coin_record in reward_coin_records:
            found_block_index: Optional[uint32] = None
            for block_index in range(
                    reward_coin_record.confirmed_block_index,
                    reward_coin_record.confirmed_block_index - 100, -1):
                if block_index < 0:
                    break
                pool_parent = pool_parent_id(uint32(block_index),
                                             self.constants.GENESIS_CHALLENGE)
                if pool_parent == reward_coin_record.coin.parent_coin_info:
                    found_block_index = uint32(block_index)
            if not found_block_index:
                self.log.info(
                    f"Received reward {reward_coin_record.coin} that is not a pool reward."
                )

            singleton_full = SINGLETON_MOD.curry(
                singleton_mod_hash, farmer_record.singleton_genesis,
                committed_inner_puzzle)

            inner_sol = Program.to([
                0,
                singleton_full.get_tree_hash(), singleton_coin.amount,
                reward_coin_record.amount, found_block_index
            ])
            full_sol = Program.to([
                farmer_record.singleton_genesis, singleton_coin.amount,
                inner_sol
            ])

            new_spend = SpendBundle(
                [
                    CoinSolution(
                        singleton_coin,
                        SerializedProgram.from_bytes(bytes(singleton_full)),
                        full_sol)
                ],
                G2Element(),
            )
            # TODO(pool): handle the case where the cost exceeds the size of the block
            aggregate_spend_bundle = SpendBundle.aggregate(
                [aggregate_spend_bundle, new_spend])

            singleton_coin = await self.get_next_singleton_coin(new_spend)

            cost, result = singleton_full.run_with_cost(
                INFINITE_COST, full_sol)
            self.log.info(f"Cost: {cost}, result {result}")

        return aggregate_spend_bundle
예제 #25
0
    async def _generate_unsigned_transaction(
        self,
        amount: uint64,
        newpuzzlehash: bytes32,
        fee: uint64 = uint64(0),
        origin_id: bytes32 = None,
        coins: Set[Coin] = None,
        primaries_input: Optional[List[Dict[str, Any]]] = None,
        ignore_max_send_amount: bool = False,
        announcements_to_consume: Set[Announcement] = None,
    ) -> List[CoinSpend]:
        """
        Generates a unsigned transaction in form of List(Puzzle, Solutions)
        Note: this must be called under a wallet state manager lock
        """
        if primaries_input is None:
            primaries: Optional[List[Dict]] = None
            total_amount = amount + fee
        else:
            primaries = primaries_input.copy()
            primaries_amount = 0
            for prim in primaries:
                primaries_amount += prim["amount"]
            total_amount = amount + fee + primaries_amount

        if not ignore_max_send_amount:
            max_send = await self.get_max_send_amount()
            if total_amount > max_send:
                raise ValueError(
                    f"Can't send more than {max_send} in a single transaction")

        if coins is None:
            coins = await self.select_coins(total_amount)
        assert len(coins) > 0

        self.log.info(f"coins is not None {coins}")
        spend_value = sum([coin.amount for coin in coins])
        change = spend_value - total_amount
        assert change >= 0

        spends: List[CoinSpend] = []
        primary_announcement_hash: Optional[bytes32] = None

        # Check for duplicates
        if primaries is not None:
            all_primaries_list = [
                (p["puzzlehash"], p["amount"]) for p in primaries
            ] + [(newpuzzlehash, amount)]
            if len(set(all_primaries_list)) != len(all_primaries_list):
                raise ValueError("Cannot create two identical coins")

        for coin in coins:
            self.log.info(f"coin from coins {coin}")
            puzzle: Program = await self.puzzle_for_puzzle_hash(
                coin.puzzle_hash)

            # Only one coin creates outputs
            if primary_announcement_hash is None and origin_id in (
                    None, coin.name()):
                if primaries is None:
                    primaries = [{
                        "puzzlehash": newpuzzlehash,
                        "amount": amount
                    }]
                else:
                    primaries.append({
                        "puzzlehash": newpuzzlehash,
                        "amount": amount
                    })
                if change > 0:
                    change_puzzle_hash: bytes32 = await self.get_new_puzzlehash(
                    )
                    primaries.append({
                        "puzzlehash": change_puzzle_hash,
                        "amount": change
                    })
                message_list: List[bytes32] = [c.name() for c in coins]
                for primary in primaries:
                    message_list.append(
                        Coin(coin.name(), primary["puzzlehash"],
                             primary["amount"]).name())
                message: bytes32 = std_hash(b"".join(message_list))
                solution: Program = self.make_solution(
                    primaries=primaries,
                    fee=fee,
                    coin_announcements={message},
                    coin_announcements_to_assert=announcements_to_consume,
                )
                primary_announcement_hash = Announcement(coin.name(),
                                                         message).name()
            else:
                solution = self.make_solution(
                    coin_announcements_to_assert={primary_announcement_hash})

            spends.append(
                CoinSpend(coin, SerializedProgram.from_bytes(bytes(puzzle)),
                          SerializedProgram.from_bytes(bytes(solution))))

        self.log.info(f"Spends is {spends}")
        return spends
예제 #26
0
def to_sp(sexp) -> SerializedProgram:
    return SerializedProgram.from_bytes(bytes(sexp))
예제 #27
0
 def test_serialization(self):
     s0 = SerializedProgram.from_bytes(b"\x00")
     p0 = Program.from_bytes(b"\x00")
     print(s0, p0)
예제 #28
0
 def test_program_execution(self):
     p_result = SHA256TREE_MOD.run(SHA256TREE_MOD)
     sp = SerializedProgram.from_bytes(bytes(SHA256TREE_MOD))
     cost, sp_result = sp.run_with_cost(INFINITE_COST, sp)
     self.assertEqual(p_result, sp_result)
예제 #29
0
 def test_tree_hash(self):
     p = SHA256TREE_MOD
     s = SerializedProgram.from_bytes(bytes(SHA256TREE_MOD))
     self.assertEqual(s.get_tree_hash(), p.get_tree_hash())
예제 #30
0
from typing import Dict
from unittest import TestCase

from chia.types.blockchain_format.program import Program, SerializedProgram
from chia.types.generator_types import GeneratorBlockCacheInterface
from chia.full_node.generator import create_block_generator, create_generator_args, list_to_tree
from chia.util.ints import uint32

gen0 = SerializedProgram.from_bytes(
    bytes.fromhex(
        "ff01ffffffa00000000000000000000000000000000000000000000000000000000000000000ff830186a080ffffff02ffff01ff02ffff01ff02ffff03ff0bffff01ff02ffff03ffff09ff05ffff1dff0bffff1effff0bff0bffff02ff06ffff04ff02ffff04ff17ff8080808080808080ffff01ff02ff17ff2f80ffff01ff088080ff0180ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff17ff80808080ff80808080ffff02ff17ff2f808080ff0180ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080ffff04ffff01b081963921826355dcb6c355ccf9c2637c18adf7d38ee44d803ea9ca41587e48c913d8d46896eb830aeadfc13144a8eac3ff018080ffff80ffff01ffff33ffa06b7a83babea1eec790c947db4464ab657dbe9b887fe9acc247062847b8c2a8a9ff830186a08080ff8080808080"  # noqa
    ))

gen1 = SerializedProgram.from_bytes(
    bytes.fromhex(
        "ff01ffffffa00000000000000000000000000000000000000000000000000000000000000000ff830186a080ffffff02ffff01ff02ffff01ff02ffff03ff0bffff01ff02ffff03ffff09ff05ffff1dff0bffff1effff0bff0bffff02ff06ffff04ff02ffff04ff17ff8080808080808080ffff01ff02ff17ff2f80ffff01ff088080ff0180ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff17ff80808080ff80808080ffff02ff17ff2f808080ff0180ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080ffff04ffff01b081963921826355dcb6c355ccf9c2637c18adf7d38ee44d803ea9ca41587e48c913d8d46896eb830aeadfc13144a8eac3ff018080ffff80ffff01ffff33ffa06b7a83babea1eec790c947db4464ab657dbe9b887fe9acc247062847b8c2a8a9ff830186a08080ff8080808080"  # noqa
    ))

gen2 = SerializedProgram.from_bytes(
    bytes.fromhex(
        "ff01ffffffa00000000000000000000000000000000000000000000000000000000000000000ff830186a080ffffff02ffff01ff02ffff01ff02ffff03ff0bffff01ff02ffff03ffff09ff05ffff1dff0bffff1effff0bff0bffff02ff06ffff04ff02ffff04ff17ff8080808080808080ffff01ff02ff17ff2f80ffff01ff088080ff0180ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff17ff80808080ff80808080ffff02ff17ff2f808080ff0180ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080ffff04ffff01b081963921826355dcb6c355ccf9c2637c18adf7d38ee44d803ea9ca41587e48c913d8d46896eb830aeadfc13144a8eac3ff018080ffff80ffff01ffff33ffa06b7a83babea1eec790c947db4464ab657dbe9b887fe9acc247062847b8c2a8a9ff830186a08080ff8080808080"  # noqa
    ))


class BlockDict(GeneratorBlockCacheInterface):
    def __init__(self, d: Dict[uint32, SerializedProgram]):
        self.d = d

    def get_generator_for_block_height(self,
                                       index: uint32) -> SerializedProgram:
        return self.d[index]