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)
def puzzle_for_m_of_public_key_list(m, public_key_list): format_tuple = tuple( binutils.disassemble(Program.to(_)) for _ in (puzzle_prog_template, m, public_key_list)) puzzle_src = "((c (q %s) (c (q %s) (c (q %s) (a)))))" % format_tuple puzzle_prog = binutils.assemble(puzzle_src) return Program.to(puzzle_prog)
def name_puzzle_conditions_list(body_program): """ Return a list of tuples of (coin_name, solved_puzzle_hash, conditions_dict) """ try: sexp = Program.to(body_program).run([]) 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
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
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)
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
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))
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
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))
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)
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 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)
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))
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))
def load_clvm(filename): for p in path_list_for_filename(filename): if os.path.isfile(p): break clvm_hex = open(p, "rt").read() clvm_blob = bytes.fromhex(clvm_hex) return Program.from_bytes(clvm_blob)
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))
def solution_with_hidden_puzzle(hidden_public_key, hidden_puzzle, solution_to_hidden_puzzle): synthetic_public_key = calculate_synthetic_public_key( hidden_public_key, hidden_puzzle) puzzle = puzzle_for_synthetic_public_key(synthetic_public_key) return Program.to([ puzzle, [hidden_public_key, hidden_puzzle, solution_to_hidden_puzzle] ])
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))
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")
def best_solution_program(bundle: SpendBundle): """ This could potentially do a lot of clever and complicated compression optimizations in conjunction with choosing the set of SpendBundles to include. For now, we just quote the solutions we know. """ r = [] for coin_solution in bundle.coin_solutions: entry = [coin_solution.coin.name(), coin_solution.solution] r.append(entry) return Program.to([binutils.assemble("#q"), r])
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))
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
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))
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
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
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))
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
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