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

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

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

        log.info(f"Time spent: {duration}")
        assert duration < 3
示例#2
0
    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
示例#3
0
def puzzle():
    # public key --> puzzle
    pb = "b95e11eccf667b4312588094db0725257f4ce440835d808ed749c9ec39dc5c3afbfdfda7bbf24f2adb58335e848a7a94"
    g: G1Element = G1Element.from_bytes(bytes.fromhex(pb))
    puzzle = puzzle_for_pk(g)
    h = "ff02ffff01ff02ffff01ff02ffff03ff0bffff01ff02ffff03ffff09ff05ffff1dff0bffff1effff0bff0bffff02ff06ffff04ff02ffff04ff17ff8080808080808080ffff01ff02ff17ff2f80ffff01ff088080ff0180ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff17ff80808080ff80808080ffff02ff17ff2f808080ff0180ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080ffff04ffff01b0a76f5e6a0fdb34124b18b492de6cb6ba637571df77c7e8be29a8e9127c4b94cee5cf385ad0c867b67d762fece5993a7eff018080"
    return str(puzzle) == h
示例#4
0
    def __init__(self, parent, name, pk, priv):
        """Internal use constructor, use Network::make_wallet

        Fields:
        parent - The Network object that created this Wallet
        name - The textural name of the actor
        pk_ - The actor's public key
        sk_ - The actor's private key
        usable_coins - Standard coins spendable by this actor
        puzzle - A program for creating this actor's standard coin
        puzzle_hash - The puzzle hash for this actor's standard coin
        pk_to_sk_dict - a dictionary for retrieving the secret keys when presented with the corresponding public key
        """
        self.parent = parent
        self.name = name
        self.pk_ = pk
        self.sk_ = priv
        self.usable_coins = {}
        self.puzzle = puzzle_for_pk(self.pk())
        self.puzzle_hash = self.puzzle.get_tree_hash()

        synth_sk = calculate_synthetic_secret_key(self.sk_,
                                                  DEFAULT_HIDDEN_PUZZLE_HASH)
        self.pk_to_sk_dict = {
            str(self.pk_): self.sk_,
            str(synth_sk.get_g1()): synth_sk
        }
示例#5
0
def puzzHash(pk):
    child_sk: PrivateKey = PrivateKey.from_bytes(bytes.fromhex(pk))
    child_public_key = child_sk.get_g1()
    puzzle = puzzle_for_pk(child_public_key)
    puzzle_hash = puzzle.get_tree_hash()
    # xch
    address = encode_puzzle_hash(puzzle_hash, "txch")
    return address
示例#6
0
    def get_new_puzzle(self) -> bytes32:
        next_address_index: uint32 = self.get_next_address_index()
        pubkey = master_sk_to_wallet_sk(self.private_key, next_address_index).get_g1()
        self.pubkey_num_lookup[bytes(pubkey)] = next_address_index

        puzzle = puzzle_for_pk(bytes(pubkey))

        self.puzzle_pk_cache[puzzle.get_tree_hash()] = next_address_index
        return puzzle
示例#7
0
def mnemonic():
    # mnemonic = "imitate obvious arch square fan bike thumb hedgehog crystal innocent shoe glare share father romance local size gloom hurt maid denial weapon wave bulb"
    mnemonic = "turn acquire ring mind empower ahead section often habit sick sail mountain pen repair catch drum insect file dry trend venue junk novel laptop"
    seed = mnemonic_to_seed(mnemonic, "")
    master_private_key = AugSchemeMPL.key_gen(seed)
    child_private_key = master_sk_to_wallet_sk(master_private_key, 0)
    child_public_key = child_private_key.get_g1()
    puzzle = puzzle_for_pk(child_public_key)
    puzzle_hash = puzzle.get_tree_hash()
    address = encode_puzzle_hash(puzzle_hash, "txch")
示例#8
0
    async def test_strict_mode(self, rust_checker: bool):
        wallet_tool = bt.get_pool_wallet_tool()
        ph = wallet_tool.get_new_puzzlehash()

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

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

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

        coin_name = npc_result.npc_list[0].coin_name
        error, puzzle, solution = get_puzzle_and_solution_for_coin(
            generator, coin_name, test_constants.MAX_BLOCK_COST_CLVM)
        assert error is None
示例#9
0
def addr(sk):
    b = bytes.fromhex(sk)
    master_private_key = PrivateKey.from_bytes(b)
    child_public_key = master_private_key.get_g1()
    puzzle = puzzle_for_pk(child_public_key)
    puzzle_hash = puzzle.get_tree_hash()
    # xch
    address = encode_puzzle_hash(puzzle_hash, "txch")
    # print(address)
    return "{\"address\":\"" + address + "\", \"pubkey\":\"" + str(
        puzzle_hash) + "\"}"
示例#10
0
 def get_private_key_for_puzzle_hash(self, puzzle_hash: bytes32) -> PrivateKey:
     if puzzle_hash in self.puzzle_pk_cache:
         child = self.puzzle_pk_cache[puzzle_hash]
         private = master_sk_to_wallet_sk(self.private_key, uint32(child))
         #  pubkey = private.get_g1()
         return private
     else:
         for child in range(self.next_address):
             pubkey = master_sk_to_wallet_sk(self.private_key, uint32(child)).get_g1()
             if puzzle_hash == puzzle_for_pk(bytes(pubkey)).get_tree_hash():
                 return master_sk_to_wallet_sk(self.private_key, uint32(child))
     raise ValueError(f"Do not have the keys for puzzle hash {puzzle_hash}")
 def test_standard_puzzle(self):
     coin_spend = CoinSpend(
         COIN,
         puzzle_for_pk(G1Element()),
         SOLUTION,
     )
     compressed = compress_object_with_puzzles(bytes(coin_spend),
                                               LATEST_VERSION)
     assert len(bytes(coin_spend)) > len(compressed)
     assert coin_spend == CoinSpend.from_bytes(
         decompress_object_with_puzzles(compressed))
     self.compression_factors["standard_puzzle"] = len(
         bytes(compressed)) / len(bytes(coin_spend))
 def test_unknown_wrapper(self):
     unknown = Program.to([2, 2, []])  # (a 2 ())
     coin_spend = CoinSpend(
         COIN,
         unknown.curry(puzzle_for_pk(G1Element())),
         SOLUTION,
     )
     compressed = compress_object_with_puzzles(bytes(coin_spend),
                                               LATEST_VERSION)
     assert len(bytes(coin_spend)) > len(compressed)
     assert coin_spend == CoinSpend.from_bytes(
         decompress_object_with_puzzles(compressed))
     self.compression_factors["unknown_and_standard"] = len(
         bytes(compressed)) / len(bytes(coin_spend))
 def test_nesting_puzzles(self):
     coin_spend = CoinSpend(
         COIN,
         construct_cat_puzzle(CAT_MOD,
                              Program.to([]).get_tree_hash(),
                              puzzle_for_pk(G1Element())),
         SOLUTION,
     )
     compressed = compress_object_with_puzzles(bytes(coin_spend),
                                               LATEST_VERSION)
     assert len(bytes(coin_spend)) > len(compressed)
     assert coin_spend == CoinSpend.from_bytes(
         decompress_object_with_puzzles(compressed))
     self.compression_factors["cat_w_standard_puzzle"] = len(
         bytes(compressed)) / len(bytes(coin_spend))
示例#14
0
def tx(info):
    j = json.dumps(info)
    m: Dict = eval(j)
    inputs: List = m.get("inputs")
    outputs: List = m.get("outputs")

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

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

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

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

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

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

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

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

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

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

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

    new_spend_bundle = SpendBundle(spend_bundle.coin_solutions,
                                   aggregate_signature)
    # print(json.dumps(new_spend_bundle.to_json_dict()))
    return json.dumps(new_spend_bundle.to_json_dict())
示例#16
0
def create_puzzlehash_for_pk(pub_key: G1Element) -> bytes32:
    return puzzle_for_pk(pub_key).get_tree_hash()
示例#17
0
 async def get_new_puzzle(self) -> Program:
     dr = await self.wallet_state_manager.get_unused_derivation_record(
         self.id())
     return puzzle_for_pk(bytes(dr.pubkey))
示例#18
0
 async def puzzle_for_puzzle_hash(self, puzzle_hash: bytes32) -> Program:
     public_key = await self.hack_populate_secret_key_for_puzzle_hash(
         puzzle_hash)
     return puzzle_for_pk(bytes(public_key))
示例#19
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()
示例#20
0
    def test_pool_lifecycle(self):
        # START TESTS
        # Generate starting info
        key_lookup = KeyTool()
        sk: PrivateKey = PrivateKey.from_bytes(
            secret_exponent_for_index(1).to_bytes(32, "big"), )
        pk: G1Element = G1Element.from_bytes(
            public_key_for_index(1, key_lookup))
        starting_puzzle: Program = puzzle_for_pk(pk)
        starting_ph: bytes32 = starting_puzzle.get_tree_hash()

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

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

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

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

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

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

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

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

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

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

        # ABSORB ONCE MORE FOR GOOD MEASURE
        time = CoinTimestamp(20000000, 10005)
        # create the farming  reward
        coin_db.farm_coin(p2_singleton_ph, time, 1750000000000)
        coin_sols: List[CoinSolution] = create_absorb_spend(
            return_coinsol,
            pool_state,
            launcher_coin,
            10005,
            GENESIS_CHALLENGE,
            DELAY_TIME,
            DELAY_PH,  # height
        )
        # Spend it!
        coin_db.update_coin_store_for_spend_bundle(
            SpendBundle(coin_sols, G2Element()),
            time,
            DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM,
        )
示例#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
示例#22
0
def sign_tx(intermediate_sk: PrivateKey, spend_bundle: SpendBundle,
            use_hardened_keys: bool):
    """
    Takes in an unsigned transaction (called a spend bundle in chia), and a 24 word mnemonic (master sk)
    and generates the aggregate BLS signature for the transaction.
    """

    # This field is the ADDITIONAL_DATA found in the constants
    additional_data: bytes = bytes.fromhex(
        "ccd5bb71183532bff220ba46c268991a3ff07eb358e8255a65c30a2dce0e5fbb")
    puzzle_hash_to_sk: Dict[bytes32, PrivateKey] = {}

    if use_hardened_keys:
        # Change this loop to scan more keys if you have more
        for i in range(5000):
            child_sk: PrivateKey = AugSchemeMPL.derive_child_sk(
                intermediate_sk, i)
            child_pk: G1Element = child_sk.get_g1()
            puzzle = puzzle_for_pk(child_pk)
            puzzle_hash = puzzle.get_tree_hash()
            puzzle_hash_to_sk[puzzle_hash] = child_sk
    else:
        # Change this loop to scan more keys if you have more
        for i in range(5000):
            child_sk: PrivateKey = AugSchemeMPL.derive_child_sk_unhardened(
                intermediate_sk, i)
            child_pk: G1Element = child_sk.get_g1()
            puzzle = puzzle_for_pk(child_pk)
            puzzle_hash = puzzle.get_tree_hash()
            puzzle_hash_to_sk[puzzle_hash] = child_sk

    aggregate_signature: G2Element = G2Element()
    for coin_solution in spend_bundle.coin_solutions:
        if coin_solution.coin.puzzle_hash not in puzzle_hash_to_sk:
            print(
                f"Puzzle hash {coin_solution.coin.puzzle_hash} not found for this key."
            )
            return
        sk: PrivateKey = puzzle_hash_to_sk[coin_solution.coin.puzzle_hash]
        synthetic_secret_key: PrivateKey = calculate_synthetic_secret_key(
            sk, DEFAULT_HIDDEN_PUZZLE_HASH)

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

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

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

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

    new_spend_bundle = SpendBundle(spend_bundle.coin_solutions,
                                   aggregate_signature)
    print("")
    print("Signed spend bundle JSON:\n")
    print(json.dumps(new_spend_bundle.to_json_dict()))
示例#23
0
def puzzle_hash_for_index(index: int, puzzle_hash_db: dict) -> bytes:
    public_key = bytes(int_to_public_key(index))
    puzzle = puzzle_for_pk(public_key)
    puzzle_hash = puzzle.get_tree_hash()
    puzzle_hash_db[puzzle_hash] = puzzle
    return puzzle_hash
示例#24
0
 def puzzle_for_pk(self, pubkey: bytes) -> Program:
     return puzzle_for_pk(pubkey)
    def test_singleton_top_layer(self):
        # 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
        coin_db = CoinStore()
        coin_db.farm_coin(starting_puzzle.get_tree_hash(), T1, START_AMOUNT)
        starting_coin: Coin = next(coin_db.all_unspent_coins())
        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 = CoinSolution(
            starting_coin,
            starting_puzzle,
            full_solution,
        )

        make_and_spend_bundle(
            coin_db,
            starting_coin,
            delegated_puzzle,
            [starting_coinsol, launcher_coinsol],
        )

        # EVE
        singleton_eve: Coin = next(coin_db.all_unspent_coins())
        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 = CoinSolution(
            singleton_eve,
            puzzle_reveal,
            full_solution,
        )

        make_and_spend_bundle(
            coin_db,
            singleton_eve,
            delegated_puzzle,
            [singleton_eve_coinsol],
        )

        # POST-EVE
        singleton: Coin = next(coin_db.all_unspent_coins())
        # 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 = CoinSolution(
            singleton,
            puzzle_reveal,
            full_solution,
        )

        make_and_spend_bundle(
            coin_db,
            singleton,
            delegated_puzzle,
            [singleton_coinsol],
        )

        # CLAIM A P2_SINGLETON
        singleton_child: Coin = next(coin_db.all_unspent_coins())
        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
        coin_db.farm_coin(p2_singleton_ph, T1, ARBITRARY_AMOUNT)
        p2_singleton_coin: Coin = list(
            filter(
                lambda e: e.amount == ARBITRARY_AMOUNT,
                list(coin_db.all_unspent_coins()),
            ))[0]
        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 = CoinSolution(
            singleton_child,
            puzzle_reveal,
            full_solution,
        )

        make_and_spend_bundle(coin_db, singleton_child, delegated_puzzle,
                              [singleton_claim_coinsol, claim_coinsol])

        # CLAIM A P2_SINGLETON_OR_DELAYED
        singleton_child: Coin = next(coin_db.all_unspent_coins())
        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
        coin_db.farm_coin(p2_singleton_ph, T1, ARBITRARY_AMOUNT)
        p2_singleton_coin: Coin = list(
            filter(
                lambda e: e.amount == ARBITRARY_AMOUNT,
                list(coin_db.all_unspent_coins()),
            ))[0]
        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,
        )
        delay_claim_coinsol = CoinSolution(
            singleton_child,
            puzzle_reveal,
            full_solution,
        )

        # Fork it so we can try the other spend types
        fork_coin_db: CoinStore = copy.deepcopy(coin_db)
        fork_coin_db_2: CoinStore = copy.deepcopy(coin_db)
        make_and_spend_bundle(coin_db, singleton_child, delegated_puzzle,
                              [delay_claim_coinsol, claim_coinsol])

        # TRY TO SPEND AWAY TOO SOON (Negative Test)
        to_delay_ph_coinsol = singleton_top_layer.spend_to_delayed_puzzle(
            p2_singleton_coin,
            ARBITRARY_AMOUNT,
            launcher_id,
            DELAY_TIME,
            DELAY_PH,
        )
        try:
            fork_coin_db.update_coin_store_for_spend_bundle(
                SpendBundle([to_delay_ph_coinsol], G2Element()),
                T1,
                DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM,
            )
        except BadSpendBundleError as e:
            assert str(
                e
            ) == "condition validation failure Err.ASSERT_SECONDS_RELATIVE_FAILED"

        # SPEND TO DELAYED PUZZLE HASH
        fork_coin_db_2.update_coin_store_for_spend_bundle(
            SpendBundle([to_delay_ph_coinsol], G2Element()),
            CoinTimestamp(100, 10000005),
            DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM,
        )

        # CREATE MULTIPLE ODD CHILDREN (Negative Test)
        singleton_child: Coin = next(coin_db.all_unspent_coins())
        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_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_child.amount, inner_solution)

        multi_odd_coinsol = CoinSolution(
            singleton_child,
            puzzle_reveal,
            full_solution,
        )

        make_and_spend_bundle(
            coin_db,
            singleton_child,
            delegated_puzzle,
            [multi_odd_coinsol],
            exception=BadSpendBundleError,
            ex_msg="clvm validation failure Err.SEXP_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_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_child.amount, inner_solution)

        no_odd_coinsol = CoinSolution(
            singleton_child,
            puzzle_reveal,
            full_solution,
        )

        make_and_spend_bundle(
            coin_db,
            singleton_child,
            delegated_puzzle,
            [no_odd_coinsol],
            exception=BadSpendBundleError,
            ex_msg="clvm validation failure Err.SEXP_ERROR",
            fail_msg="Need at least one odd child",
        )

        # ATTEMPT TO CREATE AN EVEN SINGLETON (Negative test)
        fork_coin_db: CoinStore = copy.deepcopy(coin_db)

        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(
            delay_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 = CoinSolution(
            singleton_child,
            puzzle_reveal,
            full_solution,
        )

        make_and_spend_bundle(
            fork_coin_db,
            singleton_child,
            delegated_puzzle,
            [singleton_even_coinsol],
        )

        # Now try a perfectly innocent spend
        evil_coin: Coin = next(fork_coin_db.all_unspent_coins())
        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 = CoinSolution(
            evil_coin,
            puzzle_reveal,
            full_solution,
        )

        make_and_spend_bundle(
            fork_coin_db,
            evil_coin,
            delegated_puzzle,
            [evil_coinsol],
            exception=BadSpendBundleError,
            ex_msg="condition validation failure Err.ASSERT_MY_COIN_ID_FAILED",
            fail_msg="This coin is even!",
        )

        # MELTING
        # Remember, we're still spending singleton_child
        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(
            delay_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 = CoinSolution(
            singleton_child,
            puzzle_reveal,
            full_solution,
        )

        make_and_spend_bundle(
            coin_db,
            singleton_child,
            delegated_puzzle,
            [melt_coinsol],
        )

        melted_coin = next(coin_db.all_unspent_coins())
        assert melted_coin.puzzle_hash == adapted_puzzle_hash