def parse_fee(args: SExp, safe_mode: bool) -> List[bytes]:
    fee_int = sanitize_int(args.first(), safe_mode)
    if fee_int >= 2**64 or fee_int < 0:
        raise ValidationError(Err.RESERVE_FEE_CONDITION_FAILED)
    # note that this may change the representation of the fee. If the original
    # buffer had redundant leading zeroes, they will be stripped
    return [int_to_bytes(fee_int)]
Example #2
0
    async def test_assert_time_relative_exceeds(self, two_nodes):

        full_node_1, full_node_2, server_1, server_2 = two_nodes
        time_relative = 3

        cvp = ConditionWithArgs(ConditionOpcode.ASSERT_SECONDS_RELATIVE, [int_to_bytes(time_relative)])
        dic = {cvp.opcode: [cvp]}
        blocks, spend_bundle1, peer, status, err = await self.condition_tester(two_nodes, dic)

        sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
        assert sb1 is None
        assert status == MempoolInclusionStatus.FAILED
        assert err == Err.ASSERT_SECONDS_RELATIVE_FAILED

        for i in range(0, 4):
            await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(32 * b"0"))

        tx2: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction(spend_bundle1)

        status, err = await respond_transaction(full_node_1, tx2, peer)

        sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
        assert sb1 is spend_bundle1
        assert status == MempoolInclusionStatus.SUCCESS
        assert err is None
Example #3
0
    def test_get_name_puzzle_conditions(self):
        # this tests that extra block or coin data doesn't confuse `get_name_puzzle_conditions`

        gen = block_generator()
        cost, r = run_generator(gen, max_cost=MAX_COST)
        print(r)

        npc_result = get_name_puzzle_conditions(gen,
                                                max_cost=MAX_COST,
                                                cost_per_byte=COST_PER_BYTE,
                                                safe_mode=False)
        assert npc_result.error is None
        assert npc_result.clvm_cost == EXPECTED_COST
        cond_1 = ConditionWithArgs(
            ConditionOpcode.CREATE_COIN,
            [bytes([0] * 31 + [1]), int_to_bytes(500)])
        CONDITIONS = [
            (ConditionOpcode.CREATE_COIN, [cond_1]),
        ]

        npc = NPC(
            coin_name=bytes32.fromhex(
                "e8538c2d14f2a7defae65c5c97f5d4fae7ee64acef7fec9d28ad847a0880fd03"
            ),
            puzzle_hash=bytes32.fromhex(
                "9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2"
            ),
            conditions=CONDITIONS,
        )

        assert npc_result.npc_list == [npc]
Example #4
0
    def generate_unsigned_transaction(
        self,
        amount: uint64,
        new_puzzle_hash: bytes32,
        coin: Coin,
        condition_dic: Dict[ConditionOpcode, List[ConditionWithArgs]],
        fee: int = 0,
        secret_key: Optional[PrivateKey] = None,
    ) -> List[CoinSolution]:
        spends = []
        spend_value = coin.amount
        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 ConditionOpcode.CREATE_COIN not in condition_dic:
            condition_dic[ConditionOpcode.CREATE_COIN] = []

        output = ConditionWithArgs(ConditionOpcode.CREATE_COIN, [new_puzzle_hash, int_to_bytes(amount)])
        condition_dic[output.opcode].append(output)
        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)
            solution = self.make_solution(condition_dic)
        else:
            solution = self.make_solution(condition_dic)

        spends.append(CoinSolution(coin, puzzle, solution))
        return spends
Example #5
0
    async def test_stealing_fee(self, two_nodes):
        reward_ph = WALLET_A.get_new_puzzlehash()
        full_node_1, full_node_2, server_1, server_2 = two_nodes
        blocks = await full_node_1.get_all_full_blocks()
        start_height = blocks[-1].height
        blocks = bt.get_consecutive_blocks(
            5,
            block_list_input=blocks,
            guarantee_transaction_block=True,
            farmer_reward_puzzle_hash=reward_ph,
            pool_reward_puzzle_hash=reward_ph,
        )

        full_node_1, full_node_2, server_1, server_2 = two_nodes
        peer = await connect_and_get_peer(server_1, server_2)

        for block in blocks:
            await full_node_1.full_node.respond_block(
                full_node_protocol.RespondBlock(block))

        await time_out_assert(60, node_height_at_least, True, full_node_1,
                              start_height + 5)

        receiver_puzzlehash = BURN_PUZZLE_HASH

        cvp = ConditionWithArgs(ConditionOpcode.RESERVE_FEE,
                                [int_to_bytes(10)])
        dic = {cvp.opcode: [cvp]}

        fee = 9

        coin_1 = list(blocks[-2].get_included_reward_coins())[0]
        coin_2 = None
        for coin in list(blocks[-1].get_included_reward_coins()):
            if coin.amount == coin_1.amount:
                coin_2 = coin
        spend_bundle1 = generate_test_spend_bundle(coin_1, dic, uint64(fee))

        steal_fee_spendbundle = WALLET_A.generate_signed_transaction(
            coin_1.amount + fee - 4, receiver_puzzlehash, coin_2)

        assert spend_bundle1 is not None
        assert steal_fee_spendbundle is not None

        combined = SpendBundle.aggregate(
            [spend_bundle1, steal_fee_spendbundle])

        assert combined.fees() == 4

        tx1: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction(
            spend_bundle1)

        await full_node_1.respond_transaction(tx1, peer)

        mempool_bundle = full_node_1.full_node.mempool_manager.get_spendbundle(
            spend_bundle1.name())

        assert mempool_bundle is None
def parse_amount(args: SExp, safe_mode: bool) -> List[bytes]:
    amount_int = sanitize_int(args.first(), safe_mode)
    if amount_int < 0:
        raise ValidationError(Err.ASSERT_MY_AMOUNT_FAILED)
    if amount_int >= 2**64:
        raise ValidationError(Err.ASSERT_MY_AMOUNT_FAILED)
    # note that this may change the representation of amount. If the original
    # buffer had redundant leading zeroes, they will be stripped
    return [int_to_bytes(amount_int)]
Example #7
0
    def get_hash(self) -> bytes32:
        # This does not use streamable format for hashing, the amount is
        # serialized using CLVM integer format.

        # Note that int_to_bytes() will prepend a 0 to integers where the most
        # significant bit is set, to encode it as a positive number. This
        # despite "amount" being unsigned. This way, a CLVM program can generate
        # these hashes easily.
        return std_hash(self.parent_coin_info + self.puzzle_hash + int_to_bytes(self.amount))
def parse_height(args: SExp, safe_mode: bool, error_code: Err) -> Optional[List[bytes]]:
    height_int = sanitize_int(args.first(), safe_mode)
    # this condition is inherently satisified, there is no need to keep it
    if height_int < 0:
        return None
    if height_int >= 2 ** 32:
        raise ValidationError(error_code)
    # note that this may change the representation of the height. If the original
    # buffer had redundant leading zeroes, they will be stripped
    return [int_to_bytes(height_int)]
Example #9
0
    async def test_negative_block_index(self, two_nodes):

        full_node_1, full_node_2, server_1, server_2 = two_nodes
        cvp = ConditionWithArgs(ConditionOpcode.ASSERT_HEIGHT_ABSOLUTE, [int_to_bytes(-1)])
        dic = {ConditionOpcode.ASSERT_HEIGHT_ABSOLUTE: [cvp]}
        blocks, spend_bundle1, peer, status, err = await self.condition_tester(two_nodes, dic)
        sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
        assert sb1 is spend_bundle1
        assert status == MempoolInclusionStatus.SUCCESS
        assert err is None
Example #10
0
    async def test_assert_fee_condition(self, two_nodes):

        full_node_1, full_node_2, server_1, server_2 = two_nodes
        cvp = ConditionWithArgs(ConditionOpcode.RESERVE_FEE, [int_to_bytes(10)])
        dic = {cvp.opcode: [cvp]}
        blocks, spend_bundle1, peer, status, err = await self.condition_tester(two_nodes, dic, fee=10)
        mempool_bundle = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())

        assert mempool_bundle is not None
        assert status == MempoolInclusionStatus.SUCCESS
        assert err is None
Example #11
0
    async def test_correct_block_age(self, two_nodes):

        full_node_1, full_node_2, server_1, server_2 = two_nodes
        cvp = ConditionWithArgs(ConditionOpcode.ASSERT_HEIGHT_RELATIVE, [int_to_bytes(1)])
        dic = {cvp.opcode: [cvp]}
        blocks, spend_bundle1, peer, status, err = await self.condition_tester(two_nodes, dic, num_blocks=4)

        sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
        assert sb1 is spend_bundle1
        assert status == MempoolInclusionStatus.SUCCESS
        assert err is None
Example #12
0
    async def test_invalid_block_age(self, two_nodes):

        full_node_1, full_node_2, server_1, server_2 = two_nodes
        cvp = ConditionWithArgs(ConditionOpcode.ASSERT_HEIGHT_RELATIVE, [int_to_bytes(5)])
        dic = {cvp.opcode: [cvp]}
        blocks, spend_bundle1, peer, status, err = await self.condition_tester(two_nodes, dic)
        sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
        assert sb1 is None
        # the transaction may become valid later
        assert status == MempoolInclusionStatus.PENDING
        assert err == Err.ASSERT_HEIGHT_RELATIVE_FAILED
Example #13
0
 async def test_assert_fee_condition_fee_too_large(self, two_nodes):
     full_node_1, full_node_2, server_1, server_2 = two_nodes
     cvp = ConditionWithArgs(ConditionOpcode.RESERVE_FEE, [int_to_bytes(2 ** 64)])
     dic = {cvp.opcode: [cvp]}
     blocks, spend_bundle1, peer, status, err = await self.condition_tester(two_nodes, dic, fee=10)
     assert status == MempoolInclusionStatus.FAILED
     assert err == Err.RESERVE_FEE_CONDITION_FAILED
     blocks = bt.get_consecutive_blocks(
         1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=spend_bundle1
     )
     assert full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name()) is None
     assert (await full_node_1.full_node.blockchain.receive_block(blocks[-1]))[1] == Err.RESERVE_FEE_CONDITION_FAILED
def parse_create_coin(args: SExp, safe_mode: bool) -> List[bytes]:
    puzzle_hash = args.first().atom
    args = args.rest()
    if len(puzzle_hash) != 32:
        raise ValidationError(Err.INVALID_CONDITION)
    amount_int = sanitize_int(args.first(), safe_mode)
    if amount_int >= 2**64:
        raise ValidationError(Err.COIN_AMOUNT_EXCEEDS_MAXIMUM)
    if amount_int < 0:
        raise ValidationError(Err.COIN_AMOUNT_NEGATIVE)
    # note that this may change the representation of amount. If the original
    # buffer had redundant leading zeroes, they will be stripped
    return [puzzle_hash, int_to_bytes(amount_int)]
Example #15
0
    async def test_my_amount_too_large(self, two_nodes):

        full_node_1, full_node_2, server_1, server_2 = two_nodes
        blocks = await full_node_1.get_all_full_blocks()
        cvp = ConditionWithArgs(ConditionOpcode.ASSERT_MY_AMOUNT, [int_to_bytes(2 ** 64)])
        dic = {cvp.opcode: [cvp]}
        blocks, spend_bundle1, peer, status, err = await self.condition_tester(two_nodes, dic)

        sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())

        assert sb1 is None
        assert status == MempoolInclusionStatus.FAILED
        assert err == Err.ASSERT_MY_AMOUNT_FAILED
Example #16
0
    async def test_assert_time_exceeds(self, two_nodes):

        full_node_1, full_node_2, server_1, server_2 = two_nodes
        # 5 seconds should be before the next block
        time_now = full_node_1.full_node.blockchain.get_peak().timestamp + 5

        cvp = ConditionWithArgs(ConditionOpcode.ASSERT_SECONDS_ABSOLUTE, [int_to_bytes(time_now)])
        dic = {cvp.opcode: [cvp]}
        blocks, spend_bundle1, peer, status, err = await self.condition_tester(two_nodes, dic)
        sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
        assert sb1 is spend_bundle1
        assert status == MempoolInclusionStatus.SUCCESS
        assert err is None
Example #17
0
    async def test_assert_time_relative_negative(self, two_nodes):

        full_node_1, full_node_2, server_1, server_2 = two_nodes
        time_relative = -3

        cvp = ConditionWithArgs(ConditionOpcode.ASSERT_SECONDS_RELATIVE, [int_to_bytes(time_relative)])
        dic = {cvp.opcode: [cvp]}
        blocks, spend_bundle1, peer, status, err = await self.condition_tester(two_nodes, dic)

        sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
        assert sb1 is spend_bundle1
        assert status == MempoolInclusionStatus.SUCCESS
        assert err is None
Example #18
0
    async def test_correct_my_amount(self, two_nodes):

        full_node_1, full_node_2, server_1, server_2 = two_nodes
        blocks = await full_node_1.get_all_full_blocks()
        coin = list(blocks[-1].get_included_reward_coins())[0]
        cvp = ConditionWithArgs(ConditionOpcode.ASSERT_MY_AMOUNT, [int_to_bytes(coin.amount)])
        dic = {cvp.opcode: [cvp]}
        blocks, spend_bundle1, peer, status, err = await self.condition_tester(two_nodes, dic, coin=coin)

        sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())

        assert sb1 is spend_bundle1
        assert status == MempoolInclusionStatus.SUCCESS
        assert err is None
Example #19
0
    async def test_invalid_block_index(self, two_nodes):

        full_node_1, full_node_2, server_1, server_2 = two_nodes
        blocks = await full_node_1.get_all_full_blocks()
        start_height = blocks[-1].height
        cvp = ConditionWithArgs(
            ConditionOpcode.ASSERT_HEIGHT_ABSOLUTE,
            [int_to_bytes(start_height + 5)],
        )
        dic = {ConditionOpcode.ASSERT_HEIGHT_ABSOLUTE: [cvp]}
        blocks, spend_bundle1, peer, status, err = await self.condition_tester(two_nodes, dic)
        sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
        assert sb1 is None
        # the transaction may become valid later
        assert status == MempoolInclusionStatus.PENDING
        assert err == Err.ASSERT_HEIGHT_ABSOLUTE_FAILED
Example #20
0
    async def test_assert_fee_condition_wrong_fee(self, two_nodes):
        reward_ph = WALLET_A.get_new_puzzlehash()
        full_node_1, full_node_2, server_1, server_2 = two_nodes
        blocks = await full_node_1.get_all_full_blocks()
        start_height = blocks[-1].height
        blocks = bt.get_consecutive_blocks(
            3,
            block_list_input=blocks,
            guarantee_transaction_block=True,
            farmer_reward_puzzle_hash=reward_ph,
            pool_reward_puzzle_hash=reward_ph,
        )
        peer = await connect_and_get_peer(server_1, server_2)

        for block in blocks:
            await full_node_1.full_node.respond_block(
                full_node_protocol.RespondBlock(block))

        await time_out_assert(60, node_height_at_least, True, full_node_1,
                              start_height + 3)

        cvp = ConditionWithArgs(ConditionOpcode.RESERVE_FEE,
                                [int_to_bytes(10)])
        dic = {cvp.opcode: [cvp]}

        spend_bundle1 = generate_test_spend_bundle(
            list(blocks[-1].get_included_reward_coins())[0], dic, uint64(9))

        assert spend_bundle1 is not None

        tx1: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction(
            spend_bundle1)

        await full_node_1.respond_transaction(tx1, peer)

        mempool_bundle = full_node_1.full_node.mempool_manager.get_spendbundle(
            spend_bundle1.name())

        assert mempool_bundle is None
Example #21
0
 def __bytes__(self):
     return self.parent_coin_info + self.puzzle_hash + int_to_bytes(self.amount)
    async def test_full_block_performance(self, wallet_nodes):
        full_node_1, server_1, wallet_a, wallet_receiver = wallet_nodes
        blocks = await full_node_1.get_all_full_blocks()
        full_node_1.full_node.mempool_manager.limit_factor = 1

        wallet_ph = wallet_a.get_new_puzzlehash()
        blocks = bt.get_consecutive_blocks(
            10,
            block_list_input=blocks,
            guarantee_transaction_block=True,
            farmer_reward_puzzle_hash=wallet_ph,
            pool_reward_puzzle_hash=wallet_ph,
        )
        for block in blocks:
            await full_node_1.full_node.respond_block(fnp.RespondBlock(block))

        start_height = (full_node_1.full_node.blockchain.get_peak().height
                        if full_node_1.full_node.blockchain.get_peak()
                        is not None else -1)
        incoming_queue, node_id = await add_dummy_connection(server_1, 12312)
        fake_peer = server_1.all_connections[node_id]
        # Mempool has capacity of 100, make 110 unspents that we can use
        puzzle_hashes = []

        # Makes a bunch of coins
        for i in range(20):
            conditions_dict: Dict = {ConditionOpcode.CREATE_COIN: []}
            # This should fit in one transaction
            for _ in range(100):
                receiver_puzzlehash = wallet_receiver.get_new_puzzlehash()
                puzzle_hashes.append(receiver_puzzlehash)
                output = ConditionWithArgs(
                    ConditionOpcode.CREATE_COIN,
                    [receiver_puzzlehash,
                     int_to_bytes(100000000)])

                conditions_dict[ConditionOpcode.CREATE_COIN].append(output)

            spend_bundle = wallet_a.generate_signed_transaction(
                100,
                puzzle_hashes[0],
                get_future_reward_coins(blocks[1 + i])[0],
                condition_dic=conditions_dict,
            )
            assert spend_bundle is not None

            respond_transaction_2 = fnp.RespondTransaction(spend_bundle)
            await full_node_1.respond_transaction(respond_transaction_2,
                                                  fake_peer)

            blocks = bt.get_consecutive_blocks(
                1,
                block_list_input=blocks,
                guarantee_transaction_block=True,
                transaction_data=spend_bundle,
            )
            await full_node_1.full_node.respond_block(
                fnp.RespondBlock(blocks[-1]), fake_peer)

        await time_out_assert(10, node_height_at_least, True, full_node_1,
                              start_height + 20)

        spend_bundles = []
        spend_bundle_ids = []

        # Fill mempool
        for puzzle_hash in puzzle_hashes[1:]:
            coin_record = (await full_node_1.full_node.coin_store.
                           get_coin_records_by_puzzle_hash(True,
                                                           puzzle_hash))[0]
            receiver_puzzlehash = wallet_receiver.get_new_puzzlehash()
            if puzzle_hash == puzzle_hashes[-1]:
                fee = 100000000  # 100 million (20 fee per cost)
            else:
                fee = random.randint(1, 100000000)
            spend_bundle = wallet_receiver.generate_signed_transaction(
                uint64(500), receiver_puzzlehash, coin_record.coin, fee=fee)
            spend_bundles.append(spend_bundle)
            spend_bundle_ids.append(spend_bundle.get_hash())

        pr = cProfile.Profile()
        pr.enable()

        start = time.time()
        num_tx: int = 0
        for spend_bundle, spend_bundle_id in zip(spend_bundles,
                                                 spend_bundle_ids):
            num_tx += 1
            respond_transaction = fnp.RespondTransaction(spend_bundle)

            await full_node_1.respond_transaction(respond_transaction,
                                                  fake_peer)

            request = fnp.RequestTransaction(spend_bundle_id)
            req = await full_node_1.request_transaction(request)

            if req is None:
                break
        log.warning(f"Num Tx: {num_tx}")
        log.warning(f"Time for mempool: {time.time() - start}")
        pr.create_stats()
        pr.dump_stats("./mempool-benchmark.pstats")

        # Create an unfinished block
        peak = full_node_1.full_node.blockchain.get_peak()
        assert peak is not None
        curr: BlockRecord = peak
        while not curr.is_transaction_block:
            curr = full_node_1.full_node.blockchain.block_record(
                curr.prev_hash)
        mempool_bundle = await full_node_1.full_node.mempool_manager.create_bundle_from_mempool(
            curr.header_hash)
        if mempool_bundle is None:
            spend_bundle = None
        else:
            spend_bundle = mempool_bundle[0]

        current_blocks = await full_node_1.get_all_full_blocks()
        blocks = bt.get_consecutive_blocks(
            1,
            transaction_data=spend_bundle,
            block_list_input=current_blocks,
            guarantee_transaction_block=True,
        )
        block = blocks[-1]
        unfinished = UnfinishedBlock(
            block.finished_sub_slots,
            block.reward_chain_block.get_unfinished(),
            block.challenge_chain_sp_proof,
            block.reward_chain_sp_proof,
            block.foliage,
            block.foliage_transaction_block,
            block.transactions_info,
            block.transactions_generator,
            [],
        )

        pr = cProfile.Profile()
        pr.enable()

        start = time.time()
        res = await full_node_1.respond_unfinished_block(
            fnp.RespondUnfinishedBlock(unfinished), fake_peer)
        log.warning(f"Res: {res}")
        log.warning(f"Time for unfinished: {time.time() - start}")

        pr.create_stats()
        pr.dump_stats("./unfinished-benchmark.pstats")

        pr = cProfile.Profile()
        pr.enable()

        start = time.time()
        # No transactions generator, the full node already cached it from the unfinished block
        block_small = dataclasses.replace(block, transactions_generator=None)
        res = await full_node_1.full_node.respond_block(
            fnp.RespondBlock(block_small))
        log.warning(f"Res: {res}")
        log.warning(f"Time for full block: {time.time() - start}")

        pr.create_stats()
        pr.dump_stats("./full-block-benchmark.pstats")
Example #23
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