示例#1
0
    def ap_generate_signed_aggregation_transaction(self):
        list_of_coinsolutions = []
        if self.aggregation_coins is False:  # empty sets evaluate to false in python
            return
        consolidating_coin = self.aggregation_coins.pop()

        pubkey, secretkey = self.get_keys(
            self.temp_coin.puzzle_hash, self.a_pubkey)

        # Spend wallet coin
        puzzle = ap_make_puzzle(self.a_pubkey, bytes(pubkey))
        solution = self.ap_make_solution_mode_2(self.temp_coin.puzzle_hash, consolidating_coin.parent_coin_info,
                                                consolidating_coin.puzzle_hash, consolidating_coin.amount, self.temp_coin.parent_coin_info, self.temp_coin.amount)
        signature = secretkey.sign(ProgramHash(solution))
        list_of_coinsolutions.append(CoinSolution(
            self.temp_coin, clvm.to_sexp_f([puzzle, solution])))

        # Spend consolidating coin
        puzzle = ap_make_aggregation_puzzle(self.temp_coin.puzzle_hash)
        solution = self.ac_make_aggregation_solution(consolidating_coin.name(
        ), self.temp_coin.parent_coin_info, self.temp_coin.amount)
        list_of_coinsolutions.append(CoinSolution(
            consolidating_coin, clvm.to_sexp_f([puzzle, solution])))
        # Spend lock
        puzstring = f"(r (c (q 0x{consolidating_coin.name().hex()}) (q ())))"
        puzzle = Program(binutils.assemble(puzstring))
        solution = Program(binutils.assemble("()"))
        list_of_coinsolutions.append(CoinSolution(Coin(self.temp_coin, ProgramHash(
            puzzle), 0), clvm.to_sexp_f([puzzle, solution])))

        self.temp_coin = Coin(self.temp_coin, self.temp_coin.puzzle_hash,
                              self.temp_coin.amount + consolidating_coin.amount)
        aggsig = BLSSignature.aggregate([signature])
        solution_list = CoinSolutionList(list_of_coinsolutions)
        return SpendBundle(solution_list, aggsig)
示例#2
0
def test_standard_spend():
    remote = make_client_server()
    run = asyncio.get_event_loop().run_until_complete
    wallet_a = Wallet()
    wallet_b = Wallet()
    wallets = [wallet_a, wallet_b]
    commit_and_notify(remote, wallets, wallet_a)

    assert wallet_a.current_balance == 1000000000
    assert len(wallet_a.my_utxos) == 2
    assert wallet_b.current_balance == 0
    assert len(wallet_b.my_utxos) == 0
    # wallet a send to wallet b
    pubkey_puz_string = "(0x%s)" % hexlify(
        wallet_b.get_next_public_key().serialize()).decode('ascii')
    args = binutils.assemble(pubkey_puz_string)
    program = Program(
        clvm.eval_f(
            clvm.eval_f,
            binutils.assemble(
                wallet_a.generator_lookups[wallet_b.puzzle_generator_id]),
            args))
    puzzlehash = ProgramHash(program)

    amount = 5000
    spend_bundle = wallet_a.generate_signed_transaction(amount, puzzlehash)
    _ = run(remote.push_tx(tx=spend_bundle))
    # give new wallet the reward to not complicate the one's we're tracking
    commit_and_notify(remote, wallets, Wallet())

    assert wallet_a.current_balance == 999995000
    assert wallet_b.current_balance == 5000
    assert len(wallet_b.my_utxos) == 1

    # wallet b sends back to wallet a
    pubkey_puz_string = "(0x%s)" % hexlify(
        wallet_a.get_next_public_key().serialize()).decode('ascii')
    args = binutils.assemble(pubkey_puz_string)
    program = Program(
        clvm.eval_f(
            clvm.eval_f,
            binutils.assemble(
                wallet_b.generator_lookups[wallet_a.puzzle_generator_id]),
            args))
    puzzlehash = ProgramHash(program)

    amount = 5000
    spend_bundle = wallet_b.generate_signed_transaction(amount, puzzlehash)
    _ = run(remote.push_tx(tx=spend_bundle))
    # give new wallet the reward to not complicate the one's we're tracking
    commit_and_notify(remote, wallets, Wallet())
    assert wallet_a.current_balance == 1000000000
    assert wallet_b.current_balance == 0
示例#3
0
    def rl_generate_signed_aggregation_transaction(self):
        list_of_coinsolutions = []
        if self.aggregation_coins is False:  # empty sets evaluate to false in python
            return
        consolidating_coin = self.aggregation_coins.pop()

        pubkey, secretkey = self.get_keys(self.rl_coin.puzzle_hash)
        # Spend wallet coin
        puzzle = self.rl_puzzle_for_pk(pubkey.serialize(), self.limit,
                                       self.interval, self.rl_origin,
                                       self.rl_clawback_pk)

        if isinstance(self.rl_parent, Coin):
            solution = self.rl_make_solution_mode_2(
                self.rl_coin.puzzle_hash, consolidating_coin.parent_coin_info,
                consolidating_coin.puzzle_hash, consolidating_coin.amount,
                self.rl_coin.parent_coin_info, self.rl_coin.amount,
                self.rl_parent.amount, self.rl_parent.parent_coin_info)
        else:
            solution = self.rl_make_solution_mode_2(
                self.rl_coin.puzzle_hash, consolidating_coin.parent_coin_info,
                consolidating_coin.puzzle_hash, consolidating_coin.amount,
                self.rl_coin.parent_coin_info, self.rl_coin.amount,
                self.rl_parent["amount"], self.rl_parent["parent_coin_info"])
        signature = BLSPrivateKey(secretkey).sign(ProgramHash(solution))
        list_of_coinsolutions.append(
            CoinSolution(self.rl_coin, clvm.to_sexp_f([puzzle, solution])))

        # Spend consolidating coin
        puzzle = self.rl_make_aggregation_puzzle(self.rl_coin.puzzle_hash)
        solution = self.rl_make_aggregation_solution(
            consolidating_coin.name(), self.rl_coin.parent_coin_info,
            self.rl_coin.amount)
        list_of_coinsolutions.append(
            CoinSolution(consolidating_coin, clvm.to_sexp_f([puzzle,
                                                             solution])))
        # Spend lock
        puzstring = "(r (c (q 0x" + hexlify(
            consolidating_coin.name()).decode('ascii') + ") (q ())))"

        puzzle = Program(binutils.assemble(puzstring))
        solution = Program(binutils.assemble("()"))
        list_of_coinsolutions.append(
            CoinSolution(Coin(self.rl_coin, ProgramHash(puzzle), 0),
                         clvm.to_sexp_f([puzzle, solution])))

        aggsig = BLSSignature.aggregate([signature])
        solution_list = CoinSolutionList(list_of_coinsolutions)

        return SpendBundle(solution_list, aggsig)
示例#4
0
 def ap_make_solution_mode_2(self, wallet_puzzle_hash,
                             consolidating_primary_input,
                             consolidating_coin_puzzle_hash,
                             outgoing_amount, my_primary_input,
                             incoming_amount):
     sol = f"(2 0x{wallet_puzzle_hash.hex()} 0x{consolidating_primary_input.hex()} 0x{consolidating_coin_puzzle_hash.hex()} {outgoing_amount} 0x{my_primary_input.hex()} {incoming_amount})"
     return Program(binutils.assemble(sol))
示例#5
0
 def solution_for_cp_permission(self, puzzlehash_amount_list=[]):
     opcode_create = hexlify(ConditionOpcode.CREATE_COIN).decode('ascii')
     sol = "(2 ("
     for puzhash, amount in puzzlehash_amount_list:
         sol += f"(0x{opcode_create} 0x{hexlify(puzhash).decode('ascii')} {amount})"
     sol += f"))"
     return Program(binutils.assemble(sol))
def ap_make_puzzle(a_pubkey_serialized, b_pubkey_serialized):
    a_pubkey = pubkey_format(a_pubkey_serialized)
    b_pubkey = pubkey_format(b_pubkey_serialized)

    # Mode one is for spending to one of the approved destinations
    # Solution contains (option 1 flag, new puzzle, new solution, my_primary_input, wallet_puzzle_hash)

    aggsig_entire_solution = f"(c (q 0x{ConditionOpcode.AGG_SIG.hex()}) (c (q {b_pubkey}) (c (sha256tree (a)) (q ()))))"
    create_outputs = f"((c (f (r (a))) (f (r (r (a))))))"
    aggsig_outputs = f"((c (q ((c (f (a)) (a)))) (c (q ((c (i (f (r (a))) (q ((c (i (= (f (f (f (r (a))))) (q 0x{ConditionOpcode.CREATE_COIN.hex()})) (q ((c (f (a)) (c (f (a)) (c (r (f (r (a)))) (c (c (c (q 0x{ConditionOpcode.AGG_SIG.hex()}) (c (q {a_pubkey}) (c (f (r (f (f (r (a)))))) (q ())))) (f (r (r (a))))) (q ()))))))) (q ((c (f (a)) (c (f (a)) (c (r (f (r (a)))) (c (f (r (r (a)))) (q ())))))))) (a)))) (q (f (r (r (a)))))) (a)))) (c {create_outputs} (c {create_outputs} (q ()))))))"
    sum_outputs = f"((c (q ((c (f (a)) (a)))) (c (q ((c (i (f (r (a))) (q ((c (i (= (f (f (f (r (a))))) (q 0x{ConditionOpcode.CREATE_COIN.hex()})) (q (+ (f (r (r (f (f (r (a))))))) ((c (f (a)) (c (f (a)) (c (r (f (r (a)))) (q ()))))))) (q (+ (q ()) ((c (f (a)) (c (f (a)) (c (r (f (r (a)))) (q ())))))))) (a)))) (q (q ()))) (a)))) (c {create_outputs} (q ())))))"
    mode_one_me_string = f"(c (q 0x{ConditionOpcode.ASSERT_MY_COIN_ID.hex()}) (c (sha256 (f (r (r (r (a))))) (f (r (r (r (r (a)))))) {sum_outputs}) (q ())))"
    mode_one = f"(c {aggsig_entire_solution} (c {mode_one_me_string} {aggsig_outputs}))"
    #mode_one = merge_two_lists(create_outputs, mode_one)

    # Mode two is for aggregating in another coin and expanding our single coin wallet
    # Solution contains (option 2 flag, wallet_puzzle_hash, consolidating_coin_primary_input, consolidating_coin_puzzle_hash, consolidating_coin_amount, my_primary_input, my_amount)
    create_consolidated = f"(c (q 0x{ConditionOpcode.CREATE_COIN.hex()}) (c (f (r (a))) (c (+ (f (r (r (r (r (a)))))) (f (r (r (r (r (r (r (a))))))))) (q ()))))"
    mode_two_me_string = f"(c (q 0x{ConditionOpcode.ASSERT_MY_COIN_ID.hex()}) (c (sha256 (f (r (r (r (r (r (a))))))) (f (r (a))) (f (r (r (r (r (r (r (a))))))))) (q ())))"
    create_lock = f"(c (q 0x{ConditionOpcode.CREATE_COIN.hex()}) (c (sha256tree (c (q 7) (c (c (q 5) (c (c (q 1) (c (sha256 (f (r (r (a)))) (f (r (r (r (a))))) (f (r (r (r (r (a))))))) (q ()))) (c (q (q ())) (q ())))) (q ())))) (c (q 0) (q ()))))"

    mode_two = f"(c {mode_two_me_string} (c {aggsig_entire_solution} \
         (c {create_lock} (c {create_consolidated} (q ())))))"

    puz = f"((c (i (= (f (a)) (q 1)) (q {mode_one}) (q {mode_two})) (a)))"
    return Program(binutils.assemble(puz))
示例#7
0
 def get_new_puzzle_with_params_and_root(self, recovery_pubkey, pubkey,
                                         stake_factor, duration):
     op_create = ConditionOpcode.CREATE_COIN[0]
     op_consumed = ConditionOpcode.ASSERT_COIN_CONSUMED[0]
     solution = args(0)
     solution_args = args(1)
     secure_switch = args(2)
     parent = args(3)
     puzzle_hash = args(4)
     value = args(5)
     new_value = args(6)
     evaluate_solution = eval(solution, solution_args)
     standard_conditions = make_list(aggsig_condition(pubkey),
                                     terminator=evaluate_solution)
     escrow_program = self.get_escrow_puzzle_with_params(
         recovery_pubkey, pubkey, duration)
     escrow_puzzlehash = f'0x' + str(hexbytes(ProgramHash(escrow_program)))
     f = Fraction(stake_factor)
     stake_factor_numerator = quote(f.numerator)
     stake_factor_denominator = quote(f.denominator)
     create_condition = make_if(
         equal(multiply(new_value, stake_factor_denominator),
               multiply(value, stake_factor_numerator)),
         make_list(quote(op_create), quote(escrow_puzzlehash), new_value),
         fail())
     coin_id = sha256(parent, puzzle_hash, uint64(value))
     consumed_condition = make_list(quote(op_consumed), coin_id)
     escrow_conditions = make_list(create_condition, consumed_condition)
     puzzle = make_if(is_zero(secure_switch), standard_conditions,
                      escrow_conditions)
     program = Program(binutils.assemble(puzzle))
     return program
示例#8
0
 def as_make_puzzle(self, as_pubkey_sender, as_pubkey_receiver, as_amount,
                    as_timelock_block, as_secret_hash):
     as_pubkey_sender_cl = "0x%s" % (
         hexlify(as_pubkey_sender).decode('ascii'))
     as_pubkey_receiver_cl = "0x%s" % (
         hexlify(as_pubkey_receiver).decode('ascii'))
     as_payout_puzzlehash_receiver = ProgramHash(
         puzzle_for_pk(as_pubkey_receiver))
     as_payout_puzzlehash_sender = ProgramHash(
         puzzle_for_pk(as_pubkey_sender))
     payout_receiver = "(c (q 0x%s) (c (q 0x%s) (c (q %d) (q ()))))" % (
         hexlify(ConditionOpcode.CREATE_COIN).decode('ascii'),
         hexlify(as_payout_puzzlehash_receiver).decode('ascii'), as_amount)
     payout_sender = "(c (q 0x%s) (c (q 0x%s) (c (q %d) (q ()))))" % (
         hexlify(ConditionOpcode.CREATE_COIN).decode('ascii'),
         hexlify(as_payout_puzzlehash_sender).decode('ascii'), as_amount)
     aggsig_receiver = "(c (q 0x%s) (c (q %s) (c (sha256 (wrap (a))) (q ()))))" % (
         hexlify(ConditionOpcode.AGG_SIG).decode('ascii'),
         as_pubkey_receiver_cl)
     aggsig_sender = "(c (q 0x%s) (c (q %s) (c (sha256 (wrap (a))) (q ()))))" % (
         hexlify(
             ConditionOpcode.AGG_SIG).decode('ascii'), as_pubkey_sender_cl)
     receiver_puz = ("((c (i (= (sha256 (f (r (a)))) (q %s)) (q (c " +
                     aggsig_receiver + " (c " + payout_receiver +
                     " (q ())))) (q (x (q 'invalid secret')))) (a))) ) "
                     ) % (as_secret_hash)
     timelock = "(c (q 0x%s) (c (q %d) (q ()))) " % (hexlify(
         ConditionOpcode.ASSERT_BLOCK_INDEX_EXCEEDS).decode('ascii'),
                                                     as_timelock_block)
     sender_puz = "(c " + aggsig_sender + " (c " + timelock + " (c " + payout_sender + " (q ()))))"
     as_puz_sender = "((c (i (= (f (a)) (q 77777)) (q " + sender_puz + ") (q (x (q 'not a valid option'))) ) (a)))"
     as_puz = "((c (i (= (f (a)) (q 33333)) (q " + receiver_puz + " (q " + as_puz_sender + ")) (a)))"
     return Program(binutils.assemble(as_puz))
示例#9
0
def puzzle_for_synthetic_public_key(synthetic_public_key):
    puzzle_src = "((c (q %s) (c (q 0x%s) (a))))" % (
        binutils.disassemble(puzzle_prog_template),
        synthetic_public_key.hex(),
    )
    puzzle_prog = binutils.assemble(puzzle_src)
    return Program(puzzle_prog)
示例#10
0
    def rl_puzzle_for_pk(self, pubkey, rate_amount, interval_time, origin_id,
                         clawback_pk):
        hex_pk = hexbytes(pubkey)
        #breakpoint()
        opcode_aggsig = hexlify(ConditionOpcode.AGG_SIG).decode('ascii')
        opcode_coin_block_age = hexlify(
            ConditionOpcode.ASSERT_BLOCK_AGE_EXCEEDS).decode('ascii')
        opcode_create = hexlify(ConditionOpcode.CREATE_COIN).decode('ascii')
        opcode_myid = hexlify(
            ConditionOpcode.ASSERT_MY_COIN_ID).decode('ascii')
        if (not origin_id):
            return None

        TEMPLATE_MY_PARENT_ID = "(sha256 (f (r (r (r (r (r (r (a)))))))) (f (r (a))) (uint64 (f (r (r (r (r (r (r (r (a)))))))))))"
        TEMPLATE_SINGLETON_RL = f"((c (i (i (= {TEMPLATE_MY_PARENT_ID} (f (a))) (q 1) (= (f (a)) (q 0x{origin_id}))) (q (c (q 1) (q ()))) (q (x (q \"Parent doesnt satisfy RL conditions\")))) (a)))"
        TEMPLATE_BLOCK_AGE = f"((c (i (i (= (* (f (r (r (r (r (r (a))))))) (q {rate_amount})) (* (f (r (r (r (r (a)))))) (q {interval_time}))) (q 1) (q (> (* (f (r (r (r (r (r (a))))))) (q {rate_amount})) (* (f (r (r (r (r (a))))))) (q {interval_time})))) (q (c (q 0x{opcode_coin_block_age}) (c (f (r (r (r (r (r (a))))))) (q ())))) (q (x (q \"wrong min block time\")))) (a) ))"
        TEMPLATE_MY_ID = f"(c (q 0x{opcode_myid}) (c (sha256 (f (a)) (f (r (a))) (uint64 (f (r (r (a)))))) (q ())))"
        CREATE_CHANGE = f"(c (q 0x{opcode_create}) (c (f (r (a))) (c (- (f (r (r (a)))) (f (r (r (r (r (a))))))) (q ()))))"
        CREATE_NEW_COIN = f"(c (q 0x{opcode_create}) (c (f (r (r (r (a))))) (c (f (r (r (r (r (a)))))) (q ()))))"
        RATE_LIMIT_PUZZLE = f"(c {TEMPLATE_SINGLETON_RL} (c {TEMPLATE_BLOCK_AGE} (c {CREATE_CHANGE} (c {TEMPLATE_MY_ID} (c {CREATE_NEW_COIN} (q ()))))))"

        TEMPLATE_MY_PARENT_ID_2 = "(sha256 (f (r (r (r (r (r (r (r (r (a)))))))))) (f (r (a))) (uint64 (f (r (r (r (r (r (r (r (a)))))))))))"
        TEMPLATE_SINGLETON_RL_2 = f"((c (i (i (= {TEMPLATE_MY_PARENT_ID_2} (f (r (r (r (r (r (a)))))))) (q 1) (= (f (r (r (r (r (r (a))))))) (q 0x{origin_id}))) (q (c (q 1) (q ()))) (q (x (q \"Parent doesnt satisfy RL conditions\")))) (a)))"
        CREATE_CONSOLIDATED = f"(c (q 0x{opcode_create}) (c (f (r (a))) (c (+ (f (r (r (r (r (a)))))) (f (r (r (r (r (r (r (a))))))))) (q ()))))"
        MODE_TWO_ME_STRING = f"(c (q 0x{opcode_myid}) (c (sha256 (f (r (r (r (r (r (a))))))) (f (r (a))) (uint64 (f (r (r (r (r (r (r (a)))))))))) (q ())))"
        CREATE_LOCK = f"(c (q 0x{opcode_create}) (c (sha256 (wrap (c (q 7) (c (c (q 5) (c (c (q 1) (c (sha256 (f (r (r (a)))) (f (r (r (r (a))))) (uint64 (f (r (r (r (r (a)))))))) (q ()))) (c (q (q ())) (q ())))) (q ()))))) (c (uint64 (q 0)) (q ()))))"
        MODE_TWO = f"(c {TEMPLATE_SINGLETON_RL_2} (c {MODE_TWO_ME_STRING} (c {CREATE_LOCK} (c {CREATE_CONSOLIDATED} (q ())))))"

        AGGSIG_ENTIRE_SOLUTION = f"(c (q 0x{opcode_aggsig}) (c (q 0x{hex_pk}) (c (sha256 (wrap (a))) (q ()))))"

        WHOLE_PUZZLE = f"(c {AGGSIG_ENTIRE_SOLUTION} ((c (i (= (f (a)) (q 1)) (q ((c (q {RATE_LIMIT_PUZZLE}) (r (a))))) (q {MODE_TWO})) (a))) (q ()))"
        CLAWBACK = f"(c (c (q 0x{opcode_aggsig}) (c (q 0x{clawback_pk}) (c (sha256 (wrap (a))) (q ())))) (r (a)))"
        WHOLE_PUZZLE_WITH_CLAWBACK = f"((c (i (= (f (a)) (q 3)) (q {CLAWBACK}) (q {WHOLE_PUZZLE})) (a)))"

        return Program(binutils.assemble(WHOLE_PUZZLE_WITH_CLAWBACK))
示例#11
0
    def generate_recovery_transaction(self, coins, root_public_key, secret_key,
                                      escrow_duration):
        recovery_pubkey = root_public_key.public_child(
            0).get_public_key().serialize()
        signatures = []
        coin_solutions = []
        secret_key = BLSPrivateKey(secret_key)
        for coin in coins:
            pubkey = self.find_pubkey_for_escrow_puzzle(
                coin, root_public_key, escrow_duration)
            puzzle = self.get_escrow_puzzle_with_params(
                recovery_pubkey, pubkey.serialize(), escrow_duration)

            op_create_coin = ConditionOpcode.CREATE_COIN[0]
            puzzlehash = f'0x' + str(hexbytes(self.get_new_puzzlehash()))
            solution_src = sexp(
                quote(sexp(sexp(op_create_coin, puzzlehash, coin.amount))),
                sexp(), 1)
            solution = Program(binutils.assemble(solution_src))

            puzzle_solution_list = clvm.to_sexp_f([puzzle, solution])
            coin_solution = CoinSolution(coin, puzzle_solution_list)
            coin_solutions.append(coin_solution)

            conditions_dict = conditions_by_opcode(
                conditions_for_solution(puzzle_solution_list))
            for _ in hash_key_pairs_for_conditions_dict(conditions_dict):
                signature = secret_key.sign(_.message_hash)
                signatures.append(signature)

        coin_solution_list = CoinSolutionList(coin_solutions)
        aggsig = BLSSignature.aggregate(signatures)
        spend_bundle = SpendBundle(coin_solution_list, aggsig)
        return spend_bundle
示例#12
0
 def as_create_spend_bundle(self,
                            as_puzzlehash,
                            as_amount,
                            as_timelock_block,
                            as_secret_hash,
                            as_pubkey_sender=None,
                            as_pubkey_receiver=None,
                            who=None,
                            as_sec_to_try=None):
     utxos = self.as_select_coins(as_amount, as_puzzlehash)
     spends = []
     for coin in utxos:
         puzzle = self.as_make_puzzle(as_pubkey_sender, as_pubkey_receiver,
                                      as_amount, as_timelock_block,
                                      as_secret_hash)
         if who == "sender":
             solution = self.as_make_solution_sender()
         elif who == "receiver":
             solution = self.as_make_solution_receiver(as_sec_to_try)
         pair = solution.to([puzzle, solution])
         signer = self.make_signer()
         spend_bundle = build_spend_bundle(coin,
                                           Program(pair),
                                           sign_f=signer)
         spends.append(spend_bundle)
     return SpendBundle.aggregate(spends)
示例#13
0
def name_puzzle_conditions_list(body_program):
    """
    Return a list of tuples of (coin_name, solved_puzzle_hash, conditions_dict)
    """

    try:
        cost, sexp = run_program(body_program, [])
    except EvalError:
        breakpoint()
        raise ConsensusError(Err.INVALID_BLOCK_SOLUTION, body_program)

    npc_list = []
    for name_solution in sexp.as_iter():
        _ = name_solution.as_python()
        if len(_) != 2:
            raise ConsensusError(Err.INVALID_COIN_SOLUTION, name_solution)
        if not isinstance(_[0], bytes) or len(_[0]) != 32:
            raise ConsensusError(Err.INVALID_COIN_SOLUTION, name_solution)
        coin_name = CoinName(_[0])
        if not isinstance(_[1], list) or len(_[1]) != 2:
            raise ConsensusError(Err.INVALID_COIN_SOLUTION, name_solution)
        puzzle_solution_program = name_solution.rest().first()
        puzzle_program = puzzle_solution_program.first()
        puzzle_hash = ProgramHash(Program(puzzle_program))
        try:
            conditions_dict = conditions_dict_for_solution(
                puzzle_solution_program)
        except EvalError:
            raise ConsensusError(Err.INVALID_COIN_SOLUTION, coin_name)

        npc_list.append((coin_name, puzzle_hash, conditions_dict))

    return npc_list
示例#14
0
 def rl_make_solution_mode_2(self, my_puzzle_hash, consolidating_primary_input, consolidating_coin_puzzle_hash,
                             outgoing_amount, my_primary_input, incoming_amount, parent_amount, my_parent_parent_id):
     my_puzzle_hash = hexlify(my_puzzle_hash).decode('ascii')
     consolidating_primary_input = hexlify(consolidating_primary_input).decode('ascii')
     consolidating_coin_puzzle_hash = hexlify(consolidating_coin_puzzle_hash).decode('ascii')
     primary_input = hexlify(my_primary_input).decode('ascii')
     sol = f"(2 0x{my_puzzle_hash} 0x{consolidating_primary_input} 0x{consolidating_coin_puzzle_hash} {outgoing_amount} 0x{primary_input} {incoming_amount} {parent_amount} 0x{my_parent_parent_id})"
     return Program(binutils.assemble(sol))
示例#15
0
 def ap_make_solution_mode_1(self,
                             outputs=[],
                             my_primary_input=0x0000,
                             my_puzzle_hash=0x0000):
     sol = "(1 (a) ("
     for puzhash, amount in outputs:
         sol += f"(0x{ConditionOpcode.CREATE_COIN.hex()} 0x{puzhash.hex()} {amount})"
     sol += f") 0x{my_primary_input.hex()} 0x{my_puzzle_hash.hex()})"
     return Program(binutils.assemble(sol))
def ap_make_aggregation_puzzle(wallet_puzzle):
    # If Wallet A wants to send further funds to Wallet B then they can lock them up using this code
    # Solution will be (my_id wallet_coin_primary_input wallet_coin_amount)
    me_is_my_id = f'(c (q 0x{ConditionOpcode.ASSERT_MY_COIN_ID.hex()}) (c (f (a)) (q ())))'
    # lock_puzzle is the hash of '(r (c (q "merge in ID") (q ())))'
    lock_puzzle = '(sha256tree (c (q 7) (c (c (q 5) (c (c (q 1) (c (f (a)) (q ()))) (c (q (q ())) (q ())))) (q ()))))'
    parent_coin_id = f"(sha256 (f (r (a))) (q 0x{wallet_puzzle.hex()}) (f (r (r (a)))))"
    input_of_lock = f'(c (q 0x{ConditionOpcode.ASSERT_COIN_CONSUMED.hex()}) (c (sha256 {parent_coin_id} {lock_puzzle} (q 0)) (q ())))'
    puz = f"(c {me_is_my_id} (c {input_of_lock} (q ())))"
    return Program(binutils.assemble(puz))
示例#17
0
 def ap_notify(self, additions):
     # this prevents unnecessary checks and stops us receiving multiple coins
     if self.AP_puzzlehash is not None and not self.my_utxos:
         for coin in additions:
             if coin.puzzle_hash == self.AP_puzzlehash:
                 self.puzzle_generator = f"(q (c (c (q 0x{hexlify(ConditionOpcode.AGG_SIG).decode('ascii')}) (c (f (a)) (q ()))) (c (c (q 0x{hexlify(ConditionOpcode.ASSERT_COIN_CONSUMED).decode('ascii')}) (c (sha256 (sha256 (f (r (a))) (q 0x{hexlify(self.AP_puzzlehash).decode('ascii')}) (uint64 (f (r (r (a)))))) (sha256 (wrap (c (q 7) (c (c (q 5) (c (c (q 1) (c (f (a)) (q ()))) (c (q (q ())) (q ())))) (q ()))))) (uint64 (q 0))) (q ()))) (q ()))))"
                 self.puzzle_generator_id = str(ProgramHash(
                     Program(binutils.assemble(self.puzzle_generator))))
                 self.current_balance += coin.amount
                 self.my_utxos.add(coin)
                 print("this coin is locked using my ID, it's output must be for me")
示例#18
0
def ap_make_aggregation_puzzle(wallet_puzzle):
    # If Wallet A wants to send further funds to Wallet B then they can lock them up using this code
    # Solution will be (my_id wallet_coin_primary_input wallet_coin_amount)
    me_is_my_id = '(c (q 0x%s) (c (f (a)) (q ())))' % (
        hexlify(ConditionOpcode.ASSERT_MY_COIN_ID).decode('ascii'))
    # lock_puzzle is the hash of '(r (c (q "merge in ID") (q ())))'
    lock_puzzle = '(sha256 (wrap (c (q 7) (c (c (q 5) (c (c (q 1) (c (f (a)) (q ()))) (c (q (q ())) (q ())))) (q ())))))'
    parent_coin_id = "(sha256 (f (r (a))) (q 0x%s) (uint64 (f (r (r (a))))))" % hexlify(
        wallet_puzzle).decode('ascii')
    input_of_lock = '(c (q 0x%s) (c (sha256 %s %s (uint64 (q 0))) (q ())))' % (hexlify(
        ConditionOpcode.ASSERT_COIN_CONSUMED).decode('ascii'), parent_coin_id, lock_puzzle)
    puz = f"(c {me_is_my_id} (c {input_of_lock} (q ())))"
    return Program(binutils.assemble(puz))
示例#19
0
 def sign_clawback_transaction(self, spends: (Program, [CoinSolution]), clawback_pubkey):
     sigs = []
     for puzzle, solution in spends:
         pubkey, secretkey = self.get_keys_pk(clawback_pubkey)
         signature = secretkey.sign(
             ProgramHash(Program(solution.solution)))
         sigs.append(signature)
     aggsig = BLSSignature.aggregate(sigs)
     solution_list = CoinSolutionList(
         [CoinSolution(coin_solution.coin, clvm.to_sexp_f([puzzle, coin_solution.solution])) for
          (puzzle, coin_solution) in spends])
     spend_bundle = SpendBundle(solution_list, aggsig)
     return spend_bundle
示例#20
0
    def rl_make_aggregation_puzzle(self, wallet_puzzle):
        # If Wallet A wants to send further funds to Wallet B then they can lock them up using this code
        # Solution will be (my_id wallet_coin_primary_input wallet_coin_amount)
        opcode_myid = hexlify(ConditionOpcode.ASSERT_MY_COIN_ID).decode('ascii')
        opcode_consumed = hexlify(ConditionOpcode.ASSERT_COIN_CONSUMED).decode('ascii')
        me_is_my_id = f"(c (q 0x{opcode_myid}) (c (f (a)) (q ())))"

        # lock_puzzle is the hash of '(r (c (q "merge in ID") (q ())))'
        lock_puzzle = "(sha256tree (c (q 7) (c (c (q 5) (c (c (q 1) (c (f (a)) (q ()))) (c (q (q ())) (q ())))) (q ()))))"
        parent_coin_id = f"(sha256 (f (r (a))) (q 0x{wallet_puzzle}) (f (r (r (a)))))"
        input_of_lock = f"(c (q 0x{opcode_consumed}) (c (sha256 {parent_coin_id} {lock_puzzle} (q 0)) (q ())))"
        puz = f"(c {me_is_my_id} (c {input_of_lock} (q ())))"

        return Program(binutils.assemble(puz))
示例#21
0
 def ap_sign_transaction(self, spends: (Program, [CoinSolution]), signatures_from_a):
     sigs = []
     for puzzle, solution in spends:
         pubkey, secretkey = self.get_keys(
             solution.coin.puzzle_hash, self.a_pubkey)
         signature = secretkey.sign(
             ProgramHash(Program(solution.solution)))
         sigs.append(signature)
     for s in signatures_from_a:
         sigs.append(s)
     aggsig = BLSSignature.aggregate(sigs)
     solution_list = CoinSolutionList(
         [CoinSolution(coin_solution.coin, clvm.to_sexp_f([puzzle, coin_solution.solution])) for
          (puzzle, coin_solution) in spends])
     spend_bundle = SpendBundle(solution_list, aggsig)
     return spend_bundle
示例#22
0
 def get_escrow_puzzle_with_params(self, recovery_pubkey, pubkey, duration):
     op_block_age_exceeds = ConditionOpcode.ASSERT_BLOCK_AGE_EXCEEDS[0]
     solution = args(0)
     solution_args = args(1)
     secure_switch = args(2)
     evaluate_solution = eval(solution, solution_args)
     standard_conditions = make_list(aggsig_condition(pubkey),
                                     terminator=evaluate_solution)
     recovery_conditions = make_list(aggsig_condition(recovery_pubkey),
                                     make_list(quote(op_block_age_exceeds),
                                               quote(duration)),
                                     terminator=evaluate_solution)
     escrow_puzzle = make_if(is_zero(secure_switch), standard_conditions,
                             recovery_conditions)
     program = Program(binutils.assemble(escrow_puzzle))
     return program
示例#23
0
    def cp_puzzle(self, pubkey_my, pubkey_permission, unlock_time):
        opcode_aggsig = hexlify(ConditionOpcode.AGG_SIG).decode('ascii')
        opcode_time_exceeds = hexlify(
            ConditionOpcode.ASSERT_TIME_EXCEEDS).decode('ascii')

        TIME_EXCEEDS = f"(c (q 0x{opcode_time_exceeds}) (c (q {unlock_time}) (q ())))"
        AGGSIG_ME = f"(c (q 0x{opcode_aggsig}) (c (q 0x{pubkey_my}) (c (sha256tree (a)) (q ()))))"
        AGGSIG_PERMISSION = f"(c (q 0x{opcode_aggsig}) (c (q 0x{pubkey_permission}) (c (sha256tree (a)) (q ()))))"
        SOLO_PUZZLE_CONDITIONS = f"(c {TIME_EXCEEDS} (c {AGGSIG_ME} (q ())))"
        SOLUTION_OUTPUTS = f"(f (r (a)))"
        SOLO_PUZZLE = self.merge_two_lists(SOLO_PUZZLE_CONDITIONS,
                                           SOLUTION_OUTPUTS)
        PERMISSION_PUZZLE_CONDITIONS = f"(c {AGGSIG_PERMISSION} (c {AGGSIG_ME} (q ())))"
        PERMISSION_PUZZLE = self.merge_two_lists(PERMISSION_PUZZLE_CONDITIONS,
                                                 SOLUTION_OUTPUTS)
        WHOLE_PUZZLE = f"(i (= (f (a)) (q 1)) {SOLO_PUZZLE} {PERMISSION_PUZZLE})"
        return Program(binutils.assemble(WHOLE_PUZZLE))
示例#24
0
def test_spend_failure():
    remote = make_client_server()
    run = asyncio.get_event_loop().run_until_complete
    wallet_a = Wallet()
    wallet_b = Wallet()
    wallets = [wallet_a, wallet_b]
    amount = 5000
    # wallet a send to wallet b
    pubkey_puz_string = "(0x%s)" % hexlify(
        wallet_b.get_next_public_key().serialize()).decode('ascii')
    args = binutils.assemble(pubkey_puz_string)
    program = Program(
        clvm.eval_f(
            clvm.eval_f,
            binutils.assemble(
                wallet_a.generator_lookups[wallet_b.puzzle_generator_id]),
            args))
    puzzlehash = ProgramHash(program)
    spend_bundle = wallet_a.generate_signed_transaction(amount, puzzlehash)
    assert spend_bundle is None

    commit_and_notify(remote, wallets, wallet_a)
    amount = 50000000000000
    puzzlehash = wallet_b.get_new_puzzlehash()
    spend_bundle = wallet_a.generate_signed_transaction(amount, puzzlehash)
    assert spend_bundle is None
    amount = 999995000
    puzzlehash = wallet_b.get_new_puzzlehash()
    spend_bundle = wallet_a.generate_signed_transaction(amount, puzzlehash)
    _ = run(remote.push_tx(tx=spend_bundle))
    assert wallet_a.temp_balance == 5000

    amount = 6000
    puzzlehash = wallet_b.get_new_puzzlehash()
    spend_bundle = wallet_a.generate_signed_transaction(amount, puzzlehash)
    assert spend_bundle is None

    amount = 4000
    puzzlehash = wallet_b.get_new_puzzlehash()
    spend_bundle = wallet_a.generate_signed_transaction(amount, puzzlehash)
    _ = run(remote.push_tx(tx=spend_bundle))
    assert wallet_a.temp_balance == 1000
    commit_and_notify(remote, wallets, Wallet())
    assert wallet_a.current_balance == 1000
    assert wallet_a.temp_balance == 1000
def make_solution(parent,
                  puzzlehash,
                  value,
                  stake_factor,
                  primaries=[],
                  recovery=False):
    conditions = []
    for primary in primaries:
        conditions.append(
            make_create_coin_condition(primary['puzzlehash'],
                                       primary['amount']))
    conditions = [binutils.assemble("#q"), conditions]
    solution = [
        conditions, [], 1 if recovery else 0, parent, puzzlehash, value,
        math.floor(value * stake_factor)
    ]
    program = Program(to_sexp_f(solution))
    return program
示例#26
0
 def as_solution_list(self, body_program):
     try:
         cost, sexp = clvm.run_program(body_program, [])
     except clvm.EvalError.EvalError:
         raise ValueError(body_program)
     npc_list = []
     for name_solution in sexp.as_iter():
         _ = name_solution.as_python()
         if len(_) != 2:
             raise ValueError(name_solution)
         if not isinstance(_[0], bytes) or len(_[0]) != 32:
             raise ValueError(name_solution)
         if not isinstance(_[1], list) or len(_[1]) != 2:
             raise ValueError(name_solution)
         puzzle_solution_program = name_solution.rest().first()
         puzzle_program = puzzle_solution_program.first()
         puzzle_hash = ProgramHash(Program(puzzle_program))
         npc_list.append((puzzle_hash, puzzle_solution_program))
     return npc_list
示例#27
0
 def cp_sign_transaction(self,
                         spends: (Program, [CoinSolution]),
                         approval=None):
     sigs = []
     for puzzle, solution in spends:
         pubkey, secretkey = self.get_keys(solution.coin.puzzle_hash)
         signature = secretkey.sign(ProgramHash(Program(solution.solution)))
         sigs.append(signature)
     if approval is not None:
         app = BLSSignature(approval)
         sigs.append(app)
     aggsig = BLSSignature.aggregate(sigs)
     solution_list = CoinSolutionList([
         CoinSolution(coin_solution.coin,
                      clvm.to_sexp_f([puzzle, coin_solution.solution]))
         for (puzzle, coin_solution) in spends
     ])
     spend_bundle = SpendBundle(solution_list, aggsig)
     return spend_bundle
示例#28
0
 def as_solution_list(self, body_program):
     try:
         sexp = clvm.eval_f(clvm.eval_f, body_program, [])
     except clvm.EvalError.EvalError:
         breakpoint()
         raise ConsensusError(Err.INVALID_BLOCK_SOLUTION, body_program)
     npc_list = []
     for name_solution in sexp.as_iter():
         _ = name_solution.as_python()
         if len(_) != 2:
             raise ConsensusError(Err.INVALID_COIN_SOLUTION, name_solution)
         if not isinstance(_[0], bytes) or len(_[0]) != 32:
             raise ConsensusError(Err.INVALID_COIN_SOLUTION, name_solution)
         if not isinstance(_[1], list) or len(_[1]) != 2:
             raise ConsensusError(Err.INVALID_COIN_SOLUTION, name_solution)
         puzzle_solution_program = name_solution.rest().first()
         puzzle_program = puzzle_solution_program.first()
         puzzle_hash = ProgramHash(Program(puzzle_program))
         npc_list.append((puzzle_hash, puzzle_solution_program))
     return npc_list
示例#29
0
 def as_make_puzzle(self, as_pubkey_sender, as_pubkey_receiver, as_amount,
                    as_timelock_block, as_secret_hash):
     as_pubkey_sender_cl = f"0x{as_pubkey_sender.hex()}"
     as_pubkey_receiver_cl = f"0x{as_pubkey_receiver.hex()}"
     as_payout_puzzlehash_receiver = ProgramHash(
         puzzle_for_pk(as_pubkey_receiver))
     as_payout_puzzlehash_sender = ProgramHash(
         puzzle_for_pk(as_pubkey_sender))
     payout_receiver = f"(c (q 0x{ConditionOpcode.CREATE_COIN.hex()}) (c (q 0x{as_payout_puzzlehash_receiver.hex()}) (c (q {as_amount}) (q ()))))"
     payout_sender = f"(c (q 0x{ConditionOpcode.CREATE_COIN.hex()}) (c (q 0x{as_payout_puzzlehash_sender.hex()}) (c (q {as_amount}) (q ()))))"
     aggsig_receiver = f"(c (q 0x{ConditionOpcode.AGG_SIG.hex()}) (c (q {as_pubkey_receiver_cl}) (c (sha256tree (a)) (q ()))))"
     aggsig_sender = f"(c (q 0x{ConditionOpcode.AGG_SIG.hex()}) (c (q {as_pubkey_sender_cl}) (c (sha256tree (a)) (q ()))))"
     receiver_puz = (
         f"((c (i (= (sha256 (f (r (a)))) (q {as_secret_hash})) (q (c " +
         aggsig_receiver + " (c " + payout_receiver +
         " (q ())))) (q (x (q 'invalid secret')))) (a))) ) ")
     timelock = f"(c (q 0x{ConditionOpcode.ASSERT_BLOCK_INDEX_EXCEEDS.hex()}) (c (q {as_timelock_block}) (q ()))) "
     sender_puz = "(c " + aggsig_sender + " (c " + timelock + " (c " + payout_sender + " (q ()))))"
     as_puz_sender = "((c (i (= (f (a)) (q 77777)) (q " + sender_puz + ") (q (x (q 'not a valid option'))) ) (a)))"
     as_puz = "((c (i (= (f (a)) (q 33333)) (q " + receiver_puz + " (q " + as_puz_sender + ")) (a)))"
     return Program(binutils.assemble(as_puz))
示例#30
0
class Wallet:
    seed = b'seed'
    next_address = 0
    pubkey_num_lookup = {}
    puzzle_generator = f"(c (q 5) (c (c (q 5) (c (q (q 0x{hexlify(ConditionOpcode.AGG_SIG).decode('ascii')})) (c (c (q 5) (c (c (q 1) (c (f (a)) (q ()))) (q ((c (sha256 (wrap (f (a)))) (q ())))))) (q ())))) (q (((c (f (a)) (f (r (a)))))))))"
    puzzle_generator_id = str(
        ProgramHash(Program(binutils.assemble(puzzle_generator))))

    def __init__(self):
        self.current_balance = 0
        self.my_utxos = set()
        self.seed = urandom(1024)
        self.extended_secret_key = ExtendedPrivateKey.from_seed(self.seed)
        # self.contacts = {}  # {'name': (puzzlegenerator, last, extradata)}
        self.generator_lookups = {}  # {generator_hash: generator}
        self.name = "MyChiaWallet"
        self.generator_lookups[
            self.puzzle_generator_id] = self.puzzle_generator
        self.temp_utxos = set()
        self.temp_balance = 0
        self.all_additions = {}
        self.all_deletions = {}

    def get_next_public_key(self):
        pubkey = self.extended_secret_key.public_child(
            self.next_address).get_public_key()
        self.pubkey_num_lookup[pubkey.serialize()] = self.next_address
        self.next_address = self.next_address + 1
        return pubkey

    # def add_contact(self, name, puzzlegenerator, last, extradata):
    #    if name in self.contacts:
    #        return None
    #    else:
    #        self.contacts[name] = [puzzlegenerator, last, extradata]

    def set_name(self, name):
        self.name = name

    def can_generate_puzzle_hash(self, hash):
        return any(
            map(
                lambda child: hash == ProgramHash(
                    puzzle_for_pk(
                        self.extended_secret_key.public_child(child).
                        get_public_key().serialize())),
                reversed(range(self.next_address))))

    def get_keys(self, hash):
        for child in range(self.next_address):
            pubkey = self.extended_secret_key.public_child(
                child).get_public_key()
            if hash == ProgramHash(self.puzzle_for_pk(pubkey.serialize())):
                return (pubkey, self.extended_secret_key.private_child(
                    child).get_private_key())

    def notify(self, additions, deletions):
        for coin in additions:
            if coin.name() in self.all_additions:
                continue
            self.all_additions[coin.name()] = coin
            if self.can_generate_puzzle_hash(coin.puzzle_hash):
                self.current_balance += coin.amount
                self.my_utxos.add(coin)
        for coin in deletions:
            if coin.name() in self.all_deletions:
                continue
            self.all_deletions[coin.name()] = coin
            if coin in self.my_utxos:
                self.my_utxos.remove(coin)
                self.current_balance -= coin.amount

        self.temp_utxos = self.my_utxos.copy()
        self.temp_balance = self.current_balance

    def select_coins(self, amount):
        if amount > self.temp_balance:
            return None
        used_utxos = set()
        while sum(map(lambda coin: coin.amount, used_utxos)) < amount:
            used_utxos.add(self.temp_utxos.pop())
        return used_utxos

    def puzzle_for_pk(self, pubkey):
        args = f"({pubkey_format(pubkey)})"
        puzzle = Program(
            clvm.eval_f(clvm.eval_f, binutils.assemble(self.puzzle_generator),
                        binutils.assemble(args)))
        return puzzle

    def get_new_puzzle(self):
        pubkey = self.get_next_public_key().serialize()
        puzzle = puzzle_for_pk(pubkey)
        return puzzle

    def get_new_puzzlehash(self):
        puzzle = self.get_new_puzzle()
        puzzlehash = ProgramHash(puzzle)
        return puzzlehash

    def sign(self, value, pubkey):
        privatekey = self.extended_secret_key.private_child(
            self.pubkey_num_lookup[pubkey]).get_private_key()
        blskey = BLSPrivateKey(privatekey)
        return blskey.sign(value)

    def generate_unsigned_transaction(self, amount, newpuzzlehash):
        if self.temp_balance < amount:
            return None  # TODO: Should we throw a proper error here, or just return None?
        utxos = self.select_coins(amount)
        spends = []
        output_id = None
        spend_value = sum([coin.amount for coin in utxos])
        change = spend_value - amount
        for coin in utxos:
            puzzle_hash = coin.puzzle_hash

            pubkey, secretkey = self.get_keys(puzzle_hash)
            puzzle = self.puzzle_for_pk(pubkey.serialize())
            if output_id is None:
                primaries = [{'puzzlehash': newpuzzlehash, 'amount': amount}]
                if change > 0:
                    changepuzzlehash = self.get_new_puzzlehash()
                    primaries.append({
                        'puzzlehash': changepuzzlehash,
                        'amount': change
                    })
                    # add change coin into temp_utxo set
                    self.temp_utxos.add(Coin(coin, changepuzzlehash, change))
                solution = make_solution(primaries=primaries)
                output_id = sha256(coin.name() + newpuzzlehash)
            else:
                solution = make_solution(consumed=[coin.name()])
            spends.append((puzzle, CoinSolution(coin, solution)))
        self.temp_balance -= amount
        return spends

    def sign_transaction(self, spends: (Program, [CoinSolution])):
        sigs = []
        for puzzle, solution in spends:
            pubkey, secretkey = self.get_keys(solution.coin.puzzle_hash)
            secretkey = BLSPrivateKey(secretkey)
            code_ = [puzzle, [solution.solution, []]]
            sexp = clvm.to_sexp_f(code_)
            conditions_dict = conditions_by_opcode(
                conditions_for_solution(sexp))
            for _ in hash_key_pairs_for_conditions_dict(conditions_dict):
                signature = secretkey.sign(_.message_hash)
                sigs.append(signature)
        aggsig = BLSSignature.aggregate(sigs)
        solution_list = CoinSolutionList([
            CoinSolution(
                coin_solution.coin,
                clvm.to_sexp_f([puzzle, [coin_solution.solution, []]]))
            for (puzzle, coin_solution) in spends
        ])
        spend_bundle = SpendBundle(solution_list, aggsig)
        return spend_bundle

    def generate_signed_transaction(self, amount, newpuzzlehash):
        transaction = self.generate_unsigned_transaction(amount, newpuzzlehash)
        if transaction is None:
            return None  # TODO: Should we throw a proper error here, or just return None?
        return self.sign_transaction(transaction)