Beispiel #1
0
async def main():
    rpc_port = 8555
    self_hostname = "localhost"
    path = DEFAULT_ROOT_PATH
    config = load_config(path, "config.yaml")
    client = await FullNodeRpcClient.create(self_hostname, rpc_port, path,
                                            config)
    try:
        farmer_prefarm = (
            await
            client.get_block_record_by_height(1)).reward_claims_incorporated[1]
        pool_prefarm = (
            await
            client.get_block_record_by_height(1)).reward_claims_incorporated[0]

        pool_amounts = int(calculate_pool_reward(uint32(0)) / 2)
        farmer_amounts = int(calculate_base_farmer_reward(uint32(0)) / 2)
        print(farmer_prefarm.amount, farmer_amounts)
        assert farmer_amounts == farmer_prefarm.amount // 2
        assert pool_amounts == pool_prefarm.amount // 2

        address1 = "txch15gx26ndmacfaqlq8m0yajeggzceu7cvmaz4df0hahkukes695rss6lej7h"  # Gene wallet (m/12381/8444/2/42):
        address2 = (
            "txch1c2cguswhvmdyz9hr3q6hak2h6p9dw4rz82g4707k2xy2sarv705qcce4pn"  # Mariano address (m/12381/8444/2/0)
        )

        ph1 = decode_puzzle_hash(address1)
        ph2 = decode_puzzle_hash(address2)

        p_farmer_2 = Program.to(
            binutils.assemble(
                f"(q . ((51 0x{ph1.hex()} {farmer_amounts}) (51 0x{ph2.hex()} {farmer_amounts})))"
            ))
        p_pool_2 = Program.to(
            binutils.assemble(
                f"(q . ((51 0x{ph1.hex()} {pool_amounts}) (51 0x{ph2.hex()} {pool_amounts})))"
            ))

        p_solution = Program.to(binutils.assemble("()"))

        sb_farmer = SpendBundle(
            [CoinSolution(farmer_prefarm, p_farmer_2, p_solution)],
            G2Element())
        sb_pool = SpendBundle(
            [CoinSolution(pool_prefarm, p_pool_2, p_solution)], G2Element())

        print(sb_pool, sb_farmer)
        # res = await client.push_tx(sb_farmer)
        res = await client.push_tx(sb_pool)

        print(res)
        up = await client.get_coin_records_by_puzzle_hash(
            farmer_prefarm.puzzle_hash, True)
        uf = await client.get_coin_records_by_puzzle_hash(
            pool_prefarm.puzzle_hash, True)
        print(up)
        print(uf)
    finally:
        client.close()
async def main():
    rpc_port = 8555
    self_hostname = "localhost"
    path = DEFAULT_ROOT_PATH
    config = load_config(path, "config.yaml")
    client = await FullNodeRpcClient.create(self_hostname, rpc_port, path,
                                            config)
    try:
        farmer_prefarm = (
            await
            client.get_block_record_by_height(1)).reward_claims_incorporated[1]
        pool_prefarm = (
            await
            client.get_block_record_by_height(1)).reward_claims_incorporated[0]

        pool_amounts = int(calculate_pool_reward(uint32(0)) / 2)
        farmer_amounts = int(calculate_base_farmer_reward(uint32(0)) / 2)
        print(farmer_prefarm.amount, farmer_amounts)
        assert farmer_amounts == farmer_prefarm.amount // 2
        assert pool_amounts == pool_prefarm.amount // 2

        address1 = "txch1k50glwkdffp2mrqq64rsgjtxj4waphuf72stqayz4qqk6mj9hd4qp7lrek"  # Gene wallet (m/12381/8444/2/51):
        address2 = "txch1430mtj60hvzyuyz4t45dyxwjdjsvphhl2fgreyry362reca4zpkszhjd3e"  # farmer1 key (m/12381/8444/2/51)

        ph1 = decode_puzzle_hash(address1)
        ph2 = decode_puzzle_hash(address2)

        p_farmer_2 = Program.to(
            binutils.assemble(
                f"(q . ((51 0x{ph1.hex()} {farmer_amounts}) (51 0x{ph2.hex()} {farmer_amounts})))"
            ))
        p_pool_2 = Program.to(
            binutils.assemble(
                f"(q . ((51 0x{ph1.hex()} {pool_amounts}) (51 0x{ph2.hex()} {pool_amounts})))"
            ))

        p_solution = Program.to(binutils.assemble("()"))

        sb_farmer = SpendBundle(
            [CoinSolution(farmer_prefarm, p_farmer_2, p_solution)],
            G2Element())
        sb_pool = SpendBundle(
            [CoinSolution(pool_prefarm, p_pool_2, p_solution)], G2Element())

        print(sb_pool, sb_farmer)
        # res = await client.push_tx(sb_farmer)
        # res = await client.push_tx(sb_pool)

        # print(res)
        up = await client.get_coin_records_by_puzzle_hash(
            farmer_prefarm.puzzle_hash, True)
        uf = await client.get_coin_records_by_puzzle_hash(
            pool_prefarm.puzzle_hash, True)
        print(up)
        print(uf)
    finally:
        client.close()
Beispiel #3
0
async def main() -> None:
    rpc_port: uint16 = uint16(8555)
    self_hostname = "localhost"
    path = DEFAULT_ROOT_PATH
    config = load_config(path, "config.yaml")
    client = await FullNodeRpcClient.create(self_hostname, rpc_port, path,
                                            config)
    try:
        farmer_prefarm = (
            await
            client.get_block_record_by_height(1)).reward_claims_incorporated[1]
        pool_prefarm = (
            await
            client.get_block_record_by_height(1)).reward_claims_incorporated[0]

        pool_amounts = int(calculate_pool_reward(uint32(0)) / 2)
        farmer_amounts = int(calculate_base_farmer_reward(uint32(0)) / 2)
        print(farmer_prefarm.amount, farmer_amounts)
        assert farmer_amounts == farmer_prefarm.amount // 2
        assert pool_amounts == pool_prefarm.amount // 2
        address1 = "xch1rdatypul5c642jkeh4yp933zu3hw8vv8tfup8ta6zfampnyhjnusxdgns6"  # Key 1
        address2 = "xch1duvy5ur5eyj7lp5geetfg84cj2d7xgpxt7pya3lr2y6ke3696w9qvda66e"  # Key 2

        ph1 = decode_puzzle_hash(address1)
        ph2 = decode_puzzle_hash(address2)

        p_farmer_2 = Program.to(
            binutils.assemble(
                f"(q . ((51 0x{ph1.hex()} {farmer_amounts}) (51 0x{ph2.hex()} {farmer_amounts})))"
            ))
        p_pool_2 = Program.to(
            binutils.assemble(
                f"(q . ((51 0x{ph1.hex()} {pool_amounts}) (51 0x{ph2.hex()} {pool_amounts})))"
            ))

        p_solution = Program.to(binutils.assemble("()"))

        sb_farmer = SpendBundle(
            [CoinSolution(farmer_prefarm, p_farmer_2, p_solution)],
            G2Element())
        sb_pool = SpendBundle(
            [CoinSolution(pool_prefarm, p_pool_2, p_solution)], G2Element())

        print(sb_pool, sb_farmer)
        res = await client.push_tx(sb_farmer)
        # res = await client.push_tx(sb_pool)

        print(res)
        up = await client.get_coin_records_by_puzzle_hash(
            farmer_prefarm.puzzle_hash, True)
        uf = await client.get_coin_records_by_puzzle_hash(
            pool_prefarm.puzzle_hash, True)
        print(up)
        print(uf)
    finally:
        client.close()
Beispiel #4
0
    def aggregate(cls, offers: List["Offer"]) -> "Offer":
        total_requested_payments: Dict[Optional[bytes32],
                                       List[NotarizedPayment]] = {}
        total_bundle = SpendBundle([], G2Element())
        for offer in offers:
            # First check for any overlap in inputs
            total_inputs: Set[Coin] = {
                cs.coin
                for cs in total_bundle.coin_spends
            }
            offer_inputs: Set[Coin] = {
                cs.coin
                for cs in offer.bundle.coin_spends
            }
            if total_inputs & offer_inputs:
                raise ValueError("The aggregated offers overlap inputs")

            # Next, do the aggregation
            for tail, payments in offer.requested_payments.items():
                if tail in total_requested_payments:
                    total_requested_payments[tail].extend(payments)
                else:
                    total_requested_payments[tail] = payments

            total_bundle = SpendBundle.aggregate([total_bundle, offer.bundle])

        return cls(total_requested_payments, total_bundle)
Beispiel #5
0
    def to_spend_bundle(self) -> SpendBundle:
        # Before we serialze this as a SpendBundle, we need to serialze the `requested_payments` as dummy CoinSpends
        additional_coin_spends: List[CoinSpend] = []
        for tail_hash, payments in self.requested_payments.items():
            puzzle_reveal: Program = construct_cat_puzzle(
                CAT_MOD, tail_hash, OFFER_MOD) if tail_hash else OFFER_MOD
            inner_solutions = []
            nonces: List[bytes32] = [p.nonce for p in payments]
            for nonce in list(
                    dict.fromkeys(nonces)):  # dedup without messing with order
                nonce_payments: List[NotarizedPayment] = list(
                    filter(lambda p: p.nonce == nonce, payments))
                inner_solutions.append(
                    (nonce, [np.as_condition_args() for np in nonce_payments]))

            additional_coin_spends.append(
                CoinSpend(
                    Coin(
                        ZERO_32,
                        puzzle_reveal.get_tree_hash(),
                        uint64(0),
                    ),
                    puzzle_reveal,
                    Program.to(inner_solutions),
                ))

        return SpendBundle.aggregate([
            SpendBundle(additional_coin_spends, G2Element()),
            self.bundle,
        ])
Beispiel #6
0
def do_inspect_spend_bundle_cmd(ctx, bundles, print_results=True, **kwargs):
    if kwargs and (len(kwargs['spend']) > 0) and (len(kwargs['aggsig']) > 0):
        spend_bundle_objs = [
            SpendBundle(
                do_inspect_coin_spend_cmd(ctx,
                                          kwargs["spend"],
                                          print_results=False),
                AugSchemeMPL.aggregate([
                    G2Element(bytes.fromhex(sanitize_bytes(aggsig)))
                    for aggsig in kwargs["aggsig"]
                ]))
        ]
    else:
        spend_bundle_objs = []
        try:
            if type(bundles[0]) == str:
                spend_bundle_objs = streamable_load(SpendBundle, bundles)
            else:
                spend_bundle_objs = bundles
        except:
            print(
                "One or more of the specified objects was not a spend bundle")

    if print_results:
        inspect_callback(spend_bundle_objs,
                         ctx,
                         id_calc=(lambda e: e.name()),
                         type='SpendBundle')
    else:
        return spend_bundle_objs
Beispiel #7
0
def launcher_conditions_and_spend_bundle(
    parent_coin_id: bytes32,
    launcher_amount: uint64,
    initial_singleton_inner_puzzle: Program,
    metadata: List[Tuple[str, str]],
    launcher_puzzle: Program = LAUNCHER_PUZZLE,
) -> Tuple[Program, bytes32, List[Program], SpendBundle]:
    launcher_puzzle_hash = launcher_puzzle.get_tree_hash()
    launcher_coin = Coin(parent_coin_id, launcher_puzzle_hash, launcher_amount)
    singleton_full_puzzle = SINGLETON_MOD.curry(
        SINGLETON_MOD_HASH, launcher_coin.name(), launcher_puzzle_hash,
        initial_singleton_inner_puzzle)
    singleton_full_puzzle_hash = singleton_full_puzzle.get_tree_hash()
    message_program = Program.to(
        [singleton_full_puzzle_hash, launcher_amount, metadata])
    expected_announcement = Announcement(launcher_coin.name(),
                                         message_program.get_tree_hash())
    expected_conditions = []
    expected_conditions.append(
        Program.to(
            binutils.assemble(
                f"(0x{ConditionOpcode.ASSERT_COIN_ANNOUNCEMENT.hex()} 0x{expected_announcement.name()})"
            )))
    expected_conditions.append(
        Program.to(
            binutils.assemble(
                f"(0x{ConditionOpcode.CREATE_COIN.hex()} 0x{launcher_puzzle_hash} {launcher_amount})"
            )))
    launcher_solution = Program.to(
        [singleton_full_puzzle_hash, launcher_amount, metadata])
    coin_spend = CoinSpend(launcher_coin, launcher_puzzle, launcher_solution)
    spend_bundle = SpendBundle([coin_spend], G2Element())
    lineage_proof = Program.to([parent_coin_id, launcher_amount])
    return lineage_proof, launcher_coin.name(
    ), expected_conditions, spend_bundle
    async def test_delegated_tail(self, setup_sim):
        sim, sim_client = setup_sim

        try:
            standard_acs = Program.to(1)
            standard_acs_ph: bytes32 = standard_acs.get_tree_hash()
            await sim.farm_block(standard_acs_ph)

            starting_coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(standard_acs_ph))[0].coin
            sk = PrivateKey.from_bytes(secret_exponent_for_index(1).to_bytes(32, "big"))
            tail: Program = DelegatedLimitations.construct([Program.to(sk.get_g1())])
            cat_puzzle: Program = construct_cat_puzzle(CAT_MOD, tail.get_tree_hash(), acs)
            cat_ph: bytes32 = cat_puzzle.get_tree_hash()

            await sim_client.push_tx(
                SpendBundle(
                    [CoinSpend(starting_coin, standard_acs, Program.to([[51, cat_ph, starting_coin.amount]]))],
                    G2Element(),
                )
            )
            await sim.farm_block()

            # We're signing a different tail to use here
            name_as_program = Program.to(starting_coin.name())
            new_tail: Program = GenesisById.construct([name_as_program])
            checker_solution: Program = DelegatedLimitations.solve(
                [name_as_program],
                {
                    "signed_program": {
                        "identifier": "genesis_by_id",
                        "args": [str(name_as_program)],
                    },
                    "program_arguments": {},
                },
            )
            signature: G2Element = AugSchemeMPL.sign(sk, new_tail.get_tree_hash())

            await self.do_spend(
                sim,
                sim_client,
                tail,
                [(await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False))[0].coin],
                [NO_LINEAGE_PROOF],
                [
                    Program.to(
                        [
                            [51, acs.get_tree_hash(), starting_coin.amount],
                            [51, 0, -113, tail, checker_solution],
                        ]
                    )
                ],
                (MempoolInclusionStatus.SUCCESS, None),
                signatures=[signature],
                limitations_solutions=[checker_solution],
                cost_str="Delegated Genesis",
            )

        finally:
            await sim.close()
Beispiel #9
0
def test_vectors_invalid():
    # Invalid inputs from https://github.com/algorand/bls_sigs_ref/blob/master/python-impl/serdesZ.py
    invalid_inputs_1 = [
        # infinity points: too short
        "c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
        # infinity points: not all zeros
        "c00000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000",
        # bad tags
        "3a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa",
        "7a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa",
        "fa0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa",
        # wrong length for compresed point
        "9a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa",
        "9a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaaaa",
        # invalid x-coord
        "9a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa",
        # invalid elm of Fp --- equal to p (must be strictly less)
        "9a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab",
    ]
    invalid_inputs_2 = [
        # infinity points: too short
        "c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
        # infinity points: not all zeros
        "c00000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
        "c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000",
        # bad tags
        "3a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
        "7a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
        "fa0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
        # wrong length for compressed point
        "9a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
        "9a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
        # invalid x-coord
        "9a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaa7",
        # invalid elm of Fp --- equal to p (must be strictly less)
        "9a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
        "9a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab",
    ]

    for s in invalid_inputs_1:
        bytes_ = binascii.unhexlify(s)
        try:
            g1 = G1Element(bytes_)
            assert False, "Failed to disallow creation of G1 element."
        except Exception as e:
            pass

    for s in invalid_inputs_2:
        bytes_ = binascii.unhexlify(s)
        try:
            g2 = G2Element(bytes_)
            assert False, "Failed to disallow creation of G2 element."
        except Exception as e:
            pass
Beispiel #10
0
async def check_conditions(
    condition_solution: Program, expected_err: Optional[Err] = None, spend_reward_index: int = -2
):
    blocks = initial_blocks()
    coin = list(blocks[spend_reward_index].get_included_reward_coins())[0]

    coin_solution = CoinSolution(coin, EASY_PUZZLE, condition_solution)
    spend_bundle = SpendBundle([coin_solution], G2Element())

    # now let's try to create a block with the spend bundle and ensure that it doesn't validate

    await check_spend_bundle_validity(bt.constants, blocks, spend_bundle, expected_err=expected_err)
def test_only_odd_coins_0():
    blocks = initial_blocks()
    farmed_coin = list(blocks[-1].get_included_reward_coins())[0]

    metadata = [("foo", "bar")]
    ANYONE_CAN_SPEND_PUZZLE = Program.to(1)
    launcher_amount = uint64(1)
    launcher_puzzle = LAUNCHER_PUZZLE
    launcher_puzzle_hash = launcher_puzzle.get_tree_hash()
    initial_singleton_puzzle = adaptor_for_singleton_inner_puzzle(
        ANYONE_CAN_SPEND_PUZZLE)
    lineage_proof, launcher_id, condition_list, launcher_spend_bundle = launcher_conditions_and_spend_bundle(
        farmed_coin.name(), launcher_amount, initial_singleton_puzzle,
        metadata, launcher_puzzle)

    conditions = Program.to(condition_list)
    coin_solution = CoinSolution(farmed_coin, ANYONE_CAN_SPEND_PUZZLE,
                                 conditions)
    spend_bundle = SpendBundle.aggregate(
        [launcher_spend_bundle,
         SpendBundle([coin_solution], G2Element())])
    run = asyncio.get_event_loop().run_until_complete
    coins_added, coins_removed = run(
        check_spend_bundle_validity(bt.constants, blocks, spend_bundle))

    coin_set_added = set([_.coin for _ in coins_added])
    coin_set_removed = set([_.coin for _ in coins_removed])

    launcher_coin = launcher_spend_bundle.coin_solutions[0].coin

    assert launcher_coin in coin_set_added
    assert launcher_coin in coin_set_removed

    assert farmed_coin in coin_set_removed
    # breakpoint()

    singleton_expected_puzzle_hash = singleton_puzzle_hash(
        launcher_id, launcher_puzzle_hash, initial_singleton_puzzle)
    expected_singleton_coin = Coin(launcher_coin.name(),
                                   singleton_expected_puzzle_hash,
                                   launcher_amount)
    assert expected_singleton_coin in coin_set_added

    # next up: spend the expected_singleton_coin
    # it's an adapted `ANYONE_CAN_SPEND_PUZZLE`

    # then try a bad lineage proof
    # then try writing two odd coins
    # then try writing zero odd coins

    # then, destroy the singleton with the -113 hack

    return 0
    def generate_secure_bundle(
        self,
        selected_coins: List[Coin],
        announcements: List[Announcement],
        offered_amount: uint64,
        tail_str: Optional[str] = None,
    ) -> SpendBundle:
        announcement_assertions: List[List] = [[63, a.name()]
                                               for a in announcements]
        selected_coin_amount: int = sum([c.amount for c in selected_coins])
        non_primaries: List[Coin] = [] if len(
            selected_coins) < 2 else selected_coins[1:]
        inner_solution: List[List] = [
            [51, Offer.ph(), offered_amount],  # Offered coin
            [51, acs_ph,
             uint64(selected_coin_amount - offered_amount)],  # Change
            *announcement_assertions,
        ]

        if tail_str is None:
            bundle = SpendBundle(
                [
                    CoinSpend(
                        selected_coins[0],
                        acs,
                        Program.to(inner_solution),
                    ),
                    *[
                        CoinSpend(c, acs, Program.to([]))
                        for c in non_primaries
                    ],
                ],
                G2Element(),
            )
        else:
            spendable_cats: List[SpendableCAT] = [
                SpendableCAT(
                    c,
                    str_to_tail_hash(tail_str),
                    acs,
                    Program.to([
                        [51, 0, -113,
                         str_to_tail(tail_str),
                         Program.to([])],  # Use the TAIL rather than lineage
                        *(inner_solution if c == selected_coins[0] else []),
                    ]),
                ) for c in selected_coins
            ]
            bundle = unsigned_spend_bundle_for_spendable_cats(
                CAT_MOD, spendable_cats)

        return bundle
def spend_coin_to_singleton(
        puzzle_db: PuzzleDB, launcher_puzzle: Program, coin_store: CoinStore,
        now: CoinTimestamp) -> Tuple[List[Coin], List[CoinSpend]]:

    farmed_coin_amount = 100000
    metadata = [("foo", "bar")]

    now = CoinTimestamp(10012300, 1)
    farmed_coin = coin_store.farm_coin(ANYONE_CAN_SPEND_PUZZLE.get_tree_hash(),
                                       now,
                                       amount=farmed_coin_amount)
    now.seconds += 500
    now.height += 1

    launcher_amount: uint64 = uint64(1)
    launcher_puzzle = LAUNCHER_PUZZLE
    launcher_puzzle_hash = launcher_puzzle.get_tree_hash()
    initial_singleton_puzzle = adaptor_for_singleton_inner_puzzle(
        ANYONE_CAN_SPEND_PUZZLE)
    launcher_id, condition_list, launcher_spend_bundle = launcher_conditions_and_spend_bundle(
        puzzle_db, farmed_coin.name(), launcher_amount,
        initial_singleton_puzzle, metadata, launcher_puzzle)

    conditions = Program.to(condition_list)
    coin_spend = CoinSpend(farmed_coin, ANYONE_CAN_SPEND_PUZZLE, conditions)
    spend_bundle = SpendBundle.aggregate(
        [launcher_spend_bundle,
         SpendBundle([coin_spend], G2Element())])

    additions, removals = coin_store.update_coin_store_for_spend_bundle(
        spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE)

    launcher_coin = launcher_spend_bundle.coin_spends[0].coin

    assert_coin_spent(coin_store, launcher_coin)
    assert_coin_spent(coin_store, farmed_coin)

    # TODO: address hint error and remove ignore
    #       error: Argument 1 to "singleton_puzzle" has incompatible type "bytes32"; expected "Program"  [arg-type]
    singleton_expected_puzzle = singleton_puzzle(
        launcher_id,  # type: ignore[arg-type]
        launcher_puzzle_hash,
        initial_singleton_puzzle,
    )
    singleton_expected_puzzle_hash = singleton_expected_puzzle.get_tree_hash()
    expected_singleton_coin = Coin(launcher_coin.name(),
                                   singleton_expected_puzzle_hash,
                                   launcher_amount)
    assert_coin_spent(coin_store, expected_singleton_coin, is_spent=False)

    return additions, removals
def launcher_conditions_and_spend_bundle(
    puzzle_db: PuzzleDB,
    parent_coin_id: bytes32,
    launcher_amount: uint64,
    initial_singleton_inner_puzzle: Program,
    metadata: List[Tuple[str, str]],
    launcher_puzzle: Program,
) -> Tuple[bytes32, List[Program], SpendBundle]:
    puzzle_db.add_puzzle(launcher_puzzle)
    launcher_puzzle_hash = launcher_puzzle.get_tree_hash()
    launcher_coin = Coin(parent_coin_id, launcher_puzzle_hash, launcher_amount)
    # TODO: address hint error and remove ignore
    #       error: Argument 1 to "singleton_puzzle" has incompatible type "bytes32"; expected "Program"  [arg-type]
    singleton_full_puzzle = singleton_puzzle(
        launcher_coin.name(),  # type: ignore[arg-type]
        launcher_puzzle_hash,
        initial_singleton_inner_puzzle,
    )
    puzzle_db.add_puzzle(singleton_full_puzzle)
    singleton_full_puzzle_hash = singleton_full_puzzle.get_tree_hash()
    message_program = Program.to(
        [singleton_full_puzzle_hash, launcher_amount, metadata])
    expected_announcement = Announcement(launcher_coin.name(),
                                         message_program.get_tree_hash())
    expected_conditions = []
    expected_conditions.append(
        Program.to(
            binutils.assemble(
                f"(0x{ConditionOpcode.ASSERT_COIN_ANNOUNCEMENT.hex()} 0x{expected_announcement.name()})"
            )))
    expected_conditions.append(
        Program.to(
            binutils.assemble(
                f"(0x{ConditionOpcode.CREATE_COIN.hex()} 0x{launcher_puzzle_hash} {launcher_amount})"
            )))
    solution = solve_puzzle(
        puzzle_db,
        launcher_puzzle,
        destination_puzzle_hash=singleton_full_puzzle_hash,
        launcher_amount=launcher_amount,
        metadata=metadata,
    )
    coin_spend = CoinSpend(launcher_coin,
                           SerializedProgram.from_program(launcher_puzzle),
                           solution)
    spend_bundle = SpendBundle([coin_spend], G2Element())
    return launcher_coin.name(), expected_conditions, spend_bundle
Beispiel #15
0
async def create_absorb_transaction(
    node_rpc_client: FullNodeRpcClient,
    farmer_record: FarmerRecord,
    peak_height: uint32,
    reward_coin_records: List[CoinRecord],
    genesis_challenge: bytes32,
) -> SpendBundle:
    last_solution, last_state, _, _ = await get_and_validate_singleton_state_inner(
        node_rpc_client, farmer_record.launcher_id, farmer_record, peak_height,
        0, None)
    launcher_coin_record: Optional[
        CoinRecord] = await node_rpc_client.get_coin_record_by_name(
            farmer_record.launcher_id)
    assert launcher_coin_record is not None

    all_spends: List[CoinSolution] = []
    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),
                                         genesis_challenge)
            if pool_parent == reward_coin_record.coin.parent_coin_info:
                found_block_index = uint32(block_index)
        if not found_block_index:
            # The puzzle does not allow spending coins that are not a coinbase reward
            log.info(
                f"Received reward {reward_coin_record.coin} that is not a pool reward."
            )
            continue
        absorb_spend: List[CoinSolution] = create_absorb_spend(
            last_solution,
            last_state,
            launcher_coin_record.coin,
            found_block_index,
            genesis_challenge,
            farmer_record.delay_time,
            farmer_record.delay_puzzle_hash,
        )
        last_solution = absorb_spend[0]
        all_spends += absorb_spend
        # TODO(pool): handle the case where the cost exceeds the size of the block

    return SpendBundle(all_spends, G2Element())
def do_test_spend(
    puzzle_reveal: Program,
    solution: Program,
    payments: Iterable[Tuple[bytes32, int]],
    key_lookup: KeyTool,
    farm_time: CoinTimestamp = T1,
    spend_time: CoinTimestamp = T2,
) -> SpendBundle:
    """
    This method will farm a coin paid to the hash of `puzzle_reveal`, then try to spend it
    with `solution`, and verify that the created coins correspond to `payments`.

    The `key_lookup` is used to create a signed version of the `SpendBundle`, although at
    this time, signatures are not verified.
    """

    coin_db = CoinStore()

    puzzle_hash = puzzle_reveal.get_tree_hash()

    # farm it
    coin = coin_db.farm_coin(puzzle_hash, farm_time)

    # spend it
    coin_spend = CoinSpend(coin, puzzle_reveal, solution)

    spend_bundle = SpendBundle([coin_spend], G2Element())
    coin_db.update_coin_store_for_spend_bundle(spend_bundle, spend_time,
                                               MAX_BLOCK_COST_CLVM,
                                               COST_PER_BYTE)

    # ensure all outputs are there
    for puzzle_hash, amount in payments:
        for coin in coin_db.coins_for_puzzle_hash(puzzle_hash):
            if coin.amount == amount:
                break
        else:
            assert 0

    # make sure we can actually sign the solution
    signatures = []
    for coin_spend in spend_bundle.coin_spends:
        signature = key_lookup.signature_for_solution(coin_spend,
                                                      bytes([2] * 32))
        signatures.append(signature)
    return SpendBundle(spend_bundle.coin_spends,
                       AugSchemeMPL.aggregate(signatures))
 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))
Beispiel #18
0
def tx(info):
    j = json.dumps(info)
    m: Dict = eval(j)
    inputs: List = m.get("inputs")
    outputs: List = m.get("outputs")

    primaries = []
    for o in outputs:
        output: Dict = o
        address: str = output.get("address")
        value: float = output.get("value")
        primaries.append({
            "puzzlehash": decode_puzzle_hash(address),
            "amount": value
        })

    spends: List[CoinSolution] = []
    pks: List[str] = []
    first_spend = True
    for i in inputs:
        input: Dict = i
        pk: str = input.get("pk")
        pks.append(pk)
        txid: Dict = eval(input.get("txId"))
        parentCoinInfo = txid.get("parentCoinInfo")
        puzzleHash = txid.get("puzzleHash")
        amount = txid.get("amount")

        pa = bytes32(bytes.fromhex(parentCoinInfo[2:]))
        pu = bytes32(bytes.fromhex(puzzleHash[2:]))
        a = uint64(amount)
        coin: Coin = Coin(pa, pu, a)
        child_sk: PrivateKey = PrivateKey.from_bytes(bytes.fromhex(pk))
        child_public_key = child_sk.get_g1()
        puzzle = puzzle_for_pk(child_public_key)

        if first_spend:
            solution: Program = Wallet().make_solution(primaries=primaries)
            first_spend = False
        else:
            solution = Wallet().make_solution()
        spends.append(CoinSolution(coin, puzzle, solution))

    spend_bundle: SpendBundle = SpendBundle(spends, G2Element())
    # return json.dumps(spend_bundle.to_json_dict())
    return sign_tx(pks, spend_bundle)
Beispiel #19
0
def sign_tx(pks: List[str], spend_bundle: SpendBundle):
    # This field is the ADDITIONAL_DATA found in the constants
    additional_data: bytes = bytes.fromhex(
        "ccd5bb71183532bff220ba46c268991a3ff07eb358e8255a65c30a2dce0e5fbb")
    puzzle_hash_to_sk: Dict[bytes32, PrivateKey] = {}

    for p in pks:
        child_sk: PrivateKey = PrivateKey.from_bytes(bytes.fromhex(p))
        # master_private_key = PrivateKey.from_bytes(
        #     bytes.fromhex(p))
        # child_sk = master_sk_to_wallet_sk(master_private_key, 242)
        child_pk: G1Element = child_sk.get_g1()
        puzzle = puzzle_for_pk(child_pk)
        puzzle_hash = puzzle.get_tree_hash()
        puzzle_hash_to_sk[puzzle_hash] = child_sk

    aggregate_signature: G2Element = G2Element()
    for coin_solution in spend_bundle.coin_solutions:
        if coin_solution.coin.puzzle_hash not in puzzle_hash_to_sk:
            return
        sk: PrivateKey = puzzle_hash_to_sk[coin_solution.coin.puzzle_hash]
        synthetic_secret_key: PrivateKey = calculate_synthetic_secret_key(
            sk, DEFAULT_HIDDEN_PUZZLE_HASH)

        err, conditions_dict, cost = conditions_dict_for_solution(
            coin_solution.puzzle_reveal, coin_solution.solution, 11000000000)

        if err or conditions_dict is None:
            print(
                f"Sign transaction failed, con:{conditions_dict}, error: {err}"
            )
            return

        pk_msgs = pkm_pairs_for_conditions_dict(
            conditions_dict, bytes(coin_solution.coin.name()), additional_data)
        assert len(pk_msgs) == 1
        _, msg = pk_msgs[0]
        signature = AugSchemeMPL.sign(synthetic_secret_key, msg)

        aggregate_signature = AugSchemeMPL.aggregate(
            [aggregate_signature, signature])

    new_spend_bundle = SpendBundle(spend_bundle.coin_solutions,
                                   aggregate_signature)
    # print(json.dumps(new_spend_bundle.to_json_dict()))
    return json.dumps(new_spend_bundle.to_json_dict())
    async def test_genesis_by_puzhash(self, setup_sim):
        sim, sim_client = setup_sim

        try:
            standard_acs = Program.to(1)
            standard_acs_ph: bytes32 = standard_acs.get_tree_hash()
            await sim.farm_block(standard_acs_ph)

            starting_coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(standard_acs_ph))[0].coin
            tail: Program = GenesisByPuzhash.construct([Program.to(starting_coin.puzzle_hash)])
            checker_solution: Program = GenesisByPuzhash.solve([], starting_coin.to_json_dict())
            cat_puzzle: Program = construct_cat_puzzle(CAT_MOD, tail.get_tree_hash(), acs)
            cat_ph: bytes32 = cat_puzzle.get_tree_hash()

            await sim_client.push_tx(
                SpendBundle(
                    [CoinSpend(starting_coin, standard_acs, Program.to([[51, cat_ph, starting_coin.amount]]))],
                    G2Element(),
                )
            )
            await sim.farm_block()

            await self.do_spend(
                sim,
                sim_client,
                tail,
                [(await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False))[0].coin],
                [NO_LINEAGE_PROOF],
                [
                    Program.to(
                        [
                            [51, acs.get_tree_hash(), starting_coin.amount],
                            [51, 0, -113, tail, checker_solution],
                        ]
                    )
                ],
                (MempoolInclusionStatus.SUCCESS, None),
                limitations_solutions=[checker_solution],
                cost_str="Genesis by Puzhash",
            )

        finally:
            await sim.close()
Beispiel #21
0
def compute_coin_hints(cs: CoinSpend) -> List[bytes]:

    bundle = SpendBundle([cs], G2Element())
    generator = simple_solution_generator(bundle)

    npc_result = get_name_puzzle_conditions(
        generator,
        INFINITE_COST,
        cost_per_byte=DEFAULT_CONSTANTS.COST_PER_BYTE,
        mempool_mode=False,
        height=DEFAULT_CONSTANTS.SOFT_FORK_HEIGHT,
    )
    h_list = []
    for npc in npc_result.npc_list:
        for opcode, conditions in npc.conditions:
            if opcode == ConditionOpcode.CREATE_COIN:
                for condition in conditions:
                    if len(condition.vars) > 2 and condition.vars[2] != b"":
                        h_list.append(condition.vars[2])

    return h_list
Beispiel #22
0
from chia.types.blockchain_format.coin import Coin
from chia.types.blockchain_format.program import Program, INFINITE_COST
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.condition_opcodes import ConditionOpcode
from chia.types.spend_bundle import CoinSpend, SpendBundle
from chia.util.condition_tools import conditions_dict_for_solution
from chia.util.ints import uint64
from chia.wallet.puzzles.cc_loader import CC_MOD, LOCK_INNER_PUZZLE
from chia.wallet.puzzles.genesis_by_coin_id_with_0 import (
    genesis_coin_id_for_genesis_coin_checker,
    lineage_proof_for_coin,
    lineage_proof_for_genesis,
    lineage_proof_for_zero,
)

NULL_SIGNATURE = G2Element()

ANYONE_CAN_SPEND_PUZZLE = Program.to(1)  # simply return the conditions

# information needed to spend a cc
# if we ever support more genesis conditions, like a re-issuable coin,
# we may need also to save the `genesis_coin_mod` or its hash


@dataclasses.dataclass
class SpendableCC:
    coin: Coin
    genesis_coin_id: bytes32
    inner_puzzle: Program
    lineage_proof: Program
Beispiel #23
0
    def to_valid_spend(self,
                       arbitrage_ph: Optional[bytes32] = None) -> SpendBundle:
        if not self.is_valid():
            raise ValueError("Offer is currently incomplete")

        completion_spends: List[CoinSpend] = []
        for tail_hash, payments in self.requested_payments.items():
            offered_coins: List[Coin] = self.get_offered_coins()[tail_hash]

            # Because of CAT supply laws, we must specify a place for the leftovers to go
            arbitrage_amount: int = self.arbitrage()[tail_hash]
            all_payments: List[NotarizedPayment] = payments.copy()
            if arbitrage_amount > 0:
                assert arbitrage_amount is not None
                assert arbitrage_ph is not None
                all_payments.append(
                    NotarizedPayment(arbitrage_ph, uint64(arbitrage_amount),
                                     []))

            for coin in offered_coins:
                inner_solutions = []
                if coin == offered_coins[0]:
                    nonces: List[bytes32] = [p.nonce for p in all_payments]
                    for nonce in list(dict.fromkeys(
                            nonces)):  # dedup without messing with order
                        nonce_payments: List[NotarizedPayment] = list(
                            filter(lambda p: p.nonce == nonce, all_payments))
                        inner_solutions.append(
                            (nonce,
                             [np.as_condition_args()
                              for np in nonce_payments]))

                if tail_hash:
                    # CATs have a special way to be solved so we have to do some calculation before getting the solution
                    parent_spend: CoinSpend = list(
                        filter(
                            lambda cs: cs.coin.name() == coin.parent_coin_info,
                            self.bundle.coin_spends))[0]
                    parent_coin: Coin = parent_spend.coin
                    matched, curried_args = match_cat_puzzle(
                        parent_spend.puzzle_reveal.to_program())
                    assert matched
                    _, _, inner_puzzle = curried_args
                    spendable_cat = SpendableCAT(
                        coin,
                        tail_hash,
                        OFFER_MOD,
                        Program.to(inner_solutions),
                        lineage_proof=LineageProof(
                            parent_coin.parent_coin_info,
                            inner_puzzle.get_tree_hash(), parent_coin.amount),
                    )
                    solution: Program = (
                        unsigned_spend_bundle_for_spendable_cats(
                            CAT_MOD, [spendable_cat
                                      ]).coin_spends[0].solution.to_program())
                else:
                    solution = Program.to(inner_solutions)

                completion_spends.append(
                    CoinSpend(
                        coin,
                        construct_cat_puzzle(CAT_MOD, tail_hash, OFFER_MOD)
                        if tail_hash else OFFER_MOD,
                        solution,
                    ))

        return SpendBundle.aggregate(
            [SpendBundle(completion_spends, G2Element()), self.bundle])
Beispiel #24
0
def test_elements():
    b1 = BNWrapper([1, 2])
    b2 = BNWrapper([3, 1, 4, 1, 5, 9])
    i1 = int.from_bytes(bytes([1, 2]), byteorder="big")
    i2 = int.from_bytes(bytes([3, 1, 4, 1, 5, 9]), byteorder="big")
    g1 = G1Element.generator()
    g2 = G2Element.generator()
    u1 = G1Element.infinity()  # unity
    u2 = G2Element.infinity()

    # Does not allow construction
    try:
        i = G1Element()
        assert False
    except Exception:
        pass
    try:
        i = G2Element()
        assert False
    except Exception:
        pass

    x1 = g1 * b1
    x2 = g1 * b2
    y1 = g2 * b1
    y2 = g2 * b2

    # Implicit conversion from python ints to BNWrapperWrapperWrapper
    assert x1 == g1 * i1 == i1 * g1
    assert x2 == g1 * i2 == i2 * g1
    assert y1 == g2 * i1 == i1 * g2
    assert y2 == g2 * i2 == i2 * g2

    # G1
    assert x1 != x2
    assert x1 * b1 == b1 * x1
    assert x1 * b1 != x1 * b2
    assert x1 + u1 == x1
    assert x1 + x2 == x2 + x1
    assert x1 + x1.negate() == u1
    assert x1 == G1Element(bytes(x1))
    copy = deepcopy(x1)
    assert x1 == copy
    x1 += x2
    assert x1 != copy

    # G2
    assert y1 != y2
    assert y1 * b1 == b1 * y1
    assert y1 * b1 != y1 * b2
    assert y1 + u2 == y1
    assert y1 + y2 == y2 + y1
    assert y1 + y1.negate() == u2
    assert y1 == G2Element(bytes(y1))
    copy = deepcopy(y1)
    assert y1 == copy
    y1 += y2
    assert y1 != copy

    # pairing operation
    pair = x1 & y1
    assert pair != x1 & y2
    assert pair != x2 & y1
    assert pair == x1.pair(y1)
    assert pair == GTElement(bytes(pair))
    copy = deepcopy(pair)
    assert pair == copy
    pair = None
    assert pair != copy
def test_lifecycle_with_coinstore_as_wallet():

    PUZZLE_DB = PuzzleDB()

    interested_singletons = []

    #######
    # farm a coin

    coin_store = CoinStore(int.from_bytes(POOL_REWARD_PREFIX_MAINNET, "big"))
    now = CoinTimestamp(10012300, 1)

    DELAY_SECONDS = 86400
    DELAY_PUZZLE_HASH = bytes([0] * 32)

    #######
    # spend coin to a singleton

    additions, removals = spend_coin_to_singleton(PUZZLE_DB, LAUNCHER_PUZZLE,
                                                  coin_store, now)

    assert len(list(coin_store.all_unspent_coins())) == 1

    new_singletons = find_interesting_singletons(PUZZLE_DB, removals)
    interested_singletons.extend(new_singletons)

    assert len(interested_singletons) == 1

    SINGLETON_WALLET = interested_singletons[0]

    #######
    # farm a `p2_singleton`

    pool_reward_puzzle_hash = p2_singleton_puzzle_hash_for_launcher(
        PUZZLE_DB, SINGLETON_WALLET.launcher_id,
        SINGLETON_WALLET.launcher_puzzle_hash, DELAY_SECONDS,
        DELAY_PUZZLE_HASH)
    farmed_coin = coin_store.farm_coin(pool_reward_puzzle_hash, now)
    now.seconds += 500
    now.height += 1

    p2_singleton_coins = filter_p2_singleton(PUZZLE_DB, SINGLETON_WALLET,
                                             [farmed_coin])
    assert p2_singleton_coins == [farmed_coin]

    assert len(list(coin_store.all_unspent_coins())) == 2

    #######
    # now collect the `p2_singleton` using the singleton

    for coin in p2_singleton_coins:
        p2_singleton_coin_spend, singleton_conditions = claim_p2_singleton(
            PUZZLE_DB, SINGLETON_WALLET, coin)

        coin_spend = SINGLETON_WALLET.coin_spend_for_conditions(
            PUZZLE_DB, conditions=singleton_conditions)
        spend_bundle = SpendBundle([coin_spend, p2_singleton_coin_spend],
                                   G2Element())

        additions, removals = coin_store.update_coin_store_for_spend_bundle(
            spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE)
        now.seconds += 500
        now.height += 1

        SINGLETON_WALLET.update_state(PUZZLE_DB, removals)

    assert len(list(coin_store.all_unspent_coins())) == 1

    #######
    # farm and collect another `p2_singleton`

    pool_reward_puzzle_hash = p2_singleton_puzzle_hash_for_launcher(
        PUZZLE_DB, SINGLETON_WALLET.launcher_id,
        SINGLETON_WALLET.launcher_puzzle_hash, DELAY_SECONDS,
        DELAY_PUZZLE_HASH)
    farmed_coin = coin_store.farm_coin(pool_reward_puzzle_hash, now)
    now.seconds += 500
    now.height += 1

    p2_singleton_coins = filter_p2_singleton(PUZZLE_DB, SINGLETON_WALLET,
                                             [farmed_coin])
    assert p2_singleton_coins == [farmed_coin]

    assert len(list(coin_store.all_unspent_coins())) == 2

    for coin in p2_singleton_coins:
        p2_singleton_coin_spend, singleton_conditions = claim_p2_singleton(
            PUZZLE_DB, SINGLETON_WALLET, coin)

        coin_spend = SINGLETON_WALLET.coin_spend_for_conditions(
            PUZZLE_DB, conditions=singleton_conditions)
        spend_bundle = SpendBundle([coin_spend, p2_singleton_coin_spend],
                                   G2Element())

        additions, removals = coin_store.update_coin_store_for_spend_bundle(
            spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE)
        now.seconds += 500
        now.height += 1

        SINGLETON_WALLET.update_state(PUZZLE_DB, removals)

    assert len(list(coin_store.all_unspent_coins())) == 1

    #######
    # loan the singleton to a pool

    # puzzle_for_loan_singleton_to_pool(
    # pool_puzzle_hash, p2_singleton_puzzle_hash, owner_public_key, pool_reward_prefix, relative_lock_height)

    # calculate the series

    owner_public_key = bytes(create_throwaway_pubkey(b"foo"))
    pool_puzzle_hash = Program.to(bytes(
        create_throwaway_pubkey(b""))).get_tree_hash()
    pool_reward_prefix = POOL_REWARD_PREFIX_MAINNET
    relative_lock_height = 1440

    pool_escaping_puzzle = POOL_WAITINGROOM_MOD.curry(pool_puzzle_hash,
                                                      pool_reward_puzzle_hash,
                                                      owner_public_key,
                                                      pool_reward_prefix,
                                                      relative_lock_height)
    pool_escaping_puzzle_hash = pool_escaping_puzzle.get_tree_hash()

    pool_member_puzzle = POOL_MEMBER_MOD.curry(
        pool_puzzle_hash,
        pool_reward_puzzle_hash,
        owner_public_key,
        pool_reward_prefix,
        pool_escaping_puzzle_hash,
    )
    pool_member_puzzle_hash = pool_member_puzzle.get_tree_hash()

    PUZZLE_DB.add_puzzle(pool_escaping_puzzle)
    PUZZLE_DB.add_puzzle(
        singleton_puzzle(SINGLETON_WALLET.launcher_id,
                         SINGLETON_WALLET.launcher_puzzle_hash,
                         pool_escaping_puzzle))
    PUZZLE_DB.add_puzzle(pool_member_puzzle)
    full_puzzle = singleton_puzzle(SINGLETON_WALLET.launcher_id,
                                   SINGLETON_WALLET.launcher_puzzle_hash,
                                   pool_member_puzzle)
    PUZZLE_DB.add_puzzle(full_puzzle)

    conditions = [
        Program.to([ConditionOpcode.CREATE_COIN, pool_member_puzzle_hash, 1])
    ]

    singleton_coin_spend = SINGLETON_WALLET.coin_spend_for_conditions(
        PUZZLE_DB, conditions=conditions)

    spend_bundle = SpendBundle([singleton_coin_spend], G2Element())

    additions, removals = coin_store.update_coin_store_for_spend_bundle(
        spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE)

    assert len(list(coin_store.all_unspent_coins())) == 1

    SINGLETON_WALLET.update_state(PUZZLE_DB, removals)

    #######
    # farm a `p2_singleton`

    pool_reward_puzzle_hash = p2_singleton_puzzle_hash_for_launcher(
        PUZZLE_DB, SINGLETON_WALLET.launcher_id,
        SINGLETON_WALLET.launcher_puzzle_hash, DELAY_SECONDS,
        DELAY_PUZZLE_HASH)
    farmed_coin = coin_store.farm_coin(pool_reward_puzzle_hash, now)
    now.seconds += 500
    now.height += 1

    p2_singleton_coins = filter_p2_singleton(PUZZLE_DB, SINGLETON_WALLET,
                                             [farmed_coin])
    assert p2_singleton_coins == [farmed_coin]

    assert len(list(coin_store.all_unspent_coins())) == 2

    #######
    # now collect the `p2_singleton` for the pool

    for coin in p2_singleton_coins:
        p2_singleton_coin_spend, singleton_conditions = claim_p2_singleton(
            PUZZLE_DB, SINGLETON_WALLET, coin)

        coin_spend = SINGLETON_WALLET.coin_spend_for_conditions(
            PUZZLE_DB,
            pool_member_spend_type="claim-p2-nft",
            pool_reward_amount=p2_singleton_coin_spend.coin.amount,
            pool_reward_height=now.height - 1,
        )
        spend_bundle = SpendBundle([coin_spend, p2_singleton_coin_spend],
                                   G2Element())
        spend_bundle.debug()

        additions, removals = coin_store.update_coin_store_for_spend_bundle(
            spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE)
        now.seconds += 500
        now.height += 1

        SINGLETON_WALLET.update_state(PUZZLE_DB, removals)

    assert len(list(coin_store.all_unspent_coins())) == 2

    #######
    # spend the singleton into the "leaving the pool" state

    coin_spend = SINGLETON_WALLET.coin_spend_for_conditions(
        PUZZLE_DB,
        pool_member_spend_type="to-waiting-room",
        key_value_list=Program.to([("foo", "bar")]))
    spend_bundle = SpendBundle([coin_spend], G2Element())

    additions, removals = coin_store.update_coin_store_for_spend_bundle(
        spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE)
    now.seconds += 500
    now.height += 1
    change_count = SINGLETON_WALLET.update_state(PUZZLE_DB, removals)
    assert change_count == 1

    assert len(list(coin_store.all_unspent_coins())) == 2

    #######
    # farm a `p2_singleton`

    pool_reward_puzzle_hash = p2_singleton_puzzle_hash_for_launcher(
        PUZZLE_DB, SINGLETON_WALLET.launcher_id,
        SINGLETON_WALLET.launcher_puzzle_hash, DELAY_SECONDS,
        DELAY_PUZZLE_HASH)
    farmed_coin = coin_store.farm_coin(pool_reward_puzzle_hash, now)
    now.seconds += 500
    now.height += 1

    p2_singleton_coins = filter_p2_singleton(PUZZLE_DB, SINGLETON_WALLET,
                                             [farmed_coin])
    assert p2_singleton_coins == [farmed_coin]

    assert len(list(coin_store.all_unspent_coins())) == 3

    #######
    # now collect the `p2_singleton` for the pool

    for coin in p2_singleton_coins:
        p2_singleton_coin_spend, singleton_conditions = claim_p2_singleton(
            PUZZLE_DB, SINGLETON_WALLET, coin)

        coin_spend = SINGLETON_WALLET.coin_spend_for_conditions(
            PUZZLE_DB,
            pool_leaving_spend_type="claim-p2-nft",
            pool_reward_amount=p2_singleton_coin_spend.coin.amount,
            pool_reward_height=now.height - 1,
        )
        spend_bundle = SpendBundle([coin_spend, p2_singleton_coin_spend],
                                   G2Element())

        additions, removals = coin_store.update_coin_store_for_spend_bundle(
            spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE)
        now.seconds += 500
        now.height += 1

        SINGLETON_WALLET.update_state(PUZZLE_DB, removals)

    assert len(list(coin_store.all_unspent_coins())) == 3

    #######
    # now finish leaving the pool

    initial_singleton_puzzle = adaptor_for_singleton_inner_puzzle(
        ANYONE_CAN_SPEND_PUZZLE)

    coin_spend = SINGLETON_WALLET.coin_spend_for_conditions(
        PUZZLE_DB,
        pool_leaving_spend_type="exit-waiting-room",
        key_value_list=[("foo1", "bar2"), ("foo2", "baz5")],
        destination_puzzle_hash=initial_singleton_puzzle.get_tree_hash(),
    )
    spend_bundle = SpendBundle([coin_spend], G2Element())

    full_puzzle = singleton_puzzle(SINGLETON_WALLET.launcher_id,
                                   SINGLETON_WALLET.launcher_puzzle_hash,
                                   initial_singleton_puzzle)

    PUZZLE_DB.add_puzzle(full_puzzle)

    try:
        additions, removals = coin_store.update_coin_store_for_spend_bundle(
            spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE)
        assert 0
    except BadSpendBundleError as ex:
        assert ex.args[
            0] == "condition validation failure Err.ASSERT_HEIGHT_RELATIVE_FAILED"

    now.seconds += 350000
    now.height += 1445

    additions, removals = coin_store.update_coin_store_for_spend_bundle(
        spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE)

    SINGLETON_WALLET.update_state(PUZZLE_DB, removals)

    assert len(list(coin_store.all_unspent_coins())) == 3

    #######
    # now spend to oblivion with the `-113` hack

    coin_spend = SINGLETON_WALLET.coin_spend_for_conditions(
        PUZZLE_DB, conditions=[[ConditionOpcode.CREATE_COIN, 0, -113]])
    spend_bundle = SpendBundle([coin_spend], G2Element())
    spend_bundle.debug()

    additions, removals = coin_store.update_coin_store_for_spend_bundle(
        spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE)
    update_count = SINGLETON_WALLET.update_state(PUZZLE_DB, removals)

    assert update_count == 0

    assert len(list(coin_store.all_unspent_coins())) == 2

    return 0
Beispiel #26
0
    async def test_singleton_top_layer(self):
        try:
            # START TESTS
            # Generate starting info
            key_lookup = KeyTool()
            pk: G1Element = public_key_for_index(1, key_lookup)
            starting_puzzle: Program = p2_delegated_puzzle_or_hidden_puzzle.puzzle_for_pk(
                pk)  # noqa
            adapted_puzzle: Program = singleton_top_layer.adapt_inner_to_singleton(
                starting_puzzle)  # noqa
            adapted_puzzle_hash: bytes32 = adapted_puzzle.get_tree_hash()

            # Get our starting standard coin created
            START_AMOUNT: uint64 = 1023
            sim = await SpendSim.create()
            sim_client = SimClient(sim)
            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,
            )

            await self.make_and_spend_bundle(
                sim,
                sim_client,
                starting_coin,
                delegated_puzzle,
                [starting_coinsol, launcher_coinsol],
            )

            # 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,
            )

            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],
            )

            # 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,
            )

            await self.make_and_spend_bundle(
                sim,
                sim_client,
                singleton,
                delegated_puzzle,
                [singleton_coinsol],
            )

            # 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()
            ARBITRARY_AMOUNT: uint64 = 1379
            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])

            # 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 = 1379
            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,
                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])

            # 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,
            )

            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",
            )

            # 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,
            )

            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",
            )

            # ATTEMPT TO CREATE AN EVEN SINGLETON (Negative test)
            await sim.rewind(save_height)

            delegated_puzzle: Program = Program.to((
                1,
                [
                    [
                        ConditionOpcode.CREATE_COIN,
                        singleton_child.puzzle_hash,
                        2,
                    ],
                    [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,
            )

            await self.make_and_spend_bundle(
                sim,
                sim_client,
                singleton_child,
                delegated_puzzle,
                [singleton_even_coinsol],
            )

            # Now try a perfectly innocent spend
            evil_coin: Coin = (await sim.all_non_reward_coins())[0]
            delegated_puzzle: Program = Program.to((
                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,
            )

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

            melt_coinsol = CoinSpend(
                singleton_child,
                puzzle_reveal,
                full_solution,
            )

            await self.make_and_spend_bundle(
                sim,
                sim_client,
                singleton_child,
                delegated_puzzle,
                [melt_coinsol],
            )

            melted_coin: Coin = (await sim.all_non_reward_coins())[0]
            assert melted_coin.puzzle_hash == adapted_puzzle_hash
        finally:
            await sim.close()
Beispiel #27
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
Beispiel #28
0
    def test_pool_lifecycle(self):
        # START TESTS
        # Generate starting info
        key_lookup = KeyTool()
        sk: PrivateKey = PrivateKey.from_bytes(
            secret_exponent_for_index(1).to_bytes(32, "big"), )
        pk: G1Element = G1Element.from_bytes(
            public_key_for_index(1, key_lookup))
        starting_puzzle: Program = puzzle_for_pk(pk)
        starting_ph: bytes32 = starting_puzzle.get_tree_hash()

        # Get our starting standard coin created
        START_AMOUNT: uint64 = 1023
        coin_db = CoinStore()
        time = CoinTimestamp(10000000, 1)
        coin_db.farm_coin(starting_ph, time, START_AMOUNT)
        starting_coin: Coin = next(coin_db.all_unspent_coins())

        # LAUNCHING
        # Create the escaping inner puzzle
        GENESIS_CHALLENGE = bytes32.fromhex(
            "ccd5bb71183532bff220ba46c268991a3ff07eb358e8255a65c30a2dce0e5fbb")
        launcher_coin = singleton_top_layer.generate_launcher_coin(
            starting_coin,
            START_AMOUNT,
        )
        DELAY_TIME = uint64(60800)
        DELAY_PH = starting_ph
        launcher_id = launcher_coin.name()
        relative_lock_height: uint32 = uint32(5000)
        # use a dummy pool state
        pool_state = PoolState(
            owner_pubkey=pk,
            pool_url="",
            relative_lock_height=relative_lock_height,
            state=3,  # farming to pool
            target_puzzle_hash=starting_ph,
            version=1,
        )
        # create a new dummy pool state for travelling
        target_pool_state = PoolState(
            owner_pubkey=pk,
            pool_url="",
            relative_lock_height=relative_lock_height,
            state=2,  # Leaving pool
            target_puzzle_hash=starting_ph,
            version=1,
        )
        # Standard format comment
        comment = Program.to([("p", bytes(pool_state)), ("t", DELAY_TIME),
                              ("h", DELAY_PH)])
        pool_wr_innerpuz: bytes32 = create_waiting_room_inner_puzzle(
            starting_ph,
            relative_lock_height,
            pk,
            launcher_id,
            GENESIS_CHALLENGE,
            DELAY_TIME,
            DELAY_PH,
        )
        pool_wr_inner_hash = pool_wr_innerpuz.get_tree_hash()
        pooling_innerpuz: Program = create_pooling_inner_puzzle(
            starting_ph,
            pool_wr_inner_hash,
            pk,
            launcher_id,
            GENESIS_CHALLENGE,
            DELAY_TIME,
            DELAY_PH,
        )
        # Driver tests
        assert is_pool_singleton_inner_puzzle(pooling_innerpuz)
        assert is_pool_singleton_inner_puzzle(pool_wr_innerpuz)
        assert get_pubkey_from_member_inner_puzzle(pooling_innerpuz) == pk
        # Generating launcher information
        conditions, launcher_coinsol = singleton_top_layer.launch_conditions_and_coinsol(
            starting_coin, pooling_innerpuz, comment, START_AMOUNT)
        # Creating solution for standard transaction
        delegated_puzzle: Program = puzzle_for_conditions(conditions)
        full_solution: Program = solution_for_conditions(conditions)
        starting_coinsol = CoinSolution(
            starting_coin,
            starting_puzzle,
            full_solution,
        )
        # Create the spend bundle
        sig: G2Element = sign_delegated_puz(delegated_puzzle, starting_coin)
        spend_bundle = SpendBundle(
            [starting_coinsol, launcher_coinsol],
            sig,
        )
        # Spend it!
        coin_db.update_coin_store_for_spend_bundle(
            spend_bundle,
            time,
            DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM,
        )
        # Test that we can retrieve the extra data
        assert get_delayed_puz_info_from_launcher_spend(launcher_coinsol) == (
            DELAY_TIME, DELAY_PH)
        assert solution_to_extra_data(launcher_coinsol) == pool_state

        # TEST TRAVEL AFTER LAUNCH
        # fork the state
        fork_coin_db: CoinStore = copy.deepcopy(coin_db)
        post_launch_coinsol, _ = create_travel_spend(
            launcher_coinsol,
            launcher_coin,
            pool_state,
            target_pool_state,
            GENESIS_CHALLENGE,
            DELAY_TIME,
            DELAY_PH,
        )
        # Spend it!
        fork_coin_db.update_coin_store_for_spend_bundle(
            SpendBundle([post_launch_coinsol], G2Element()),
            time,
            DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM,
        )

        # HONEST ABSORB
        time = CoinTimestamp(10000030, 2)
        # create the farming reward
        p2_singleton_puz: Program = create_p2_singleton_puzzle(
            SINGLETON_MOD_HASH,
            launcher_id,
            DELAY_TIME,
            DELAY_PH,
        )
        p2_singleton_ph: bytes32 = p2_singleton_puz.get_tree_hash()
        assert uncurry_pool_waitingroom_inner_puzzle(pool_wr_innerpuz) == (
            starting_ph,
            relative_lock_height,
            pk,
            p2_singleton_ph,
        )
        assert launcher_id_to_p2_puzzle_hash(launcher_id, DELAY_TIME,
                                             DELAY_PH) == p2_singleton_ph
        assert get_seconds_and_delayed_puzhash_from_p2_singleton_puzzle(
            p2_singleton_puz) == (DELAY_TIME, DELAY_PH)
        coin_db.farm_coin(p2_singleton_ph, time, 1750000000000)
        coin_sols: List[CoinSolution] = create_absorb_spend(
            launcher_coinsol,
            pool_state,
            launcher_coin,
            2,
            GENESIS_CHALLENGE,
            DELAY_TIME,
            DELAY_PH,  # height
        )
        # Spend it!
        coin_db.update_coin_store_for_spend_bundle(
            SpendBundle(coin_sols, G2Element()),
            time,
            DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM,
        )

        # ABSORB A NON EXISTENT REWARD (Negative test)
        last_coinsol: CoinSolution = list(
            filter(
                lambda e: e.coin.amount == START_AMOUNT,
                coin_sols,
            ))[0]
        coin_sols: List[CoinSolution] = create_absorb_spend(
            last_coinsol,
            pool_state,
            launcher_coin,
            2,
            GENESIS_CHALLENGE,
            DELAY_TIME,
            DELAY_PH,  # height
        )
        # filter for only the singleton solution
        singleton_coinsol: CoinSolution = list(
            filter(
                lambda e: e.coin.amount == START_AMOUNT,
                coin_sols,
            ))[0]
        # Spend it and hope it fails!
        try:
            coin_db.update_coin_store_for_spend_bundle(
                SpendBundle([singleton_coinsol], G2Element()),
                time,
                DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM,
            )
        except BadSpendBundleError as e:
            assert str(
                e
            ) == "condition validation failure Err.ASSERT_ANNOUNCE_CONSUMED_FAILED"

        # SPEND A NON-REWARD P2_SINGLETON (Negative test)
        # create the dummy coin
        non_reward_p2_singleton = Coin(
            bytes32(32 * b"3"),
            p2_singleton_ph,
            uint64(1337),
        )
        coin_db._add_coin_entry(non_reward_p2_singleton, time)
        # construct coin solution for the p2_singleton coin
        bad_coinsol = CoinSolution(
            non_reward_p2_singleton,
            p2_singleton_puz,
            Program.to([
                pooling_innerpuz.get_tree_hash(),
                non_reward_p2_singleton.name(),
            ]),
        )
        # Spend it and hope it fails!
        try:
            coin_db.update_coin_store_for_spend_bundle(
                SpendBundle([singleton_coinsol, bad_coinsol], G2Element()),
                time,
                DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM,
            )
        except BadSpendBundleError as e:
            assert str(
                e
            ) == "condition validation failure Err.ASSERT_ANNOUNCE_CONSUMED_FAILED"

        # ENTER WAITING ROOM
        # find the singleton
        singleton = get_most_recent_singleton_coin_from_coin_solution(
            last_coinsol)
        # get the relevant coin solution
        travel_coinsol, _ = create_travel_spend(
            last_coinsol,
            launcher_coin,
            pool_state,
            target_pool_state,
            GENESIS_CHALLENGE,
            DELAY_TIME,
            DELAY_PH,
        )
        # Test that we can retrieve the extra data
        assert solution_to_extra_data(travel_coinsol) == target_pool_state
        # sign the serialized state
        data = Program.to(bytes(target_pool_state)).get_tree_hash()
        sig: G2Element = AugSchemeMPL.sign(
            sk,
            (data + singleton.name() +
             DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA),
        )
        # Spend it!
        coin_db.update_coin_store_for_spend_bundle(
            SpendBundle([travel_coinsol], sig),
            time,
            DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM,
        )

        # ESCAPE TOO FAST (Negative test)
        # find the singleton
        singleton = get_most_recent_singleton_coin_from_coin_solution(
            travel_coinsol)
        # get the relevant coin solution
        return_coinsol, _ = create_travel_spend(
            travel_coinsol,
            launcher_coin,
            target_pool_state,
            pool_state,
            GENESIS_CHALLENGE,
            DELAY_TIME,
            DELAY_PH,
        )
        # sign the serialized target state
        sig = AugSchemeMPL.sign(
            sk,
            (data + singleton.name() +
             DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA),
        )
        # Spend it and hope it fails!
        try:
            coin_db.update_coin_store_for_spend_bundle(
                SpendBundle([return_coinsol], sig),
                time,
                DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM,
            )
        except BadSpendBundleError as e:
            assert str(
                e
            ) == "condition validation failure Err.ASSERT_HEIGHT_RELATIVE_FAILED"

        # ABSORB WHILE IN WAITING ROOM
        time = CoinTimestamp(10000060, 3)
        # create the farming reward
        coin_db.farm_coin(p2_singleton_ph, time, 1750000000000)
        # generate relevant coin solutions
        coin_sols: List[CoinSolution] = create_absorb_spend(
            travel_coinsol,
            target_pool_state,
            launcher_coin,
            3,
            GENESIS_CHALLENGE,
            DELAY_TIME,
            DELAY_PH,  # height
        )
        # Spend it!
        coin_db.update_coin_store_for_spend_bundle(
            SpendBundle(coin_sols, G2Element()),
            time,
            DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM,
        )

        # LEAVE THE WAITING ROOM
        time = CoinTimestamp(20000000, 10000)
        # find the singleton
        singleton_coinsol: CoinSolution = list(
            filter(
                lambda e: e.coin.amount == START_AMOUNT,
                coin_sols,
            ))[0]
        singleton: Coin = get_most_recent_singleton_coin_from_coin_solution(
            singleton_coinsol)
        # get the relevant coin solution
        return_coinsol, _ = create_travel_spend(
            singleton_coinsol,
            launcher_coin,
            target_pool_state,
            pool_state,
            GENESIS_CHALLENGE,
            DELAY_TIME,
            DELAY_PH,
        )
        # Test that we can retrieve the extra data
        assert solution_to_extra_data(return_coinsol) == pool_state
        # sign the serialized target state
        data = Program.to([
            pooling_innerpuz.get_tree_hash(), START_AMOUNT,
            bytes(pool_state)
        ]).get_tree_hash()
        sig: G2Element = AugSchemeMPL.sign(
            sk,
            (data + singleton.name() +
             DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA),
        )
        # Spend it!
        coin_db.update_coin_store_for_spend_bundle(
            SpendBundle([return_coinsol], sig),
            time,
            DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM,
        )

        # ABSORB ONCE MORE FOR GOOD MEASURE
        time = CoinTimestamp(20000000, 10005)
        # create the farming  reward
        coin_db.farm_coin(p2_singleton_ph, time, 1750000000000)
        coin_sols: List[CoinSolution] = create_absorb_spend(
            return_coinsol,
            pool_state,
            launcher_coin,
            10005,
            GENESIS_CHALLENGE,
            DELAY_TIME,
            DELAY_PH,  # height
        )
        # Spend it!
        coin_db.update_coin_store_for_spend_bundle(
            SpendBundle(coin_sols, G2Element()),
            time,
            DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM,
        )
def create_unfinished_block(
    constants: ConsensusConstants,
    sub_slot_start_total_iters: uint128,
    sub_slot_iters: uint64,
    signage_point_index: uint8,
    sp_iters: uint64,
    ip_iters: uint64,
    proof_of_space: ProofOfSpace,
    slot_cc_challenge: bytes32,
    farmer_reward_puzzle_hash: bytes32,
    pool_target: PoolTarget,
    get_plot_signature: Callable[[bytes32, G1Element], G2Element],
    get_pool_signature: Callable[[PoolTarget, Optional[G1Element]], Optional[G2Element]],
    signage_point: SignagePoint,
    timestamp: uint64,
    blocks: BlockchainInterface,
    seed: bytes32 = b"",
    block_generator: Optional[BlockGenerator] = None,
    aggregate_sig: G2Element = G2Element(),
    additions: Optional[List[Coin]] = None,
    removals: Optional[List[Coin]] = None,
    prev_block: Optional[BlockRecord] = None,
    finished_sub_slots_input: List[EndOfSubSlotBundle] = None,
) -> UnfinishedBlock:
    """
    Creates a new unfinished block using all the information available at the signage point. This will have to be
    modified using information from the infusion point.

    Args:
        constants: consensus constants being used for this chain
        sub_slot_start_total_iters: the starting sub-slot iters at the signage point sub-slot
        sub_slot_iters: sub-slot-iters at the infusion point epoch
        signage_point_index: signage point index of the block to create
        sp_iters: sp_iters of the block to create
        ip_iters: ip_iters of the block to create
        proof_of_space: proof of space of the block to create
        slot_cc_challenge: challenge hash at the sp sub-slot
        farmer_reward_puzzle_hash: where to pay out farmer rewards
        pool_target: where to pay out pool rewards
        get_plot_signature: function that returns signature corresponding to plot public key
        get_pool_signature: function that returns signature corresponding to pool public key
        signage_point: signage point information (VDFs)
        timestamp: timestamp to add to the foliage block, if created
        seed: seed to randomize chain
        block_generator: transactions to add to the foliage block, if created
        aggregate_sig: aggregate of all transctions (or infinity element)
        additions: Coins added in spend_bundle
        removals: Coins removed in spend_bundle
        prev_block: previous block (already in chain) from the signage point
        blocks: dictionary from header hash to SBR of all included SBR
        finished_sub_slots_input: finished_sub_slots at the signage point

    Returns:

    """
    if finished_sub_slots_input is None:
        finished_sub_slots: List[EndOfSubSlotBundle] = []
    else:
        finished_sub_slots = finished_sub_slots_input.copy()
    overflow: bool = sp_iters > ip_iters
    total_iters_sp: uint128 = uint128(sub_slot_start_total_iters + sp_iters)
    is_genesis: bool = prev_block is None

    new_sub_slot: bool = len(finished_sub_slots) > 0

    cc_sp_hash: Optional[bytes32] = slot_cc_challenge

    # Only enters this if statement if we are in testing mode (making VDF proofs here)
    if signage_point.cc_vdf is not None:
        assert signage_point.rc_vdf is not None
        cc_sp_hash = signage_point.cc_vdf.output.get_hash()
        rc_sp_hash = signage_point.rc_vdf.output.get_hash()
    else:
        if new_sub_slot:
            rc_sp_hash = finished_sub_slots[-1].reward_chain.get_hash()
        else:
            if is_genesis:
                rc_sp_hash = constants.GENESIS_CHALLENGE
            else:
                assert prev_block is not None
                assert blocks is not None
                curr = prev_block
                while not curr.first_in_sub_slot:
                    curr = blocks.block_record(curr.prev_hash)
                assert curr.finished_reward_slot_hashes is not None
                rc_sp_hash = curr.finished_reward_slot_hashes[-1]
        signage_point = SignagePoint(None, None, None, None)

    cc_sp_signature: Optional[G2Element] = get_plot_signature(cc_sp_hash, proof_of_space.plot_public_key)
    rc_sp_signature: Optional[G2Element] = get_plot_signature(rc_sp_hash, proof_of_space.plot_public_key)
    assert cc_sp_signature is not None
    assert rc_sp_signature is not None
    assert blspy.AugSchemeMPL.verify(proof_of_space.plot_public_key, cc_sp_hash, cc_sp_signature)

    total_iters = uint128(sub_slot_start_total_iters + ip_iters + (sub_slot_iters if overflow else 0))

    rc_block = RewardChainBlockUnfinished(
        total_iters,
        signage_point_index,
        slot_cc_challenge,
        proof_of_space,
        signage_point.cc_vdf,
        cc_sp_signature,
        signage_point.rc_vdf,
        rc_sp_signature,
    )
    if additions is None:
        additions = []
    if removals is None:
        removals = []
    (foliage, foliage_transaction_block, transactions_info,) = create_foliage(
        constants,
        rc_block,
        block_generator,
        aggregate_sig,
        additions,
        removals,
        prev_block,
        blocks,
        total_iters_sp,
        timestamp,
        farmer_reward_puzzle_hash,
        pool_target,
        get_plot_signature,
        get_pool_signature,
        seed,
    )
    return UnfinishedBlock(
        finished_sub_slots,
        rc_block,
        signage_point.cc_proof,
        signage_point.rc_proof,
        foliage,
        foliage_transaction_block,
        transactions_info,
        block_generator.program if block_generator else None,
        block_generator.block_height_list() if block_generator else [],
    )
Beispiel #30
0
    async def test_wallet_rpc(self, two_wallet_nodes, trusted):
        test_rpc_port = uint16(21529)
        test_rpc_port_2 = uint16(21536)
        test_rpc_port_node = uint16(21530)
        num_blocks = 5
        full_nodes, wallets = two_wallet_nodes
        full_node_api = full_nodes[0]
        full_node_server = full_node_api.full_node.server
        wallet_node, server_2 = wallets[0]
        wallet_node_2, server_3 = wallets[1]
        wallet = wallet_node.wallet_state_manager.main_wallet
        wallet_2 = wallet_node_2.wallet_state_manager.main_wallet
        ph = await wallet.get_new_puzzlehash()
        ph_2 = await wallet_2.get_new_puzzlehash()

        await server_2.start_client(PeerInfo("localhost", uint16(full_node_server._port)), None)
        await server_3.start_client(PeerInfo("localhost", uint16(full_node_server._port)), None)

        if trusted:
            wallet_node.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
            wallet_node_2.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
        else:
            wallet_node.config["trusted_peers"] = {}
            wallet_node_2.config["trusted_peers"] = {}

        for i in range(0, num_blocks):
            await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))

        initial_funds = sum(
            [calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks)]
        )
        initial_funds_eventually = sum(
            [
                calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i))
                for i in range(1, num_blocks + 1)
            ]
        )

        wallet_rpc_api = WalletRpcApi(wallet_node)
        wallet_rpc_api_2 = WalletRpcApi(wallet_node_2)

        config = bt.config
        hostname = config["self_hostname"]
        daemon_port = config["daemon_port"]

        def stop_node_cb():
            pass

        full_node_rpc_api = FullNodeRpcApi(full_node_api.full_node)

        rpc_cleanup_node = await start_rpc_server(
            full_node_rpc_api,
            hostname,
            daemon_port,
            test_rpc_port_node,
            stop_node_cb,
            bt.root_path,
            config,
            connect_to_daemon=False,
        )
        rpc_cleanup = await start_rpc_server(
            wallet_rpc_api,
            hostname,
            daemon_port,
            test_rpc_port,
            stop_node_cb,
            bt.root_path,
            config,
            connect_to_daemon=False,
        )
        rpc_cleanup_2 = await start_rpc_server(
            wallet_rpc_api_2,
            hostname,
            daemon_port,
            test_rpc_port_2,
            stop_node_cb,
            bt.root_path,
            config,
            connect_to_daemon=False,
        )

        await time_out_assert(5, wallet.get_confirmed_balance, initial_funds)
        await time_out_assert(5, wallet.get_unconfirmed_balance, initial_funds)

        client = await WalletRpcClient.create(self_hostname, test_rpc_port, bt.root_path, config)
        client_2 = await WalletRpcClient.create(self_hostname, test_rpc_port_2, bt.root_path, config)
        client_node = await FullNodeRpcClient.create(self_hostname, test_rpc_port_node, bt.root_path, config)
        try:
            await time_out_assert(5, client.get_synced)
            addr = encode_puzzle_hash(await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash(), "xch")
            tx_amount = 15600000
            try:
                await client.send_transaction("1", 100000000000000001, addr)
                raise Exception("Should not create high value tx")
            except ValueError:
                pass

            # Tests sending a basic transaction
            tx = await client.send_transaction("1", tx_amount, addr, memos=["this is a basic tx"])
            transaction_id = tx.name

            async def tx_in_mempool():
                tx = await client.get_transaction("1", transaction_id)
                return tx.is_in_mempool()

            await time_out_assert(5, tx_in_mempool, True)
            await time_out_assert(5, wallet.get_unconfirmed_balance, initial_funds - tx_amount)
            assert (await client.get_wallet_balance("1"))["unconfirmed_wallet_balance"] == initial_funds - tx_amount
            assert (await client.get_wallet_balance("1"))["confirmed_wallet_balance"] == initial_funds

            for i in range(0, 5):
                await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_2))

            async def eventual_balance():
                return (await client.get_wallet_balance("1"))["confirmed_wallet_balance"]

            async def eventual_balance_det(c, wallet_id: str):
                return (await c.get_wallet_balance(wallet_id))["confirmed_wallet_balance"]

            # Checks that the memo can be retrieved
            tx_confirmed = await client.get_transaction("1", transaction_id)
            assert tx_confirmed.confirmed
            assert len(tx_confirmed.get_memos()) == 1
            assert [b"this is a basic tx"] in tx_confirmed.get_memos().values()
            assert list(tx_confirmed.get_memos().keys())[0] in [a.name() for a in tx.spend_bundle.additions()]

            await time_out_assert(5, eventual_balance, initial_funds_eventually - tx_amount)

            # Tests offline signing
            ph_3 = await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash()
            ph_4 = await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash()
            ph_5 = await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash()

            # Test basic transaction to one output and coin announcement
            signed_tx_amount = 888000
            tx_coin_announcements = [
                Announcement(
                    std_hash(b"coin_id_1"),
                    std_hash(b"message"),
                    b"\xca",
                ),
                Announcement(
                    std_hash(b"coin_id_2"),
                    bytes(Program.to("a string")),
                ),
            ]
            tx_res: TransactionRecord = await client.create_signed_transaction(
                [{"amount": signed_tx_amount, "puzzle_hash": ph_3}], coin_announcements=tx_coin_announcements
            )

            assert tx_res.fee_amount == 0
            assert tx_res.amount == signed_tx_amount
            assert len(tx_res.additions) == 2  # The output and the change
            assert any([addition.amount == signed_tx_amount for addition in tx_res.additions])
            # check error for a ASSERT_ANNOUNCE_CONSUMED_FAILED and if the error is not there throw a value error
            try:
                push_res = await client_node.push_tx(tx_res.spend_bundle)
            except ValueError as error:
                error_string = error.args[0]["error"]  # noqa:  # pylint: disable=E1126
                if error_string.find("ASSERT_ANNOUNCE_CONSUMED_FAILED") == -1:
                    raise ValueError from error

            # # Test basic transaction to one output and puzzle announcement
            signed_tx_amount = 888000
            tx_puzzle_announcements = [
                Announcement(
                    std_hash(b"puzzle_hash_1"),
                    b"message",
                    b"\xca",
                ),
                Announcement(
                    std_hash(b"puzzle_hash_2"),
                    bytes(Program.to("a string")),
                ),
            ]
            tx_res: TransactionRecord = await client.create_signed_transaction(
                [{"amount": signed_tx_amount, "puzzle_hash": ph_3}], puzzle_announcements=tx_puzzle_announcements
            )

            assert tx_res.fee_amount == 0
            assert tx_res.amount == signed_tx_amount
            assert len(tx_res.additions) == 2  # The output and the change
            assert any([addition.amount == signed_tx_amount for addition in tx_res.additions])
            # check error for a ASSERT_ANNOUNCE_CONSUMED_FAILED and if the error is not there throw a value error
            try:
                push_res = await client_node.push_tx(tx_res.spend_bundle)
            except ValueError as error:
                error_string = error.args[0]["error"]  # noqa:  # pylint: disable=E1126
                if error_string.find("ASSERT_ANNOUNCE_CONSUMED_FAILED") == -1:
                    raise ValueError from error

            # Test basic transaction to one output
            signed_tx_amount = 888000
            tx_res: TransactionRecord = await client.create_signed_transaction(
                [{"amount": signed_tx_amount, "puzzle_hash": ph_3, "memos": ["My memo"]}]
            )

            assert tx_res.fee_amount == 0
            assert tx_res.amount == signed_tx_amount
            assert len(tx_res.additions) == 2  # The output and the change
            assert any([addition.amount == signed_tx_amount for addition in tx_res.additions])

            push_res = await client.push_tx(tx_res.spend_bundle)
            assert push_res["success"]
            assert (await client.get_wallet_balance("1"))[
                "confirmed_wallet_balance"
            ] == initial_funds_eventually - tx_amount

            for i in range(0, 5):
                await client.farm_block(encode_puzzle_hash(ph_2, "xch"))
                await asyncio.sleep(0.5)

            await time_out_assert(5, eventual_balance, initial_funds_eventually - tx_amount - signed_tx_amount)

            # Test transaction to two outputs, from a specified coin, with a fee
            coin_to_spend = None
            for addition in tx_res.additions:
                if addition.amount != signed_tx_amount:
                    coin_to_spend = addition
            assert coin_to_spend is not None

            tx_res = await client.create_signed_transaction(
                [{"amount": 444, "puzzle_hash": ph_4, "memos": ["hhh"]}, {"amount": 999, "puzzle_hash": ph_5}],
                coins=[coin_to_spend],
                fee=100,
            )
            assert tx_res.fee_amount == 100
            assert tx_res.amount == 444 + 999
            assert len(tx_res.additions) == 3  # The outputs and the change
            assert any([addition.amount == 444 for addition in tx_res.additions])
            assert any([addition.amount == 999 for addition in tx_res.additions])
            assert sum([rem.amount for rem in tx_res.removals]) - sum([ad.amount for ad in tx_res.additions]) == 100

            push_res = await client_node.push_tx(tx_res.spend_bundle)
            assert push_res["success"]
            for i in range(0, 5):
                await client.farm_block(encode_puzzle_hash(ph_2, "xch"))
                await asyncio.sleep(0.5)

            found: bool = False
            for addition in tx_res.spend_bundle.additions():
                if addition.amount == 444:
                    cr: Optional[CoinRecord] = await client_node.get_coin_record_by_name(addition.name())
                    assert cr is not None
                    spend: CoinSpend = await client_node.get_puzzle_and_solution(
                        addition.parent_coin_info, cr.confirmed_block_index
                    )
                    sb: SpendBundle = SpendBundle([spend], G2Element())
                    assert compute_memos(sb) == {addition.name(): [b"hhh"]}
                    found = True
            assert found

            new_balance = initial_funds_eventually - tx_amount - signed_tx_amount - 444 - 999 - 100
            await time_out_assert(5, eventual_balance, new_balance)

            send_tx_res: TransactionRecord = await client.send_transaction_multi(
                "1",
                [
                    {"amount": 555, "puzzle_hash": ph_4, "memos": ["FiMemo"]},
                    {"amount": 666, "puzzle_hash": ph_5, "memos": ["SeMemo"]},
                ],
                fee=200,
            )
            assert send_tx_res is not None
            assert send_tx_res.fee_amount == 200
            assert send_tx_res.amount == 555 + 666
            assert len(send_tx_res.additions) == 3  # The outputs and the change
            assert any([addition.amount == 555 for addition in send_tx_res.additions])
            assert any([addition.amount == 666 for addition in send_tx_res.additions])
            assert (
                sum([rem.amount for rem in send_tx_res.removals]) - sum([ad.amount for ad in send_tx_res.additions])
                == 200
            )

            await asyncio.sleep(3)
            for i in range(0, 5):
                await client.farm_block(encode_puzzle_hash(ph_2, "xch"))
                await asyncio.sleep(0.5)

            new_balance = new_balance - 555 - 666 - 200
            await time_out_assert(5, eventual_balance, new_balance)

            address = await client.get_next_address("1", True)
            assert len(address) > 10

            transactions = await client.get_transactions("1")
            assert len(transactions) > 1

            all_transactions = await client.get_transactions("1")
            # Test transaction pagination
            some_transactions = await client.get_transactions("1", 0, 5)
            some_transactions_2 = await client.get_transactions("1", 5, 10)
            assert some_transactions == all_transactions[0:5]
            assert some_transactions_2 == all_transactions[5:10]

            # Testing sorts
            # Test the default sort (CONFIRMED_AT_HEIGHT)
            assert all_transactions == sorted(all_transactions, key=attrgetter("confirmed_at_height"))
            all_transactions = await client.get_transactions("1", reverse=True)
            assert all_transactions == sorted(all_transactions, key=attrgetter("confirmed_at_height"), reverse=True)

            # Test RELEVANCE
            await client.send_transaction("1", 1, encode_puzzle_hash(ph_2, "xch"))  # Create a pending tx

            all_transactions = await client.get_transactions("1", sort_key=SortKey.RELEVANCE)
            sorted_transactions = sorted(all_transactions, key=attrgetter("created_at_time"), reverse=True)
            sorted_transactions = sorted(sorted_transactions, key=attrgetter("confirmed_at_height"), reverse=True)
            sorted_transactions = sorted(sorted_transactions, key=attrgetter("confirmed"))
            assert all_transactions == sorted_transactions

            all_transactions = await client.get_transactions("1", sort_key=SortKey.RELEVANCE, reverse=True)
            sorted_transactions = sorted(all_transactions, key=attrgetter("created_at_time"))
            sorted_transactions = sorted(sorted_transactions, key=attrgetter("confirmed_at_height"))
            sorted_transactions = sorted(sorted_transactions, key=attrgetter("confirmed"), reverse=True)
            assert all_transactions == sorted_transactions

            # Checks that the memo can be retrieved
            tx_confirmed = await client.get_transaction("1", send_tx_res.name)
            assert tx_confirmed.confirmed
            if isinstance(tx_confirmed, SpendBundle):
                memos = compute_memos(tx_confirmed)
            else:
                memos = tx_confirmed.get_memos()
            assert len(memos) == 2
            print(memos)
            assert [b"FiMemo"] in memos.values()
            assert [b"SeMemo"] in memos.values()
            assert list(memos.keys())[0] in [a.name() for a in send_tx_res.spend_bundle.additions()]
            assert list(memos.keys())[1] in [a.name() for a in send_tx_res.spend_bundle.additions()]

            ##############
            # CATS       #
            ##############

            # Creates a wallet and a CAT with 20 mojos
            res = await client.create_new_cat_and_wallet(20)
            assert res["success"]
            cat_0_id = res["wallet_id"]
            asset_id = bytes.fromhex(res["asset_id"])
            assert len(asset_id) > 0

            bal_0 = await client.get_wallet_balance(cat_0_id)
            assert bal_0["confirmed_wallet_balance"] == 0
            assert bal_0["pending_coin_removal_count"] == 1
            col = await client.get_cat_asset_id(cat_0_id)
            assert col == asset_id
            assert (await client.get_cat_name(cat_0_id)) == "CAT Wallet"
            await client.set_cat_name(cat_0_id, "My cat")
            assert (await client.get_cat_name(cat_0_id)) == "My cat"
            wid, name = await client.cat_asset_id_to_name(col)
            assert wid == cat_0_id
            assert name == "My cat"
            should_be_none = await client.cat_asset_id_to_name(bytes([0] * 32))
            assert should_be_none is None
            verified_asset_id = next(iter(DEFAULT_CATS.items()))[1]["asset_id"]
            should_be_none, name = await client.cat_asset_id_to_name(bytes.fromhex(verified_asset_id))
            assert should_be_none is None
            assert name == next(iter(DEFAULT_CATS.items()))[1]["name"]

            await asyncio.sleep(1)
            for i in range(0, 5):
                await client.farm_block(encode_puzzle_hash(ph_2, "xch"))
                await asyncio.sleep(0.5)

            await time_out_assert(10, eventual_balance_det, 20, client, cat_0_id)
            bal_0 = await client.get_wallet_balance(cat_0_id)
            assert bal_0["pending_coin_removal_count"] == 0
            assert bal_0["unspent_coin_count"] == 1

            # Creates a second wallet with the same CAT
            res = await client_2.create_wallet_for_existing_cat(asset_id)
            assert res["success"]
            cat_1_id = res["wallet_id"]
            colour_1 = bytes.fromhex(res["asset_id"])
            assert colour_1 == asset_id

            await asyncio.sleep(1)
            for i in range(0, 5):
                await client.farm_block(encode_puzzle_hash(ph_2, "xch"))
                await asyncio.sleep(0.5)
            bal_1 = await client_2.get_wallet_balance(cat_1_id)
            assert bal_1["confirmed_wallet_balance"] == 0

            addr_0 = await client.get_next_address(cat_0_id, False)
            addr_1 = await client_2.get_next_address(cat_1_id, False)

            assert addr_0 != addr_1

            await client.cat_spend(cat_0_id, 4, addr_1, 0, ["the cat memo"])

            await asyncio.sleep(1)
            for i in range(0, 5):
                await client.farm_block(encode_puzzle_hash(ph_2, "xch"))
                await asyncio.sleep(0.5)

            await time_out_assert(10, eventual_balance_det, 16, client, cat_0_id)
            await time_out_assert(10, eventual_balance_det, 4, client_2, cat_1_id)

            ##########
            # Offers #
            ##########

            # Create an offer of 5 chia for one CAT
            offer, trade_record = await client.create_offer_for_ids({uint32(1): -5, cat_0_id: 1}, validate_only=True)
            all_offers = await client.get_all_offers()
            assert len(all_offers) == 0
            assert offer is None

            offer, trade_record = await client.create_offer_for_ids({uint32(1): -5, cat_0_id: 1}, fee=uint64(1))

            summary = await client.get_offer_summary(offer)
            assert summary == {"offered": {"xch": 5}, "requested": {col.hex(): 1}}

            assert await client.check_offer_validity(offer)

            all_offers = await client.get_all_offers(file_contents=True)
            assert len(all_offers) == 1
            assert TradeStatus(all_offers[0].status) == TradeStatus.PENDING_ACCEPT
            assert all_offers[0].offer == bytes(offer)

            trade_record = await client_2.take_offer(offer, fee=uint64(1))
            assert TradeStatus(trade_record.status) == TradeStatus.PENDING_CONFIRM

            await client.cancel_offer(offer.name(), secure=False)

            trade_record = await client.get_offer(offer.name(), file_contents=True)
            assert trade_record.offer == bytes(offer)
            assert TradeStatus(trade_record.status) == TradeStatus.CANCELLED

            await client.cancel_offer(offer.name(), fee=uint64(1), secure=True)

            trade_record = await client.get_offer(offer.name())
            assert TradeStatus(trade_record.status) == TradeStatus.PENDING_CANCEL

            new_offer, new_trade_record = await client.create_offer_for_ids({uint32(1): -5, cat_0_id: 1}, fee=uint64(1))
            all_offers = await client.get_all_offers()
            assert len(all_offers) == 2

            await asyncio.sleep(1)
            for i in range(0, 5):
                await client.farm_block(encode_puzzle_hash(ph_2, "xch"))
                await asyncio.sleep(0.5)

            async def is_trade_confirmed(client, trade) -> bool:
                trade_record = await client.get_offer(trade.name())
                return TradeStatus(trade_record.status) == TradeStatus.CONFIRMED

            time_out_assert(15, is_trade_confirmed, True, client, offer)

            # Test trade sorting
            def only_ids(trades):
                return [t.trade_id for t in trades]

            trade_record = await client.get_offer(offer.name())
            all_offers = await client.get_all_offers(include_completed=True)  # confirmed at index descending
            assert len(all_offers) == 2
            assert only_ids(all_offers) == only_ids([trade_record, new_trade_record])
            all_offers = await client.get_all_offers(
                include_completed=True, reverse=True
            )  # confirmed at index ascending
            assert only_ids(all_offers) == only_ids([new_trade_record, trade_record])
            all_offers = await client.get_all_offers(include_completed=True, sort_key="RELEVANCE")  # most relevant
            assert only_ids(all_offers) == only_ids([new_trade_record, trade_record])
            all_offers = await client.get_all_offers(
                include_completed=True, sort_key="RELEVANCE", reverse=True
            )  # least relevant
            assert only_ids(all_offers) == only_ids([trade_record, new_trade_record])
            # Test pagination
            all_offers = await client.get_all_offers(include_completed=True, start=0, end=1)
            assert len(all_offers) == 1
            all_offers = await client.get_all_offers(include_completed=True, start=50)
            assert len(all_offers) == 0
            all_offers = await client.get_all_offers(include_completed=True, start=0, end=50)
            assert len(all_offers) == 2

            # Keys and addresses

            address = await client.get_next_address("1", True)
            assert len(address) > 10

            all_transactions = await client.get_transactions("1")

            some_transactions = await client.get_transactions("1", 0, 5)
            some_transactions_2 = await client.get_transactions("1", 5, 10)
            assert len(all_transactions) > 1
            assert some_transactions == all_transactions[0:5]
            assert some_transactions_2 == all_transactions[5:10]

            transaction_count = await client.get_transaction_count("1")
            assert transaction_count == len(all_transactions)

            pks = await client.get_public_keys()
            assert len(pks) == 1

            assert (await client.get_height_info()) > 0

            created_tx = await client.send_transaction("1", tx_amount, addr)

            async def tx_in_mempool_2():
                tx = await client.get_transaction("1", created_tx.name)
                return tx.is_in_mempool()

            await time_out_assert(5, tx_in_mempool_2, True)
            assert len(await wallet.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(1)) == 1
            await client.delete_unconfirmed_transactions("1")
            assert len(await wallet.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(1)) == 0

            sk_dict = await client.get_private_key(pks[0])
            assert sk_dict["fingerprint"] == pks[0]
            assert sk_dict["sk"] is not None
            assert sk_dict["pk"] is not None
            assert sk_dict["seed"] is not None

            mnemonic = await client.generate_mnemonic()
            assert len(mnemonic) == 24

            await client.add_key(mnemonic)

            pks = await client.get_public_keys()
            assert len(pks) == 2

            await client.log_in_and_skip(pks[1])
            sk_dict = await client.get_private_key(pks[1])
            assert sk_dict["fingerprint"] == pks[1]

            # Add in reward addresses into farmer and pool for testing delete key checks
            # set farmer to first private key
            sk = await wallet_node.get_key_for_fingerprint(pks[0])
            test_ph = create_puzzlehash_for_pk(master_sk_to_wallet_sk(sk, uint32(0)).get_g1())
            test_config = load_config(wallet_node.root_path, "config.yaml")
            test_config["farmer"]["xch_target_address"] = encode_puzzle_hash(test_ph, "txch")
            # set pool to second private key
            sk = await wallet_node.get_key_for_fingerprint(pks[1])
            test_ph = create_puzzlehash_for_pk(master_sk_to_wallet_sk(sk, uint32(0)).get_g1())
            test_config["pool"]["xch_target_address"] = encode_puzzle_hash(test_ph, "txch")
            save_config(wallet_node.root_path, "config.yaml", test_config)

            # Check first key
            sk_dict = await client.check_delete_key(pks[0])
            assert sk_dict["fingerprint"] == pks[0]
            assert sk_dict["used_for_farmer_rewards"] is True
            assert sk_dict["used_for_pool_rewards"] is False

            # Check second key
            sk_dict = await client.check_delete_key(pks[1])
            assert sk_dict["fingerprint"] == pks[1]
            assert sk_dict["used_for_farmer_rewards"] is False
            assert sk_dict["used_for_pool_rewards"] is True

            # Check unknown key
            sk_dict = await client.check_delete_key(123456)
            assert sk_dict["fingerprint"] == 123456
            assert sk_dict["used_for_farmer_rewards"] is False
            assert sk_dict["used_for_pool_rewards"] is False

            await client.delete_key(pks[0])
            await client.log_in_and_skip(pks[1])
            assert len(await client.get_public_keys()) == 1

            assert not (await client.get_sync_status())

            wallets = await client.get_wallets()
            assert len(wallets) == 1
            balance = await client.get_wallet_balance(wallets[0]["id"])
            assert balance["unconfirmed_wallet_balance"] == 0

            try:
                await client.send_transaction(wallets[0]["id"], 100, addr)
                raise Exception("Should not create tx if no balance")
            except ValueError:
                pass
            # Delete all keys
            await client.delete_all_keys()
            assert len(await client.get_public_keys()) == 0
        finally:
            # Checks that the RPC manages to stop the node
            client.close()
            client_2.close()
            client_node.close()
            await client.await_closed()
            await client_2.await_closed()
            await client_node.await_closed()
            await rpc_cleanup()
            await rpc_cleanup_2()
            await rpc_cleanup_node()