Exemplo n.º 1
0
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_spend = CoinSpend(farmed_coin, ANYONE_CAN_SPEND_PUZZLE, conditions)
    spend_bundle = SpendBundle.aggregate(
        [launcher_spend_bundle,
         SpendBundle([coin_spend], 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_spends[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
Exemplo n.º 2
0
def spend_to_delayed_puzzle(
    p2_singleton_coin: Coin,
    output_amount: uint64,
    launcher_id: bytes32,
    delay_time: uint64,
    delay_ph: bytes32,
) -> CoinSpend:
    claim_coinsol = CoinSpend(
        p2_singleton_coin,
        pay_to_singleton_or_delay_puzzle(launcher_id, delay_time, delay_ph),
        solution_for_p2_delayed_puzzle(output_amount),
    )
    return claim_coinsol
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
Exemplo n.º 4
0
 def _row_to_farmer_record(row) -> FarmerRecord:
     return FarmerRecord(
         bytes.fromhex(row[0]),
         bytes.fromhex(row[1]),
         row[2],
         bytes.fromhex(row[3]),
         G1Element.from_bytes(bytes.fromhex(row[4])),
         CoinSpend.from_bytes(row[5]),
         PoolState.from_bytes(row[6]),
         row[7],
         row[8],
         row[9],
         True if row[10] == 1 else False,
     )
Exemplo n.º 5
0
def make_spend_bundle(count: int) -> SpendBundle:
    puzzle_hash_db: Dict = dict()
    coins = [make_fake_coin(_, puzzle_hash_db) for _ in range(count)]

    coin_spends = []
    for coin in coins:
        puzzle_reveal = puzzle_hash_db[coin.puzzle_hash]
        conditions = conditions_for_payment(coin)
        solution = solution_for_conditions(conditions)
        coin_spend = CoinSpend(coin, puzzle_reveal, solution)
        coin_spends.append(coin_spend)

    spend_bundle = SpendBundle(coin_spends, blspy.G2Element())
    return spend_bundle
Exemplo n.º 6
0
 async def get_puzzle_and_solution(self, coin_id: bytes32, height: uint32) -> Optional[CoinSpend]:
     generator = list(filter(lambda block: block.height == height, self.service.blocks))[0].transactions_generator
     coin_record = await self.service.mempool_manager.coin_store.get_coin_record(coin_id)
     error, puzzle, solution = get_puzzle_and_solution_for_coin(
         generator,
         coin_id,
         self.service.defaults.MAX_BLOCK_COST_CLVM,
     )
     if error:
         return None
     else:
         puzzle_ser: SerializedProgram = SerializedProgram.from_program(Program.to(puzzle))
         solution_ser: SerializedProgram = SerializedProgram.from_program(Program.to(solution))
         return CoinSpend(coin_record.coin, puzzle_ser, solution_ser)
Exemplo n.º 7
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_spend = CoinSpend(coin, EASY_PUZZLE, condition_solution)
    spend_bundle = SpendBundle([coin_spend], 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)
Exemplo n.º 8
0
 async def rebuild_cache(self) -> None:
     """
     This resets the cache, and loads all entries from the DB. Any entries in the cache that were not committed
     are removed. This can happen if a state transition in wallet_blockchain fails.
     """
     cursor = await self.db_connection.execute("SELECT * FROM pool_state_transitions ORDER BY transition_index")
     rows = await cursor.fetchall()
     await cursor.close()
     self._state_transitions_cache = {}
     for row in rows:
         _, wallet_id, height, coin_spend_bytes = row
         coin_spend: CoinSpend = CoinSpend.from_bytes(coin_spend_bytes)
         if wallet_id not in self._state_transitions_cache:
             self._state_transitions_cache[wallet_id] = []
         self._state_transitions_cache[wallet_id].append((height, coin_spend))
Exemplo n.º 9
0
    async def launch_smart_coin(self, source, **kwargs) -> CoinWrapper:
        """Create a new smart coin based on a parent coin and return the smart coin's living
        coin to the user or None if the spend failed."""
        amt = 1
        if 'amt' in kwargs:
            amt = kwargs['amt']

        found_coin = await self.choose_coin(amt)
        if found_coin is None:
            raise ValueError(
                f'could not find available coin containing {amt} mojo')

        # Create a puzzle based on the incoming smart coin
        cw = ContractWrapper(DEFAULT_CONSTANTS.GENESIS_CHALLENGE, source)
        condition_args = [
            [ConditionOpcode.CREATE_COIN,
             cw.puzzle_hash(), amt],
        ]
        if amt < found_coin.amount:
            condition_args.append([
                ConditionOpcode.CREATE_COIN, self.puzzle_hash,
                found_coin.amount - amt
            ])

        delegated_puzzle_solution = Program.to((1, condition_args))
        solution = Program.to([[], delegated_puzzle_solution, []])

        # Sign the (delegated_puzzle_hash + coin_name) with synthetic secret key
        signature = AugSchemeMPL.sign(
            calculate_synthetic_secret_key(self.sk_,
                                           DEFAULT_HIDDEN_PUZZLE_HASH),
            (delegated_puzzle_solution.get_tree_hash() + found_coin.name() +
             DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA))

        spend_bundle = SpendBundle(
            [
                CoinSpend(
                    found_coin.as_coin(),  # Coin to spend
                    self.puzzle,  # Puzzle used for found_coin
                    solution,  # The solution to the puzzle locking found_coin
                )
            ],
            signature)
        pushed = await self.parent.push_tx(spend_bundle)
        if 'error' not in pushed:
            return cw.custom_coin(found_coin, amt)
        else:
            return None
Exemplo n.º 10
0
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 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
Exemplo n.º 12
0
 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))
Exemplo n.º 13
0
    def create_standard_spend(self, priv, conditions):
        delegated_puzzle_solution = Program.to((1, conditions))
        solution = Program.to([[], delegated_puzzle_solution, []])

        coin_solution_object = CoinSpend(
            self.as_coin(),
            self.puzzle(),
            solution,
        )

        # Create a signature for each of these.  We'll aggregate them at the end.
        signature = AugSchemeMPL.sign(
            calculate_synthetic_secret_key(priv, DEFAULT_HIDDEN_PUZZLE_HASH),
            (delegated_puzzle_solution.get_tree_hash() + self.name() +
             DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA))

        return coin_solution_object, signature
Exemplo n.º 14
0
    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()
Exemplo n.º 15
0
    async def create_spend_bundle_relative_chia(
            self, chia_amount: int, exclude: List[Coin]) -> SpendBundle:
        list_of_solutions = []
        utxos = None

        # If we're losing value then get coins with at least that much value
        # If we're gaining value then our amount doesn't matter
        if chia_amount < 0:
            utxos = await self.select_coins(abs(chia_amount), exclude)
        else:
            utxos = await self.select_coins(0, exclude)

        assert len(utxos) > 0

        # Calculate output amount given sum of utxos
        spend_value = sum([coin.amount for coin in utxos])
        chia_amount = spend_value + chia_amount

        # Create coin solutions for each utxo
        output_created = None
        for coin in utxos:
            puzzle = await self.puzzle_for_puzzle_hash(coin.puzzle_hash)
            if output_created is None:
                newpuzhash = await self.get_new_puzzlehash()
                primaries: List[AmountWithPuzzlehash] = [{
                    "puzzlehash":
                    newpuzhash,
                    "amount":
                    uint64(chia_amount),
                    "memos": []
                }]
                solution = self.make_solution(primaries=primaries)
                output_created = coin
            list_of_solutions.append(CoinSpend(coin, puzzle, solution))

        await self.hack_populate_secret_keys_for_coin_spends(list_of_solutions)
        spend_bundle = await sign_coin_spends(
            list_of_solutions,
            self.secret_key_store.secret_key_for_public_key,
            self.wallet_state_manager.constants.AGG_SIG_ME_ADDITIONAL_DATA,
            self.wallet_state_manager.constants.MAX_BLOCK_COST_CLVM,
        )
        return spend_bundle
Exemplo n.º 16
0
    async def rl_generate_unsigned_transaction(self, to_puzzlehash, amount,
                                               fee) -> List[CoinSpend]:
        spends = []
        assert self.rl_coin_record is not None
        coin = self.rl_coin_record.coin
        puzzle_hash = coin.puzzle_hash
        pubkey = self.rl_info.user_pubkey
        rl_parent: Optional[Coin] = await self._get_rl_parent()
        if rl_parent is None:
            raise ValueError("No RL parent coin")

        # these lines make mypy happy

        assert pubkey is not None
        assert self.rl_info.limit is not None
        assert self.rl_info.interval is not None
        assert self.rl_info.rl_origin_id is not None
        assert self.rl_info.admin_pubkey is not None

        puzzle = rl_puzzle_for_pk(
            bytes(pubkey),
            self.rl_info.limit,
            self.rl_info.interval,
            self.rl_info.rl_origin_id,
            self.rl_info.admin_pubkey,
        )

        solution = solution_for_rl(
            coin.parent_coin_info,
            puzzle_hash,
            coin.amount,
            to_puzzlehash,
            amount,
            rl_parent.parent_coin_info,
            rl_parent.amount,
            self.rl_info.interval,
            self.rl_info.limit,
            fee,
        )

        spends.append(CoinSpend(coin, puzzle, solution))
        return spends
Exemplo n.º 17
0
 def generate_unsigned_clawback_transaction(self, clawback_coin: Coin,
                                            clawback_puzzle_hash: bytes32,
                                            fee):
     if (self.rl_info.limit is None or self.rl_info.interval is None
             or self.rl_info.user_pubkey is None
             or self.rl_info.admin_pubkey is None):
         raise ValueError("One ore more of the elements of rl_info is None")
     spends = []
     coin = clawback_coin
     if self.rl_info.rl_origin is None:
         raise ValueError("Origin not initialized")
     puzzle = rl_puzzle_for_pk(
         self.rl_info.user_pubkey,
         self.rl_info.limit,
         self.rl_info.interval,
         self.rl_info.rl_origin.name(),
         self.rl_info.admin_pubkey,
     )
     solution = make_clawback_solution(clawback_puzzle_hash,
                                       clawback_coin.amount, fee)
     spends.append((puzzle, CoinSpend(coin, puzzle, solution)))
     return spends
Exemplo n.º 18
0
def launch_conditions_and_coinsol(
    coin: Coin,
    inner_puzzle: Program,
    comment: List[Tuple[str, str]],
    amount: uint64,
) -> Tuple[List[Program], CoinSpend]:
    if (amount % 2) == 0:
        raise ValueError("Coin amount cannot be even. Subtract one mojo.")

    launcher_coin: Coin = generate_launcher_coin(coin, amount)
    curried_singleton: Program = SINGLETON_MOD.curry(
        (SINGLETON_MOD_HASH, (launcher_coin.name(), SINGLETON_LAUNCHER_HASH)),
        inner_puzzle,
    )

    launcher_solution = Program.to([
        curried_singleton.get_tree_hash(),
        amount,
        comment,
    ])
    create_launcher = Program.to([
        ConditionOpcode.CREATE_COIN,
        SINGLETON_LAUNCHER_HASH,
        amount,
    ], )
    assert_launcher_announcement = Program.to([
        ConditionOpcode.ASSERT_COIN_ANNOUNCEMENT,
        std_hash(launcher_coin.name() + launcher_solution.get_tree_hash()),
    ], )

    conditions = [create_launcher, assert_launcher_announcement]

    launcher_coin_spend = CoinSpend(
        launcher_coin,
        SINGLETON_LAUNCHER,
        launcher_solution,
    )

    return conditions, launcher_coin_spend
Exemplo n.º 19
0
    async def get_puzzle_and_solution(self, request: Dict) -> Optional[Dict]:
        coin_name: bytes32 = bytes32.from_hexstr(request["coin_id"])
        height = request["height"]
        coin_record = await self.service.coin_store.get_coin_record(coin_name)
        if coin_record is None or not coin_record.spent or coin_record.spent_block_index != height:
            raise ValueError(
                f"Invalid height {height}. coin record {coin_record}")

        header_hash = self.service.blockchain.height_to_hash(height)
        # TODO: address hint error and remove ignore
        #       error: Argument 1 to "get_full_block" of "BlockStore" has incompatible type "Optional[bytes32]";
        #       expected "bytes32"  [arg-type]
        block: Optional[
            FullBlock] = await self.service.block_store.get_full_block(
                header_hash)  # type: ignore[arg-type]  # noqa: E501

        if block is None or block.transactions_generator is None:
            raise ValueError("Invalid block or block generator")

        block_generator: Optional[
            BlockGenerator] = await self.service.blockchain.get_block_generator(
                block)
        assert block_generator is not None
        error, puzzle, solution = get_puzzle_and_solution_for_coin(
            block_generator, coin_name,
            self.service.constants.MAX_BLOCK_COST_CLVM)
        if error is not None:
            raise ValueError(f"Error: {error}")

        puzzle_ser: SerializedProgram = SerializedProgram.from_program(
            Program.to(puzzle))
        solution_ser: SerializedProgram = SerializedProgram.from_program(
            Program.to(solution))
        return {
            "coin_solution": CoinSpend(coin_record.coin, puzzle_ser,
                                       solution_ser)
        }
Exemplo n.º 20
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])
Exemplo n.º 21
0
    def generate_unsigned_transaction(
        self,
        amount: uint64,
        new_puzzle_hash: bytes32,
        coins: List[Coin],
        condition_dic: Dict[ConditionOpcode, List[ConditionWithArgs]],
        fee: int = 0,
        secret_key: Optional[PrivateKey] = None,
        additional_outputs: Optional[List[Tuple[bytes32, int]]] = None,
    ) -> List[CoinSpend]:
        spends = []

        spend_value = sum([c.amount for c in coins])

        if ConditionOpcode.CREATE_COIN not in condition_dic:
            condition_dic[ConditionOpcode.CREATE_COIN] = []
        if ConditionOpcode.CREATE_COIN_ANNOUNCEMENT not in condition_dic:
            condition_dic[ConditionOpcode.CREATE_COIN_ANNOUNCEMENT] = []

        output = ConditionWithArgs(
            ConditionOpcode.CREATE_COIN,
            [new_puzzle_hash, int_to_bytes(amount)])
        condition_dic[output.opcode].append(output)
        if additional_outputs is not None:
            for o in additional_outputs:
                out = ConditionWithArgs(ConditionOpcode.CREATE_COIN,
                                        [o[0], int_to_bytes(o[1])])
                condition_dic[out.opcode].append(out)

        amount_total = sum(
            int_from_bytes(cvp.vars[1])
            for cvp in condition_dic[ConditionOpcode.CREATE_COIN])
        change = spend_value - amount_total - fee
        if change > 0:
            change_puzzle_hash = self.get_new_puzzlehash()
            change_output = ConditionWithArgs(
                ConditionOpcode.CREATE_COIN,
                [change_puzzle_hash, int_to_bytes(change)])
            condition_dic[output.opcode].append(change_output)

        secondary_coins_cond_dic: Dict[ConditionOpcode,
                                       List[ConditionWithArgs]] = dict()
        secondary_coins_cond_dic[ConditionOpcode.ASSERT_COIN_ANNOUNCEMENT] = []
        for n, coin in enumerate(coins):
            puzzle_hash = coin.puzzle_hash
            if secret_key is None:
                secret_key = self.get_private_key_for_puzzle_hash(puzzle_hash)
            pubkey = secret_key.get_g1()
            puzzle = puzzle_for_pk(bytes(pubkey))
            if n == 0:
                message_list = [c.name() for c in coins]
                for outputs in condition_dic[ConditionOpcode.CREATE_COIN]:
                    message_list.append(
                        Coin(coin.name(), outputs.vars[0],
                             int_from_bytes(outputs.vars[1])).name())
                message = std_hash(b"".join(message_list))
                condition_dic[ConditionOpcode.CREATE_COIN_ANNOUNCEMENT].append(
                    ConditionWithArgs(ConditionOpcode.CREATE_COIN_ANNOUNCEMENT,
                                      [message]))
                primary_announcement_hash = Announcement(coin.name(),
                                                         message).name()
                secondary_coins_cond_dic[
                    ConditionOpcode.ASSERT_COIN_ANNOUNCEMENT].append(
                        ConditionWithArgs(
                            ConditionOpcode.ASSERT_COIN_ANNOUNCEMENT,
                            [primary_announcement_hash]))
                main_solution = self.make_solution(condition_dic)
                spends.append(CoinSpend(coin, puzzle, main_solution))
            else:
                spends.append(
                    CoinSpend(coin, puzzle,
                              self.make_solution(secondary_coins_cond_dic)))
        return spends
Exemplo n.º 22
0
    async def test_cat_mod(self, setup_sim):
        sim, sim_client = setup_sim

        try:
            tail = Program.to([])
            checker_solution = Program.to([])
            cat_puzzle: Program = construct_cat_puzzle(CAT_MOD, tail.get_tree_hash(), acs)
            cat_ph: bytes32 = cat_puzzle.get_tree_hash()
            await sim.farm_block(cat_ph)
            starting_coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(cat_ph))[0].coin

            # Testing the eve spend
            await self.do_spend(
                sim,
                sim_client,
                tail,
                [starting_coin],
                [NO_LINEAGE_PROOF],
                [
                    Program.to(
                        [
                            [51, acs.get_tree_hash(), starting_coin.amount - 3, [b"memo"]],
                            [51, acs.get_tree_hash(), 1],
                            [51, acs.get_tree_hash(), 2],
                            [51, 0, -113, tail, checker_solution],
                        ]
                    )
                ],
                (MempoolInclusionStatus.SUCCESS, None),
                limitations_solutions=[checker_solution],
                cost_str="Eve Spend",
            )

            # There's 4 total coins at this point. A farming reward and the three children of the spend above.

            # Testing a combination of two
            coins: List[Coin] = [
                record.coin
                for record in (await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False))
            ]
            coins = [coins[0], coins[1]]
            await self.do_spend(
                sim,
                sim_client,
                tail,
                coins,
                [NO_LINEAGE_PROOF] * 2,
                [
                    Program.to(
                        [
                            [51, acs.get_tree_hash(), coins[0].amount + coins[1].amount],
                            [51, 0, -113, tail, checker_solution],
                        ]
                    ),
                    Program.to([[51, 0, -113, tail, checker_solution]]),
                ],
                (MempoolInclusionStatus.SUCCESS, None),
                limitations_solutions=[checker_solution] * 2,
                cost_str="Two CATs",
            )

            # Testing a combination of three
            coins = [
                record.coin
                for record in (await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False))
            ]
            total_amount: uint64 = uint64(sum([c.amount for c in coins]))
            await self.do_spend(
                sim,
                sim_client,
                tail,
                coins,
                [NO_LINEAGE_PROOF] * 3,
                [
                    Program.to(
                        [
                            [51, acs.get_tree_hash(), total_amount],
                            [51, 0, -113, tail, checker_solution],
                        ]
                    ),
                    Program.to([[51, 0, -113, tail, checker_solution]]),
                    Program.to([[51, 0, -113, tail, checker_solution]]),
                ],
                (MempoolInclusionStatus.SUCCESS, None),
                limitations_solutions=[checker_solution] * 3,
                cost_str="Three CATs",
            )

            # Spend with a standard lineage proof
            parent_coin: Coin = coins[0]  # The first one is the one we didn't light on fire
            _, curried_args = cat_puzzle.uncurry()
            _, _, innerpuzzle = curried_args.as_iter()
            lineage_proof = LineageProof(parent_coin.parent_coin_info, innerpuzzle.get_tree_hash(), parent_coin.amount)
            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],
                [lineage_proof],
                [Program.to([[51, acs.get_tree_hash(), total_amount]])],
                (MempoolInclusionStatus.SUCCESS, None),
                reveal_limitations_program=False,
                cost_str="Standard Lineage Check",
            )

            # Melt some value
            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(), total_amount - 1],
                            [51, 0, -113, tail, checker_solution],
                        ]
                    )
                ],
                (MempoolInclusionStatus.SUCCESS, None),
                extra_deltas=[-1],
                limitations_solutions=[checker_solution],
                cost_str="Melting Value",
            )

            # Mint some value
            temp_p = Program.to(1)
            temp_ph: bytes32 = temp_p.get_tree_hash()
            await sim.farm_block(temp_ph)
            acs_coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(temp_ph, include_spent_coins=False))[
                0
            ].coin
            acs_bundle = SpendBundle(
                [
                    CoinSpend(
                        acs_coin,
                        temp_p,
                        Program.to([]),
                    )
                ],
                G2Element(),
            )
            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(), total_amount],
                            [51, 0, -113, tail, checker_solution],
                        ]
                    )
                ],  # We subtracted 1 last time so it's normal now
                (MempoolInclusionStatus.SUCCESS, None),
                extra_deltas=[1],
                additional_spends=[acs_bundle],
                limitations_solutions=[checker_solution],
                cost_str="Mint Value",
            )

        finally:
            await sim.close()
Exemplo n.º 23
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()
Exemplo n.º 24
0
    async def test_everything_with_signature(self, setup_sim):
        sim, sim_client = setup_sim

        try:
            sk = PrivateKey.from_bytes(secret_exponent_for_index(1).to_bytes(32, "big"))
            tail: Program = EverythingWithSig.construct([Program.to(sk.get_g1())])
            checker_solution: Program = EverythingWithSig.solve([], {})
            cat_puzzle: Program = construct_cat_puzzle(CAT_MOD, tail.get_tree_hash(), acs)
            cat_ph: bytes32 = cat_puzzle.get_tree_hash()
            await sim.farm_block(cat_ph)

            # Test eve spend
            # We don't sign any message data because CLVM 0 translates to b'' apparently
            starting_coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(cat_ph))[0].coin
            signature: G2Element = AugSchemeMPL.sign(
                sk, (starting_coin.name() + sim.defaults.AGG_SIG_ME_ADDITIONAL_DATA)
            )

            await self.do_spend(
                sim,
                sim_client,
                tail,
                [starting_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],
                signatures=[signature],
                cost_str="Signature Issuance",
            )

            # Test melting value
            coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False))[0].coin
            signature = AugSchemeMPL.sign(
                sk, (int_to_bytes(-1) + coin.name() + sim.defaults.AGG_SIG_ME_ADDITIONAL_DATA)
            )

            await self.do_spend(
                sim,
                sim_client,
                tail,
                [coin],
                [NO_LINEAGE_PROOF],
                [
                    Program.to(
                        [
                            [51, acs.get_tree_hash(), coin.amount - 1],
                            [51, 0, -113, tail, checker_solution],
                        ]
                    )
                ],
                (MempoolInclusionStatus.SUCCESS, None),
                extra_deltas=[-1],
                limitations_solutions=[checker_solution],
                signatures=[signature],
                cost_str="Signature Melt",
            )

            # Test minting value
            coin = (await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False))[0].coin
            signature = AugSchemeMPL.sign(sk, (int_to_bytes(1) + coin.name() + sim.defaults.AGG_SIG_ME_ADDITIONAL_DATA))

            # Need something to fund the minting
            temp_p = Program.to(1)
            temp_ph: bytes32 = temp_p.get_tree_hash()
            await sim.farm_block(temp_ph)
            acs_coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(temp_ph, include_spent_coins=False))[
                0
            ].coin
            acs_bundle = SpendBundle(
                [
                    CoinSpend(
                        acs_coin,
                        temp_p,
                        Program.to([]),
                    )
                ],
                G2Element(),
            )

            await self.do_spend(
                sim,
                sim_client,
                tail,
                [coin],
                [NO_LINEAGE_PROOF],
                [
                    Program.to(
                        [
                            [51, acs.get_tree_hash(), coin.amount + 1],
                            [51, 0, -113, tail, checker_solution],
                        ]
                    )
                ],
                (MempoolInclusionStatus.SUCCESS, None),
                extra_deltas=[1],
                limitations_solutions=[checker_solution],
                signatures=[signature],
                additional_spends=[acs_bundle],
                cost_str="Signature Mint",
            )

        finally:
            await sim.close()
Exemplo n.º 25
0
    async def generate_launcher_spend(
        standard_wallet: Wallet,
        amount: uint64,
        initial_target_state: PoolState,
        genesis_challenge: bytes32,
        delay_time: uint64,
        delay_ph: bytes32,
    ) -> Tuple[SpendBundle, bytes32, bytes32]:
        """
        Creates the initial singleton, which includes spending an origin coin, the launcher, and creating a singleton
        with the "pooling" inner state, which can be either self pooling or using a pool
        """
        coins: Set[Coin] = await standard_wallet.select_coins(amount)
        if coins is None:
            raise ValueError("Not enough coins to create pool wallet")

        assert len(coins) == 1

        launcher_parent: Coin = coins.copy().pop()
        genesis_launcher_puz: Program = SINGLETON_LAUNCHER
        launcher_coin: Coin = Coin(launcher_parent.name(), genesis_launcher_puz.get_tree_hash(), amount)

        escaping_inner_puzzle: Program = create_waiting_room_inner_puzzle(
            initial_target_state.target_puzzle_hash,
            initial_target_state.relative_lock_height,
            initial_target_state.owner_pubkey,
            launcher_coin.name(),
            genesis_challenge,
            delay_time,
            delay_ph,
        )
        escaping_inner_puzzle_hash = escaping_inner_puzzle.get_tree_hash()

        self_pooling_inner_puzzle: Program = create_pooling_inner_puzzle(
            initial_target_state.target_puzzle_hash,
            escaping_inner_puzzle_hash,
            initial_target_state.owner_pubkey,
            launcher_coin.name(),
            genesis_challenge,
            delay_time,
            delay_ph,
        )

        if initial_target_state.state == SELF_POOLING:
            puzzle = escaping_inner_puzzle
        elif initial_target_state.state == FARMING_TO_POOL:
            puzzle = self_pooling_inner_puzzle
        else:
            raise ValueError("Invalid initial state")
        full_pooling_puzzle: Program = create_full_puzzle(puzzle, launcher_id=launcher_coin.name())

        puzzle_hash: bytes32 = full_pooling_puzzle.get_tree_hash()
        pool_state_bytes = Program.to([("p", bytes(initial_target_state)), ("t", delay_time), ("h", delay_ph)])
        announcement_set: Set[Announcement] = set()
        announcement_message = Program.to([puzzle_hash, amount, pool_state_bytes]).get_tree_hash()
        announcement_set.add(Announcement(launcher_coin.name(), announcement_message))

        create_launcher_tx_record: Optional[TransactionRecord] = await standard_wallet.generate_signed_transaction(
            amount,
            genesis_launcher_puz.get_tree_hash(),
            uint64(0),
            None,
            coins,
            None,
            False,
            announcement_set,
        )
        assert create_launcher_tx_record is not None and create_launcher_tx_record.spend_bundle is not None

        genesis_launcher_solution: Program = Program.to([puzzle_hash, amount, pool_state_bytes])

        launcher_cs: CoinSpend = CoinSpend(
            launcher_coin,
            SerializedProgram.from_program(genesis_launcher_puz),
            SerializedProgram.from_program(genesis_launcher_solution),
        )
        launcher_sb: SpendBundle = SpendBundle([launcher_cs], G2Element())

        # Current inner will be updated when state is verified on the blockchain
        full_spend: SpendBundle = SpendBundle.aggregate([create_launcher_tx_record.spend_bundle, launcher_sb])
        return full_spend, puzzle_hash, launcher_coin.name()
Exemplo n.º 26
0
    async def generate_new_decentralised_id(
            self, amount: uint64) -> Optional[SpendBundle]:
        """
        This must be called under the wallet state manager lock
        """

        coins = await self.standard_wallet.select_coins(amount)
        if coins is None:
            return None

        origin = coins.copy().pop()
        genesis_launcher_puz = did_wallet_puzzles.SINGLETON_LAUNCHER
        launcher_coin = Coin(origin.name(),
                             genesis_launcher_puz.get_tree_hash(), amount)

        did_inner: Program = await self.get_new_innerpuz()
        did_inner_hash = did_inner.get_tree_hash()
        did_full_puz = did_wallet_puzzles.create_fullpuz(
            did_inner, launcher_coin.name())
        did_puzzle_hash = did_full_puz.get_tree_hash()

        announcement_set: Set[Announcement] = set()
        announcement_message = Program.to(
            [did_puzzle_hash, amount, bytes(0x80)]).get_tree_hash()
        announcement_set.add(
            Announcement(launcher_coin.name(), announcement_message).name())

        tx_record: Optional[
            TransactionRecord] = await self.standard_wallet.generate_signed_transaction(
                amount, genesis_launcher_puz.get_tree_hash(), uint64(0),
                origin.name(), coins, None, False, announcement_set)

        genesis_launcher_solution = Program.to(
            [did_puzzle_hash, amount, bytes(0x80)])

        launcher_cs = CoinSpend(launcher_coin, genesis_launcher_puz,
                                genesis_launcher_solution)
        launcher_sb = SpendBundle([launcher_cs], AugSchemeMPL.aggregate([]))
        eve_coin = Coin(launcher_coin.name(), did_puzzle_hash, amount)
        future_parent = LineageProof(
            eve_coin.parent_coin_info,
            did_inner_hash,
            eve_coin.amount,
        )
        eve_parent = LineageProof(
            launcher_coin.parent_coin_info,
            launcher_coin.puzzle_hash,
            launcher_coin.amount,
        )
        await self.add_parent(eve_coin.parent_coin_info, eve_parent, False)
        await self.add_parent(eve_coin.name(), future_parent, False)

        if tx_record is None or tx_record.spend_bundle is None:
            return None

        # Only want to save this information if the transaction is valid
        did_info: DIDInfo = DIDInfo(
            launcher_coin,
            self.did_info.backup_ids,
            self.did_info.num_of_backup_ids_needed,
            self.did_info.parent_info,
            did_inner,
            None,
            None,
            None,
            False,
        )
        await self.save_info(did_info, False)
        eve_spend = await self.generate_eve_spend(eve_coin, did_full_puz,
                                                  did_inner)
        full_spend = SpendBundle.aggregate(
            [tx_record.spend_bundle, eve_spend, launcher_sb])
        return full_spend
Exemplo n.º 27
0
    async def recovery_spend(
        self,
        coin: Coin,
        puzhash: bytes32,
        parent_innerpuzhash_amounts_for_recovery_ids: List[Tuple[bytes, bytes,
                                                                 int]],
        pubkey: G1Element,
        spend_bundle: SpendBundle,
    ) -> SpendBundle:
        assert self.did_info.origin_coin is not None

        # innersol is mode new_amount message new_inner_puzhash parent_innerpuzhash_amounts_for_recovery_ids pubkey recovery_list_reveal)  # noqa
        innersol: Program = Program.to([
            2,
            coin.amount,
            puzhash,
            puzhash,
            parent_innerpuzhash_amounts_for_recovery_ids,
            bytes(pubkey),
            self.did_info.backup_ids,
        ])
        # full solution is (parent_info my_amount solution)
        assert self.did_info.current_inner is not None
        innerpuz: Program = self.did_info.current_inner
        full_puzzle: Program = did_wallet_puzzles.create_fullpuz(
            innerpuz,
            self.did_info.origin_coin.name(),
        )
        parent_info = await self.get_parent_for_coin(coin)
        assert parent_info is not None
        fullsol = Program.to([
            [
                parent_info.parent_name,
                parent_info.inner_puzzle_hash,
                parent_info.amount,
            ],
            coin.amount,
            innersol,
        ])
        list_of_solutions = [CoinSpend(coin, full_puzzle, fullsol)]

        index = await self.wallet_state_manager.puzzle_store.index_for_pubkey(
            pubkey)
        if index is None:
            raise ValueError("Unknown pubkey.")
        private = master_sk_to_wallet_sk(self.wallet_state_manager.private_key,
                                         index)
        message = bytes(puzhash)
        sigs = [AugSchemeMPL.sign(private, message)]
        for _ in spend_bundle.coin_spends:
            sigs.append(AugSchemeMPL.sign(private, message))
        aggsig = AugSchemeMPL.aggregate(sigs)
        # assert AugSchemeMPL.verify(pubkey, message, aggsig)
        if spend_bundle is None:
            spend_bundle = SpendBundle(list_of_solutions, aggsig)
        else:
            spend_bundle = spend_bundle.aggregate(
                [spend_bundle,
                 SpendBundle(list_of_solutions, aggsig)])

        did_record = TransactionRecord(
            confirmed_at_height=uint32(0),
            created_at_time=uint64(int(time.time())),
            to_puzzle_hash=puzhash,
            amount=uint64(coin.amount),
            fee_amount=uint64(0),
            confirmed=False,
            sent=uint32(0),
            spend_bundle=spend_bundle,
            additions=spend_bundle.additions(),
            removals=spend_bundle.removals(),
            wallet_id=self.wallet_info.id,
            sent_to=[],
            trade_id=None,
            type=uint32(TransactionType.OUTGOING_TX.value),
            name=token_bytes(),
        )
        await self.standard_wallet.push_transaction(did_record)
        new_did_info = DIDInfo(
            self.did_info.origin_coin,
            self.did_info.backup_ids,
            self.did_info.num_of_backup_ids_needed,
            self.did_info.parent_info,
            self.did_info.current_inner,
            self.did_info.temp_coin,
            self.did_info.temp_puzhash,
            self.did_info.temp_pubkey,
            True,
        )
        await self.save_info(new_did_info, True)
        return spend_bundle
Exemplo n.º 28
0
    async def create_attestment(self,
                                recovering_coin_name: bytes32,
                                newpuz: bytes32,
                                pubkey: G1Element,
                                filename=None) -> SpendBundle:
        assert self.did_info.current_inner is not None
        assert self.did_info.origin_coin is not None
        coins = await self.select_coins(1)
        assert coins is not None and coins != set()
        coin = coins.pop()
        message = did_wallet_puzzles.create_recovery_message_puzzle(
            recovering_coin_name, newpuz, pubkey)
        innermessage = message.get_tree_hash()
        innerpuz: Program = self.did_info.current_inner
        # innerpuz solution is (mode, amount, message, new_inner_puzhash)
        messages = [(0, innermessage)]
        innersol = Program.to(
            [1, coin.amount, messages,
             innerpuz.get_tree_hash()])

        # full solution is (corehash parent_info my_amount innerpuz_reveal solution)
        full_puzzle: Program = did_wallet_puzzles.create_fullpuz(
            innerpuz,
            self.did_info.origin_coin.name(),
        )
        parent_info = await self.get_parent_for_coin(coin)
        assert parent_info is not None

        fullsol = Program.to([
            [
                parent_info.parent_name,
                parent_info.inner_puzzle_hash,
                parent_info.amount,
            ],
            coin.amount,
            innersol,
        ])
        list_of_solutions = [CoinSpend(coin, full_puzzle, fullsol)]
        message_spend = did_wallet_puzzles.create_spend_for_message(
            coin.name(), recovering_coin_name, newpuz, pubkey)
        message_spend_bundle = SpendBundle([message_spend],
                                           AugSchemeMPL.aggregate([]))
        # sign for AGG_SIG_ME
        to_sign = Program.to([innerpuz.get_tree_hash(), coin.amount,
                              messages]).get_tree_hash()
        message = to_sign + coin.name(
        ) + self.wallet_state_manager.constants.AGG_SIG_ME_ADDITIONAL_DATA
        pubkey = did_wallet_puzzles.get_pubkey_from_innerpuz(innerpuz)
        index = await self.wallet_state_manager.puzzle_store.index_for_pubkey(
            pubkey)
        private = master_sk_to_wallet_sk(self.wallet_state_manager.private_key,
                                         index)
        signature = AugSchemeMPL.sign(private, message)
        # assert signature.validate([signature.PkMessagePair(pubkey, message)])
        spend_bundle = SpendBundle(list_of_solutions, signature)
        did_record = TransactionRecord(
            confirmed_at_height=uint32(0),
            created_at_time=uint64(int(time.time())),
            to_puzzle_hash=coin.puzzle_hash,
            amount=uint64(coin.amount),
            fee_amount=uint64(0),
            confirmed=False,
            sent=uint32(0),
            spend_bundle=spend_bundle,
            additions=spend_bundle.additions(),
            removals=spend_bundle.removals(),
            wallet_id=self.wallet_info.id,
            sent_to=[],
            trade_id=None,
            type=uint32(TransactionType.INCOMING_TX.value),
            name=token_bytes(),
        )
        await self.standard_wallet.push_transaction(did_record)
        if filename is not None:
            f = open(filename, "w")
            f.write(self.get_my_DID())
            f.write(":")
            f.write(bytes(message_spend_bundle).hex())
            f.write(":")
            parent = coin.parent_coin_info.hex()
            innerpuzhash = self.did_info.current_inner.get_tree_hash().hex()
            amount = coin.amount
            f.write(parent)
            f.write(":")
            f.write(innerpuzhash)
            f.write(":")
            f.write(str(amount))
            f.close()
        return message_spend_bundle
Exemplo n.º 29
0
    async def create_exit_spend(self, puzhash: bytes32):
        assert self.did_info.current_inner is not None
        assert self.did_info.origin_coin is not None
        coins = await self.select_coins(1)
        assert coins is not None
        coin = coins.pop()
        amount = coin.amount - 1
        # innerpuz solution is (mode amount new_puzhash)
        innersol: Program = Program.to([0, amount, puzhash])
        # full solution is (corehash parent_info my_amount innerpuz_reveal solution)
        innerpuz: Program = self.did_info.current_inner

        full_puzzle: Program = did_wallet_puzzles.create_fullpuz(
            innerpuz,
            self.did_info.origin_coin.name(),
        )
        parent_info = await self.get_parent_for_coin(coin)
        assert parent_info is not None
        fullsol = Program.to([
            [
                parent_info.parent_name,
                parent_info.inner_puzzle_hash,
                parent_info.amount,
            ],
            coin.amount,
            innersol,
        ])
        list_of_solutions = [CoinSpend(coin, full_puzzle, fullsol)]
        # sign for AGG_SIG_ME
        message = (
            Program.to([amount, puzhash]).get_tree_hash() + coin.name() +
            self.wallet_state_manager.constants.AGG_SIG_ME_ADDITIONAL_DATA)
        pubkey = did_wallet_puzzles.get_pubkey_from_innerpuz(innerpuz)
        index = await self.wallet_state_manager.puzzle_store.index_for_pubkey(
            pubkey)
        private = master_sk_to_wallet_sk(self.wallet_state_manager.private_key,
                                         index)
        signature = AugSchemeMPL.sign(private, message)
        # assert signature.validate([signature.PkMessagePair(pubkey, message)])
        sigs = [signature]
        aggsig = AugSchemeMPL.aggregate(sigs)
        spend_bundle = SpendBundle(list_of_solutions, aggsig)

        did_record = TransactionRecord(
            confirmed_at_height=uint32(0),
            created_at_time=uint64(int(time.time())),
            to_puzzle_hash=puzhash,
            amount=uint64(coin.amount),
            fee_amount=uint64(0),
            confirmed=False,
            sent=uint32(0),
            spend_bundle=spend_bundle,
            additions=spend_bundle.additions(),
            removals=spend_bundle.removals(),
            wallet_id=self.wallet_info.id,
            sent_to=[],
            trade_id=None,
            type=uint32(TransactionType.OUTGOING_TX.value),
            name=token_bytes(),
        )
        await self.standard_wallet.push_transaction(did_record)
        return spend_bundle
Exemplo n.º 30
0
    async def _generate_unsigned_transaction(
        self,
        amount: uint64,
        newpuzzlehash: bytes32,
        fee: uint64 = uint64(0),
        origin_id: bytes32 = None,
        coins: Set[Coin] = None,
        primaries_input: Optional[List[Dict[str, Any]]] = None,
        ignore_max_send_amount: bool = False,
        announcements_to_consume: Set[Announcement] = None,
    ) -> List[CoinSpend]:
        """
        Generates a unsigned transaction in form of List(Puzzle, Solutions)
        Note: this must be called under a wallet state manager lock
        """
        if primaries_input is None:
            primaries: Optional[List[Dict]] = None
            total_amount = amount + fee
        else:
            primaries = primaries_input.copy()
            primaries_amount = 0
            for prim in primaries:
                primaries_amount += prim["amount"]
            total_amount = amount + fee + primaries_amount

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

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

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

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

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

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

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

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

        self.log.info(f"Spends is {spends}")
        return spends