Esempio n. 1
0
    async def load_attest_files_for_recovery_spend(self, filenames):
        spend_bundle_list = []
        info_dict = {}
        try:
            for i in filenames:
                f = open(i)
                info = f.read().split(":")
                info_dict[info[0]] = [
                    bytes.fromhex(info[2]),
                    bytes.fromhex(info[3]),
                    uint64(info[4]),
                ]

                new_sb = SpendBundle.from_bytes(bytes.fromhex(info[1]))
                spend_bundle_list.append(new_sb)
                f.close()
            # info_dict {0xidentity: "(0xparent_info 0xinnerpuz amount)"}
            my_recovery_list: List[bytes] = self.did_info.backup_ids

            # convert info dict into recovery list - same order as wallet
            info_list = []
            for entry in my_recovery_list:
                if entry.hex() in info_dict:
                    info_list.append([
                        info_dict[entry.hex()][0],
                        info_dict[entry.hex()][1],
                        info_dict[entry.hex()][2],
                    ])
                else:
                    info_list.append([])
            message_spend_bundle = SpendBundle.aggregate(spend_bundle_list)
            return info_list, message_spend_bundle
        except Exception:
            raise
Esempio n. 2
0
    def to_spend_bundle(self) -> SpendBundle:
        # Before we serialze this as a SpendBundle, we need to serialze the `requested_payments` as dummy CoinSpends
        additional_coin_spends: List[CoinSpend] = []
        for tail_hash, payments in self.requested_payments.items():
            puzzle_reveal: Program = construct_cat_puzzle(
                CAT_MOD, tail_hash, OFFER_MOD) if tail_hash else OFFER_MOD
            inner_solutions = []
            nonces: List[bytes32] = [p.nonce for p in payments]
            for nonce in list(
                    dict.fromkeys(nonces)):  # dedup without messing with order
                nonce_payments: List[NotarizedPayment] = list(
                    filter(lambda p: p.nonce == nonce, payments))
                inner_solutions.append(
                    (nonce, [np.as_condition_args() for np in nonce_payments]))

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

        return SpendBundle.aggregate([
            SpendBundle(additional_coin_spends, G2Element()),
            self.bundle,
        ])
Esempio n. 3
0
    def aggregate(cls, offers: List["Offer"]) -> "Offer":
        total_requested_payments: Dict[Optional[bytes32],
                                       List[NotarizedPayment]] = {}
        total_bundle = SpendBundle([], G2Element())
        for offer in offers:
            # First check for any overlap in inputs
            total_inputs: Set[Coin] = {
                cs.coin
                for cs in total_bundle.coin_spends
            }
            offer_inputs: Set[Coin] = {
                cs.coin
                for cs in offer.bundle.coin_spends
            }
            if total_inputs & offer_inputs:
                raise ValueError("The aggregated offers overlap inputs")

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

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

        return cls(total_requested_payments, total_bundle)
Esempio n. 4
0
    async def sign(self, spend_bundle: SpendBundle) -> SpendBundle:
        sigs: List[G2Element] = []
        for spend in spend_bundle.coin_spends:
            matched, puzzle_args = match_cat_puzzle(
                spend.puzzle_reveal.to_program())
            if matched:
                _, _, inner_puzzle = puzzle_args
                puzzle_hash = inner_puzzle.get_tree_hash()
                pubkey, private = await self.wallet_state_manager.get_keys(
                    puzzle_hash)
                synthetic_secret_key = calculate_synthetic_secret_key(
                    private, DEFAULT_HIDDEN_PUZZLE_HASH)
                error, conditions, cost = conditions_dict_for_solution(
                    spend.puzzle_reveal.to_program(),
                    spend.solution.to_program(),
                    self.wallet_state_manager.constants.MAX_BLOCK_COST_CLVM,
                )
                if conditions is not None:
                    synthetic_pk = synthetic_secret_key.get_g1()
                    for pk, msg in pkm_pairs_for_conditions_dict(
                            conditions, spend.coin.name(),
                            self.wallet_state_manager.constants.
                            AGG_SIG_ME_ADDITIONAL_DATA):
                        try:
                            assert bytes(synthetic_pk) == pk
                            sigs.append(
                                AugSchemeMPL.sign(synthetic_secret_key, msg))
                        except AssertionError:
                            raise ValueError(
                                "This spend bundle cannot be signed by the CAT wallet"
                            )

        agg_sig = AugSchemeMPL.aggregate(sigs)
        return SpendBundle.aggregate([spend_bundle, SpendBundle([], agg_sig)])
Esempio n. 5
0
    async def create_spend(self, puzhash: bytes32):
        assert self.did_info.current_inner is not None
        coins = await self.select_coins(1)
        assert coins is not None
        coin = coins.pop()
        # innerpuz solution is (mode amount new_puz identity my_puz)
        innersol: Program = Program.to([0, coin.amount, puzhash, coin.name(), coin.puzzle_hash])
        # full solution is (corehash parent_info my_amount innerpuz_reveal solution)
        innerpuz: Program = self.did_info.current_inner

        full_puzzle: Program = did_wallet_puzzles.create_fullpuz(
            innerpuz,
            self.did_info.my_did,
        )
        parent_info = await self.get_parent_for_coin(coin)
        assert parent_info is not None

        fullsol = Program.to(
            [
                [
                    parent_info.parent_name,
                    parent_info.inner_puzzle_hash,
                    parent_info.amount,
                ],
                coin.amount,
                innersol,
            ]
        )
        list_of_solutions = [CoinSolution(coin, full_puzzle, fullsol)]
        # sign for AGG_SIG_ME
        message = bytes(puzhash) + bytes(coin.name())
        pubkey = did_wallet_puzzles.get_pubkey_from_innerpuz(innerpuz)
        index = await self.wallet_state_manager.puzzle_store.index_for_pubkey(pubkey)
        private = master_sk_to_wallet_sk(self.wallet_state_manager.private_key, index)
        signature = AugSchemeMPL.sign(private, message)
        # assert signature.validate([signature.PkMessagePair(pubkey, message)])
        sigs = [signature]
        aggsig = AugSchemeMPL.aggregate(sigs)
        spend_bundle = SpendBundle(list_of_solutions, aggsig)

        did_record = TransactionRecord(
            confirmed_at_height=uint32(0),
            created_at_time=uint64(int(time.time())),
            to_puzzle_hash=puzhash,
            amount=uint64(coin.amount),
            fee_amount=uint64(0),
            confirmed=False,
            sent=uint32(0),
            spend_bundle=spend_bundle,
            additions=spend_bundle.additions(),
            removals=spend_bundle.removals(),
            wallet_id=self.wallet_info.id,
            sent_to=[],
            trade_id=None,
            type=uint32(TransactionType.OUTGOING_TX.value),
            name=token_bytes(),
        )
        await self.standard_wallet.push_transaction(did_record)
        return spend_bundle
Esempio n. 6
0
async def main() -> None:
    rpc_port: uint16 = uint16(8555)
    self_hostname = "localhost"
    path = DEFAULT_ROOT_PATH
    config = load_config(path, "config.yaml")
    client = await FullNodeRpcClient.create(self_hostname, rpc_port, path,
                                            config)
    try:
        farmer_prefarm = (
            await
            client.get_block_record_by_height(1)).reward_claims_incorporated[1]
        pool_prefarm = (
            await
            client.get_block_record_by_height(1)).reward_claims_incorporated[0]

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

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

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

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

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

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

        print(res)
        up = await client.get_coin_records_by_puzzle_hash(
            farmer_prefarm.puzzle_hash, True)
        uf = await client.get_coin_records_by_puzzle_hash(
            pool_prefarm.puzzle_hash, True)
        print(up)
        print(uf)
    finally:
        client.close()
Esempio n. 7
0
 def update_coin_store_for_spend_bundle(self, spend_bundle: SpendBundle, now: CoinTimestamp):
     err = self.validate_spend_bundle(spend_bundle, now)
     if err != 0:
         raise BadSpendBundleError(f"validation failure {err}")
     for spent_coin in spend_bundle.removals():
         coin_name = spent_coin.name()
         coin_record = self._db[coin_name]
         self._db[coin_name] = replace(coin_record, spent_block_index=now.height, spent=True)
     for new_coin in spend_bundle.additions():
         self._add_coin_entry(new_coin, now)
Esempio n. 8
0
    async def do_spend(
        self,
        sim: SpendSim,
        sim_client: SimClient,
        tail: Program,
        coins: List[Coin],
        lineage_proofs: List[Program],
        inner_solutions: List[Program],
        expected_result: Tuple[MempoolInclusionStatus, Err],
        reveal_limitations_program: bool = True,
        signatures: List[G2Element] = [],
        extra_deltas: Optional[List[int]] = None,
        additional_spends: List[SpendBundle] = [],
        limitations_solutions: Optional[List[Program]] = None,
        cost_str: str = "",
    ):
        if limitations_solutions is None:
            limitations_solutions = [Program.to([])] * len(coins)
        if extra_deltas is None:
            extra_deltas = [0] * len(coins)

        spendable_cat_list: List[SpendableCAT] = []
        for coin, innersol, proof, limitations_solution, extra_delta in zip(
            coins, inner_solutions, lineage_proofs, limitations_solutions, extra_deltas
        ):
            spendable_cat_list.append(
                SpendableCAT(
                    coin,
                    tail.get_tree_hash(),
                    acs,
                    innersol,
                    limitations_solution=limitations_solution,
                    lineage_proof=proof,
                    extra_delta=extra_delta,
                    limitations_program_reveal=tail if reveal_limitations_program else Program.to([]),
                )
            )

        spend_bundle: SpendBundle = unsigned_spend_bundle_for_spendable_cats(
            CAT_MOD,
            spendable_cat_list,
        )
        agg_sig = AugSchemeMPL.aggregate(signatures)
        result = await sim_client.push_tx(
            SpendBundle.aggregate(
                [
                    *additional_spends,
                    spend_bundle,
                    SpendBundle([], agg_sig),  # "Signing" the spend bundle
                ]
            )
        )
        assert result == expected_result
        self.cost[cost_str] = cost_of_spend_bundle(spend_bundle)
        await sim.farm_block()
Esempio n. 9
0
 async def push_tx(self, spend_bundle: SpendBundle) -> Tuple[MempoolInclusionStatus, Optional[Err]]:
     try:
         cost_result: NPCResult = await self.service.mempool_manager.pre_validate_spendbundle(
             spend_bundle, None, spend_bundle.name()
         )
     except ValidationError as e:
         return MempoolInclusionStatus.FAILED, e.code
     cost, status, error = await self.service.mempool_manager.add_spendbundle(
         spend_bundle, cost_result, spend_bundle.name()
     )
     return status, error
def test_only_odd_coins_0():
    blocks = initial_blocks()
    farmed_coin = list(blocks[-1].get_included_reward_coins())[0]

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

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

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

    launcher_coin = launcher_spend_bundle.coin_solutions[0].coin

    assert launcher_coin in coin_set_added
    assert launcher_coin in coin_set_removed

    assert farmed_coin in coin_set_removed
    # breakpoint()

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

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

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

    # then, destroy the singleton with the -113 hack

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

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

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

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

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

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

    launcher_coin = launcher_spend_bundle.coin_spends[0].coin

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

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

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

    if print_results:
        inspect_callback(spend_bundle_objs,
                         ctx,
                         id_calc=(lambda e: e.name()),
                         type='SpendBundle')
    else:
        return spend_bundle_objs
def make_and_spend_bundle(
    db: CoinStore,
    coin: Coin,
    delegated_puzzle: Program,
    coinsols: List[CoinSolution],
    exception: Optional[Exception] = None,
    ex_msg: str = "",
    fail_msg: str = "",
):

    signature: G2Element = sign_delegated_puz(delegated_puzzle, coin)
    spend_bundle = SpendBundle(
        coinsols,
        signature,
    )

    try:
        db.update_coin_store_for_spend_bundle(
            spend_bundle,
            T1,
            DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM,
        )
        if exception is not None:
            raise AssertionError(fail_msg)
    except Exception as e:
        if exception is not None:
            assert type(e) is exception
            assert str(e) == ex_msg
        else:
            raise e
Esempio n. 14
0
def issue_cc_from_farmed_coin(
    mod_code: Program,
    coin_checker_for_farmed_coin,
    block_id: int,
    inner_puzzle_hash: bytes32,
    amount: int,
) -> Tuple[Program, SpendBundle]:
    """
    This is an example of how to issue a cc.
    """
    # get a farmed coin

    farmed_puzzle = ANYONE_CAN_SPEND_PUZZLE
    farmed_puzzle_hash = farmed_puzzle.get_tree_hash()

    # mint a cc

    farmed_coin = generate_farmed_coin(block_id, farmed_puzzle_hash, amount=uint64(amount))
    genesis_coin_checker = coin_checker_for_farmed_coin(farmed_coin)

    minted_cc_puzzle_hash = cc_puzzle_hash_for_inner_puzzle_hash(mod_code, genesis_coin_checker, inner_puzzle_hash)

    output_conditions = [[ConditionOpcode.CREATE_COIN, minted_cc_puzzle_hash, farmed_coin.amount]]

    # for this very simple puzzle, the solution is simply the output conditions
    # this is just a coincidence... for more complicated puzzles, you'll likely have to do some real work

    solution = Program.to(output_conditions)
    coin_spend = CoinSpend(farmed_coin, farmed_puzzle, solution)
    spend_bundle = SpendBundle([coin_spend], NULL_SIGNATURE)
    return genesis_coin_checker, spend_bundle
Esempio n. 15
0
def main():
    # Mnemonics can be generated using `chia keys generate_and_print`, or `chia keys generate`. The latter stored
    # the key in the OS keychain (unencrypted file if linux).
    mnemonic: str = "neither medal holiday echo link dog sleep idea turkey logic security sword save taxi chapter artwork toddler wealth local mind manual never unlock narrow"

    seed: bytes = mnemonic_to_seed(mnemonic, passphrase="")
    master_private_key: PrivateKey = AugSchemeMPL.key_gen(seed)
    intermediate_sk: PrivateKey = AugSchemeMPL.derive_child_sk(
        master_private_key, 12381)
    intermediate_sk = AugSchemeMPL.derive_child_sk(intermediate_sk, 8444)
    intermediate_sk = AugSchemeMPL.derive_child_sk(intermediate_sk, 2)
    print(
        f"Parent public key is: {intermediate_sk.get_g1()}. Please use this within `create_unsigned_tx.py`"
    )

    # If you want to use hardened keys which are more secure against quantum computers, you need to export
    # The public keys
    # create_hardened_child_public_keys(mnemonic, 1000)

    try:
        with open("tx_3.json", "r") as f:
            spend_bundle_json = f.read()
    except Exception:
        print(
            "Error: create your transaction (spend bundle) json and put it into the json file."
        )
        return

    spend_bundle_json_dict: Dict = json.loads(spend_bundle_json)
    spend_bundle: SpendBundle = SpendBundle.from_json_dict(
        spend_bundle_json_dict)

    sign_tx(intermediate_sk, spend_bundle, use_hardened_keys=False)
Esempio n. 16
0
    def sign_transaction(self,
                         coin_solutions: List[CoinSolution]) -> SpendBundle:
        signatures = []
        solution: Program
        puzzle: Program
        for coin_solution in coin_solutions:  # type: ignore # noqa
            secret_key = self.get_private_key_for_puzzle_hash(
                coin_solution.coin.puzzle_hash)
            synthetic_secret_key = calculate_synthetic_secret_key(
                secret_key, DEFAULT_HIDDEN_PUZZLE_HASH)
            err, con, cost = conditions_for_solution(
                coin_solution.puzzle_reveal, coin_solution.solution,
                self.constants.MAX_BLOCK_COST_CLVM)
            if not con:
                raise ValueError(err)
            conditions_dict = conditions_by_opcode(con)

            for _, msg in pkm_pairs_for_conditions_dict(
                    conditions_dict, bytes(coin_solution.coin.name()),
                    self.constants.AGG_SIG_ME_ADDITIONAL_DATA):
                signature = AugSchemeMPL.sign(synthetic_secret_key, msg)
                signatures.append(signature)
        aggsig = AugSchemeMPL.aggregate(signatures)
        spend_bundle = SpendBundle(coin_solutions, aggsig)
        return spend_bundle
Esempio n. 17
0
    def sign_transaction(self, coin_spends: List[CoinSpend]) -> SpendBundle:
        signatures = []
        solution: Program
        puzzle: Program
        for coin_spend in coin_spends:  # noqa
            secret_key = self.get_private_key_for_puzzle_hash(coin_spend.coin.puzzle_hash)
            synthetic_secret_key = calculate_synthetic_secret_key(secret_key, DEFAULT_HIDDEN_PUZZLE_HASH)
            err, con, cost = conditions_for_solution(
                coin_spend.puzzle_reveal, coin_spend.solution, self.constants.MAX_BLOCK_COST_CLVM
            )
            if not con:
                raise ValueError(err)
            conditions_dict = conditions_by_opcode(con)

            for cwa in conditions_dict.get(ConditionOpcode.AGG_SIG_UNSAFE, []):
                msg = cwa.vars[1]
                signature = AugSchemeMPL.sign(synthetic_secret_key, msg)
                signatures.append(signature)

            for cwa in conditions_dict.get(ConditionOpcode.AGG_SIG_ME, []):
                msg = cwa.vars[1] + bytes(coin_spend.coin.name()) + self.constants.AGG_SIG_ME_ADDITIONAL_DATA
                signature = AugSchemeMPL.sign(synthetic_secret_key, msg)
                signatures.append(signature)

        aggsig = AugSchemeMPL.aggregate(signatures)
        spend_bundle = SpendBundle(coin_spends, aggsig)
        return spend_bundle
Esempio n. 18
0
    async def push_tx(self, request: Dict) -> Optional[Dict]:
        if "spend_bundle" not in request:
            raise ValueError("Spend bundle not in request")

        # This is for backwards compatibility since CoinSolution has been renamed to CoinSpend
        if "coin_solutions" in request["spend_bundle"]:
            request["spend_bundle"]["coin_spends"] = request[
                "spend_bundle"].pop("coin_solutions")

        spend_bundle = SpendBundle.from_json_dict(request["spend_bundle"])
        spend_name = spend_bundle.name()

        if self.service.mempool_manager.get_spendbundle(
                spend_name) is not None:
            status = MempoolInclusionStatus.SUCCESS
            error = None
        else:
            status, error = await self.service.respond_transaction(
                spend_bundle, spend_name)
            if status != MempoolInclusionStatus.SUCCESS:
                if self.service.mempool_manager.get_spendbundle(
                        spend_name) is not None:
                    # Already in mempool
                    status = MempoolInclusionStatus.SUCCESS
                    error = None

        if status == MempoolInclusionStatus.FAILED:
            assert error is not None
            raise ValueError(
                f"Failed to include transaction {spend_name}, error {error.name}"
            )
        return {
            "status": status.name,
        }
Esempio n. 19
0
 async def generate_eve_spend(self, coin: Coin, full_puzzle: Program, innerpuz: Program):
     assert self.did_info.origin_coin is not None
     # innerpuz solution is (mode amount message new_puzhash)
     innersol = Program.to([1, coin.amount, [], innerpuz.get_tree_hash()])
     # full solution is (lineage_proof my_amount inner_solution)
     fullsol = Program.to(
         [
             [self.did_info.origin_coin.parent_coin_info, self.did_info.origin_coin.amount],
             coin.amount,
             innersol,
         ]
     )
     list_of_solutions = [CoinSpend(coin, full_puzzle, fullsol)]
     # sign for AGG_SIG_ME
     message = (
         Program.to([innerpuz.get_tree_hash(), coin.amount, []]).get_tree_hash()
         + coin.name()
         + self.wallet_state_manager.constants.AGG_SIG_ME_ADDITIONAL_DATA
     )
     pubkey = did_wallet_puzzles.get_pubkey_from_innerpuz(innerpuz)
     record: Optional[DerivationRecord] = await self.wallet_state_manager.puzzle_store.record_for_pubkey(pubkey)
     assert record is not None
     private = master_sk_to_wallet_sk_unhardened(self.wallet_state_manager.private_key, record.index)
     signature = AugSchemeMPL.sign(private, message)
     sigs = [signature]
     aggsig = AugSchemeMPL.aggregate(sigs)
     spend_bundle = SpendBundle(list_of_solutions, aggsig)
     return spend_bundle
Esempio n. 20
0
    async def push_tx(self, request: Dict) -> Optional[Dict]:
        if "spend_bundle" not in request:
            raise ValueError("Spend bundle not in request")

        spend_bundle = SpendBundle.from_json_dict(request["spend_bundle"])
        spend_name = spend_bundle.name()

        if self.service.mempool_manager.get_spendbundle(
                spend_name) is not None:
            status = MempoolInclusionStatus.SUCCESS
            error = None
        else:
            status, error = await self.service.respond_transaction(
                spend_bundle, spend_name)
            if status != MempoolInclusionStatus.SUCCESS:
                if self.service.mempool_manager.get_spendbundle(
                        spend_name) is not None:
                    # Already in mempool
                    status = MempoolInclusionStatus.SUCCESS
                    error = None

        if status == MempoolInclusionStatus.FAILED:
            assert error is not None
            raise ValueError(
                f"Failed to include transaction {spend_name}, error {error.name}"
            )
        return {
            "status": status.name,
        }
Esempio n. 21
0
async def sign_coin_solutions(
    coin_solutions: List[CoinSolution],
    secret_key_for_public_key_f: Callable[[bytes], Optional[PrivateKey]],
) -> SpendBundle:
    signatures = []
    pk_list = []
    msg_list = []
    for coin_solution in coin_solutions:
        # Get AGG_SIG conditions
        err, conditions_dict, cost = conditions_dict_for_solution(coin_solution.puzzle_reveal, coin_solution.solution)
        if err or conditions_dict is None:
            error_msg = f"Sign transaction failed, con:{conditions_dict}, error: {err}"
            raise ValueError(error_msg)

        # Create signature
        for _, msg in pkm_pairs_for_conditions_dict(conditions_dict, bytes(coin_solution.coin.name())):
            pk_list.append(_)
            msg_list.append(msg)
            secret_key = secret_key_for_public_key_f(_)
            if secret_key is None:
                e_msg = f"no secret key for {_}"
                raise ValueError(e_msg)
            assert bytes(secret_key.get_g1()) == bytes(_)
            signature = AugSchemeMPL.sign(secret_key, msg)
            assert AugSchemeMPL.verify(_, msg, signature)
            signatures.append(signature)

    # Aggregate signatures
    aggsig = AugSchemeMPL.aggregate(signatures)
    assert AugSchemeMPL.aggregate_verify(pk_list, msg_list, aggsig)
    return SpendBundle(coin_solutions, aggsig)
Esempio n. 22
0
def launcher_conditions_and_spend_bundle(
    parent_coin_id: bytes32,
    launcher_amount: uint64,
    initial_singleton_inner_puzzle: Program,
    metadata: List[Tuple[str, str]],
    launcher_puzzle: Program = LAUNCHER_PUZZLE,
) -> Tuple[Program, bytes32, List[Program], SpendBundle]:
    launcher_puzzle_hash = launcher_puzzle.get_tree_hash()
    launcher_coin = Coin(parent_coin_id, launcher_puzzle_hash, launcher_amount)
    singleton_full_puzzle = SINGLETON_MOD.curry(
        SINGLETON_MOD_HASH, launcher_coin.name(), launcher_puzzle_hash,
        initial_singleton_inner_puzzle)
    singleton_full_puzzle_hash = singleton_full_puzzle.get_tree_hash()
    message_program = Program.to(
        [singleton_full_puzzle_hash, launcher_amount, metadata])
    expected_announcement = Announcement(launcher_coin.name(),
                                         message_program.get_tree_hash())
    expected_conditions = []
    expected_conditions.append(
        Program.to(
            binutils.assemble(
                f"(0x{ConditionOpcode.ASSERT_COIN_ANNOUNCEMENT.hex()} 0x{expected_announcement.name()})"
            )))
    expected_conditions.append(
        Program.to(
            binutils.assemble(
                f"(0x{ConditionOpcode.CREATE_COIN.hex()} 0x{launcher_puzzle_hash} {launcher_amount})"
            )))
    launcher_solution = Program.to(
        [singleton_full_puzzle_hash, launcher_amount, metadata])
    coin_spend = CoinSpend(launcher_coin, launcher_puzzle, launcher_solution)
    spend_bundle = SpendBundle([coin_spend], G2Element())
    lineage_proof = Program.to([parent_coin_id, launcher_amount])
    return lineage_proof, launcher_coin.name(
    ), expected_conditions, spend_bundle
Esempio n. 23
0
 async def generate_eve_spend(self, coin: Coin, full_puzzle: Program,
                              innerpuz: Program):
     assert self.did_info.origin_coin is not None
     # innerpuz solution is (mode amount message my_id my_puzhash parent_innerpuzhash_amounts_for_recovery_ids)
     innersol = Program.to([
         0, coin.amount, coin.puzzle_hash,
         coin.name(), coin.puzzle_hash, []
     ])
     # full solution is (parent_info my_amount innersolution)
     fullsol = Program.to([
         [
             self.did_info.origin_coin.parent_coin_info,
             self.did_info.origin_coin.amount
         ],
         coin.parent_coin_info,
         coin.amount,
         innersol,
     ])
     list_of_solutions = [CoinSolution(coin, full_puzzle, fullsol)]
     # sign for AGG_SIG_ME
     message = (
         Program.to([coin.amount, coin.puzzle_hash]).get_tree_hash() +
         coin.name() +
         self.wallet_state_manager.constants.AGG_SIG_ME_ADDITIONAL_DATA)
     pubkey = did_wallet_puzzles.get_pubkey_from_innerpuz(innerpuz)
     index = await self.wallet_state_manager.puzzle_store.index_for_pubkey(
         pubkey)
     private = master_sk_to_wallet_sk(self.wallet_state_manager.private_key,
                                      index)
     signature = AugSchemeMPL.sign(private, message)
     sigs = [signature]
     aggsig = AugSchemeMPL.aggregate(sigs)
     spend_bundle = SpendBundle(list_of_solutions, aggsig)
     return spend_bundle
Esempio n. 24
0
    def from_spend_bundle(cls, bundle: SpendBundle) -> "Offer":
        # Because of the `to_spend_bundle` method, we need to parse the dummy CoinSpends as `requested_payments`
        requested_payments: Dict[Optional[bytes32],
                                 List[NotarizedPayment]] = {}
        leftover_coin_spends: List[CoinSpend] = []
        for coin_spend in bundle.coin_spends:
            if coin_spend.coin.parent_coin_info == ZERO_32:
                matched, curried_args = match_cat_puzzle(
                    coin_spend.puzzle_reveal.to_program())
                if matched:
                    _, tail_hash_program, _ = curried_args
                    tail_hash: Optional[bytes32] = bytes32(
                        tail_hash_program.as_python())
                else:
                    tail_hash = None

                notarized_payments: List[NotarizedPayment] = []
                for payment_group in coin_spend.solution.to_program().as_iter(
                ):
                    nonce = bytes32(payment_group.first().as_python())
                    payment_args_list: List[Program] = payment_group.rest(
                    ).as_iter()
                    notarized_payments.extend([
                        NotarizedPayment.from_condition_and_nonce(
                            condition, nonce)
                        for condition in payment_args_list
                    ])
                requested_payments[tail_hash] = notarized_payments

            else:
                leftover_coin_spends.append(coin_spend)

        return cls(
            requested_payments,
            SpendBundle(leftover_coin_spends, bundle.aggregated_signature))
Esempio n. 25
0
    async def make_and_spend_bundle(
        self,
        sim: SpendSim,
        sim_client: SimClient,
        coin: Coin,
        delegated_puzzle: Program,
        coinsols: List[CoinSpend],
        ex_error: Optional[Err] = None,
        fail_msg: str = "",
    ):
        signature: G2Element = self.sign_delegated_puz(delegated_puzzle, coin)
        spend_bundle = SpendBundle(
            coinsols,
            signature,
        )

        try:
            result, error = await sim_client.push_tx(spend_bundle)
            if error is None:
                await sim.farm_block()
            elif ex_error is not None:
                assert error == ex_error
            else:
                raise TransactionPushError(error)
        except AssertionError:
            raise AssertionError(fail_msg)
Esempio n. 26
0
def do_test_spend(
    puzzle_reveal: Program,
    solution: Program,
    payments: Iterable[Tuple[bytes32, int]],
    key_lookup: KeyTool,
    farm_time: CoinTimestamp = T1,
    spend_time: CoinTimestamp = T2,
) -> SpendBundle:
    """
    This method will farm a coin paid to the hash of `puzzle_reveal`, then try to spend it
    with `solution`, and verify that the created coins correspond to `payments`.

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

    coin_db = CoinStore()

    puzzle_hash = puzzle_reveal.get_tree_hash()

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

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

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

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

    # make sure we can actually sign the solution
    signatures = []
    for coin_spend in spend_bundle.coin_spends:
        signature = key_lookup.signature_for_solution(coin_spend,
                                                      bytes([2] * 32))
        signatures.append(signature)
    return SpendBundle(spend_bundle.coin_spends,
                       AugSchemeMPL.aggregate(signatures))
Esempio n. 27
0
    async def test_delegated_tail(self, setup_sim):
        sim, sim_client = setup_sim

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

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

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

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

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

        finally:
            await sim.close()
Esempio n. 28
0
    async def create_spend_bundle_relative_amount(self,
                                                  cc_amount,
                                                  zero_coin: Coin = None
                                                  ) -> Optional[SpendBundle]:
        # If we're losing value then get coloured coins with at least that much value
        # If we're gaining value then our amount doesn't matter
        if cc_amount < 0:
            cc_spends = await self.select_coins(abs(cc_amount))
        else:
            if zero_coin is None:
                return None
            cc_spends = set()
            cc_spends.add(zero_coin)

        if cc_spends is None:
            return None

        # Calculate output amount given relative difference and sum of actual values
        spend_value = sum([coin.amount for coin in cc_spends])
        cc_amount = spend_value + cc_amount

        # Loop through coins and create solution for innerpuzzle
        list_of_solutions = []
        output_created = None
        sigs: List[G2Element] = []
        for coin in cc_spends:
            if output_created is None:
                newinnerpuzhash = await self.get_new_inner_hash()
                innersol = self.standard_wallet.make_solution(
                    primaries=[{
                        "puzzlehash": newinnerpuzhash,
                        "amount": cc_amount
                    }])
                output_created = coin
            else:
                innersol = self.standard_wallet.make_solution(
                    consumed=[output_created.name()])
            innerpuz: Program = await self.inner_puzzle_for_cc_puzhash(
                coin.puzzle_hash)
            sigs = sigs + await self.get_sigs(innerpuz, innersol, coin.name())
            lineage_proof = await self.get_lineage_proof_for_coin(coin)
            puzzle_reveal = cc_puzzle_for_inner_puzzle(
                CC_MOD, self.cc_info.my_genesis_checker, innerpuz)
            # Use coin info to create solution and add coin and solution to list of CoinSpends
            solution = [
                innersol,
                coin.as_list(),
                lineage_proof,
                None,
                None,
                None,
                None,
                None,
            ]
            list_of_solutions.append(
                CoinSpend(coin, puzzle_reveal, Program.to(solution)))

        aggsig = AugSchemeMPL.aggregate(sigs)
        return SpendBundle(list_of_solutions, aggsig)
 def test_version_override(self):
     coin_spend = CoinSpend(
         COIN,
         OFFER_MOD,
         SOLUTION,
     )
     spend_bundle = SpendBundle([coin_spend], G2Element())
     compressed = compress_object_with_puzzles(bytes(spend_bundle),
                                               LATEST_VERSION)
     compressed_earlier = compress_object_with_puzzles(
         bytes(spend_bundle), 1)
     assert len(bytes(spend_bundle)) > len(bytes(compressed))
     assert spend_bundle == SpendBundle.from_bytes(
         decompress_object_with_puzzles(compressed))
     assert spend_bundle == SpendBundle.from_bytes(
         decompress_object_with_puzzles(compressed_earlier))
     assert len(bytes(compressed_earlier)) > len(bytes(compressed))
Esempio n. 30
0
 async def push_tx(
     self, spend_bundle: SpendBundle
 ) -> Tuple[MempoolInclusionStatus, Optional[Err]]:
     cost_result: NPCResult = await self.service.mempool_manager.pre_validate_spendbundle(
         spend_bundle)
     cost, status, error = await self.service.mempool_manager.add_spendbundle(
         spend_bundle, cost_result, spend_bundle.name())
     return status, error