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 test_farm_block_one_spendbundle(): REWARD = 10000 unspent_db = RAM_DB() chain_view = ChainView.for_genesis_hash(GENESIS_BLOCK, unspent_db) pos = ProofOfSpace(get_pool_public_key(), get_plot_public_key()) puzzle_hash = puzzle_hash_for_index(1) empty_spend_bundle = SpendBundle.aggregate([]) header, header_signature, body = farm_block(GENESIS_BLOCK, Signature.zero(), 1, pos, empty_spend_bundle, puzzle_hash, REWARD) coinbase_coin = body.coinbase_coin conditions = standard_conditions() spend_bundle = spend_coin(coin=coinbase_coin, conditions=conditions, index=1) header, header_signature, body = farm_block(GENESIS_BLOCK, Signature.zero(), 1, pos, spend_bundle, puzzle_hash, REWARD) removals = removals_for_body(body) assert len(removals) == 1 assert removals[0] == list(spend_bundle.coin_solutions)[0].coin.name() run = asyncio.get_event_loop().run_until_complete additions, removals = run( chain_view.accept_new_block(header, unspent_db, REWARD, 0)) assert len(additions) == 4 assert len(removals) == 1
def farm_new_block(previous_header: HeaderHash, previous_signature: Signature, block_index: int, proof_of_space: ProofOfSpace, spend_bundle: SpendBundle, coinbase_coin: Coin, coinbase_signature: BLSSignature, fees_puzzle_hash: ProgramHash, timestamp: uint64): """ Steps: - collect up a consistent set of removals and solutions - run solutions to get the additions - select a timestamp = max(now, minimum_legal_timestamp) - create blank extension data - collect up coinbase coin with coinbase signature (if solo mining, we get these locally) - return Header, Body """ program_cost = 0 assert validate_spend_bundle_signature(spend_bundle) solution_program = best_solution_program(spend_bundle) extension_data = std_hash(b'') block_index_hash = block_index.to_bytes(32, "big") fees_coin = Coin(block_index_hash, fees_puzzle_hash, spend_bundle.fees()) body = Body(coinbase_signature, coinbase_coin, fees_coin, solution_program, program_cost, spend_bundle.aggregated_signature) header = Header(previous_header, previous_signature, timestamp, proof_of_space, body, extension_data) return header, body
def test_farm_two_blocks(): """ In this test, we farm two blocks: one empty block, then one block which spends the coinbase transaction from the empty block. """ REWARD = 10000 unspent_db = RAM_DB() chain_view = ChainView.for_genesis_hash(GENESIS_BLOCK, unspent_db) assert chain_view.genesis_hash == GENESIS_BLOCK assert chain_view.tip_hash == HeaderHash(GENESIS_BLOCK) assert chain_view.tip_index == 0 assert chain_view.unspent_db == unspent_db pos_1 = ProofOfSpace(get_pool_public_key(), get_plot_public_key()) puzzle_hash = puzzle_hash_for_index(1) empty_spend_bundle = SpendBundle.aggregate([]) header, header_signature, body = farm_block(GENESIS_BLOCK, Signature.zero(), 1, pos_1, empty_spend_bundle, puzzle_hash, REWARD) run = asyncio.get_event_loop().run_until_complete additions, removals = run( chain_view.accept_new_block(header, unspent_db, REWARD, 0)) assert len(additions) == 2 assert len(removals) == 0 # TODO: check additions assert additions[1].puzzle_hash == body.fees_coin.puzzle_hash assert additions[1].amount == 0 chain_view = run( chain_view.augment_chain_view(header, header_signature, unspent_db, unspent_db, REWARD, 0)) assert chain_view.genesis_hash == GENESIS_BLOCK assert chain_view.tip_hash == HeaderHash(header) assert chain_view.tip_index == 1 assert chain_view.unspent_db == unspent_db conditions = standard_conditions() spend_bundle_2 = spend_coin(coin=additions[0], conditions=conditions, index=1) assert validate_spend_bundle_signature(spend_bundle_2) pos_2 = ProofOfSpace(get_pool_public_key(1), get_plot_public_key()) header_2, header_signature_2, body_2 = farm_block(header, header_signature, 2, pos_2, spend_bundle_2, puzzle_hash, REWARD) print(header_2) print(header_signature_2) removals = removals_for_body(body_2) assert len(removals) == 1 assert removals[0] == list(spend_bundle_2.coin_solutions)[0].coin.name()
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)
async def new_chain_view(self, chain_view, spend_bundles, coinbase_puzzle_hash, fees_puzzle_hash, storage, unspent_db): block_number = chain_view.tip_index + 1 REWARD = int(1e9) timestamp = uint64(self._now / 1000) pool_public_key = get_pool_public_key() plot_public_key = get_plot_public_key() pos = ProofOfSpace(pool_public_key, plot_public_key) coinbase_coin, coinbase_signature = create_coinbase_coin_and_signature( block_number, coinbase_puzzle_hash, REWARD, pool_public_key) spend_bundle = SpendBundle.aggregate(spend_bundles) header, body = farm_new_block(chain_view.tip_hash, chain_view.tip_signature, block_number, pos, spend_bundle, coinbase_coin, coinbase_signature, fees_puzzle_hash, timestamp) header_signature = sign_header(header, plot_public_key) [await storage.add_preimage(bytes(_)) for _ in (header, body)] chain_view = await chain_view.augment_chain_view( header, header_signature, storage, unspent_db, REWARD, self._now) return chain_view
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 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_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 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 sign_transaction(self, spends: (Program, [CoinSolution])): sigs = [] for puzzle, solution in spends: pubkey, secretkey = self.get_keys(solution.coin.puzzle_hash) 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 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
def test_farm_block_empty(): REWARD = 10000 unspent_db = RAM_DB() chain_view = ChainView.for_genesis_hash(GENESIS_BLOCK, unspent_db) pos = ProofOfSpace(get_pool_public_key(), get_plot_public_key()) puzzle_hash = puzzle_hash_for_index(1) spend_bundle = SpendBundle.aggregate([]) header, header_signature, body = farm_block(GENESIS_BLOCK, Signature.zero(), 1, pos, spend_bundle, puzzle_hash, REWARD) removals = removals_for_body(body) assert len(removals) == 0 run = asyncio.get_event_loop().run_until_complete additions, removals = run( chain_view.accept_new_block(header, unspent_db, REWARD, 0)) assert len(additions) == 2 assert len(removals) == 0
def build_spend_bundle(coin, solution, sign_f=DEFAULT_SIGNER): coin_solution = CoinSolution(coin, solution) signature = signature_for_solution(solution, sign_f) return SpendBundle([coin_solution], signature)
def collect_best_bundle(known_bundles) -> SpendBundle: # this is way too simple spend_bundle = SpendBundle.aggregate(known_bundles) assert spend_bundle.fees() >= 0 return spend_bundle
def finalize_pst(wallet, pst, sigs): """ Return a pair (SpendBundle or None, summary_list). If we have a finalized SpendBundle, it's returned, otherwise None, The summary_list item is a list of items (coin, hkp_list, sigs_to_use, m) which allows the UI to give the end user information about which coins still need signatures. Note that hkp is short for hash_key_pair (ie. aggsig pair) """ m = wallet.m() coin_solutions = [] sig_dict = sigs_to_aggsig_sig_dict(wallet, pst, sigs) all_sigs_to_use = [] summary_list = [] for coin_solution in pst.get("coin_solutions"): coin, solution = coin_solution.coin, coin_solution.solution # run maximal_solution and get conditions conditions_dict = conditions_dict_for_solution(solution) # look for AGG_SIG conditions hkp_list = hash_key_pairs_for_conditions_dict(conditions_dict) # see if we have enough info to build signatures found_list = [] sigs_to_use = [] for aggsig_pair in hkp_list: add_me = 0 if len(sigs_to_use) < m: if aggsig_pair in sig_dict: sigs_to_use.append(sig_dict[aggsig_pair]) add_me = 1 found_list.append(add_me) all_sigs_to_use.extend(sigs_to_use) conditions = pst.get("conditions") delegated_puzzle = puzzle_for_conditions(conditions) delegated_solution = solution_for_conditions(conditions) index = wallet.index_for_puzzle_hash(coin.puzzle_hash, GAP_LIMIT) pub_keys = wallet.pub_keys_for_index(index) actual_solution = solution_for_delegated_puzzle( m, pub_keys, found_list, delegated_puzzle, delegated_solution ) coin_solution = CoinSolution(coin, actual_solution) coin_solutions.append(coin_solution) summary = (coin, hkp_list, sigs_to_use, m) summary_list.append(summary) if len(all_sigs_to_use) > 0: aggregated_sig = all_sigs_to_use[0].aggregate(all_sigs_to_use) spend_bundle = SpendBundle(coin_solutions, aggregated_sig) try: if validate_spend_bundle_signature(spend_bundle): return spend_bundle, summary_list except Exception: pass return None, summary_list
def build_spend_bundle(coin, solution, keychain=DEFAULT_KEYCHAIN): coin_solution = CoinSolution(coin, solution) signature = keychain.signature_for_solution(solution) return SpendBundle([coin_solution], signature)
def fuzz_signature(spend_bundle: SpendBundle): bls_private_key = bls_private_key_for_index(0) signature = bls_private_key.sign(b'\x11' * 32) return SpendBundle(spend_bundle.coin_solutions, signature)