def check_idempotency(f, args): cost, curried = curry(f, args) r = disassemble(curried) f_0, args_0 = uncurry(curried) assert disassemble(f_0) == disassemble(f) assert disassemble(args_0) == disassemble(args) return r
async def get_discrepancies_for_offer( self, file_path: Path ) -> Tuple[bool, Optional[Dict], Optional[Exception]]: try: self.log.info(f"trade offer: {file_path}") cc_discrepancies: Dict[bytes32, int] = dict() trade_offer_hex = file_path.read_text() trade_offer = SpendBundle.from_bytes( bytes.fromhex(trade_offer_hex)) for coinsol in trade_offer.coin_solutions: puzzle = coinsol.solution.first() solution = coinsol.solution.rest().first() # work out the deficits between coin amount and expected output for each if cc_wallet_puzzles.check_is_cc_puzzle(puzzle): parent_info = binutils.disassemble( solution.rest().first()).split(" ") if len(parent_info) > 1: colour = cc_wallet_puzzles.get_genesis_from_puzzle( binutils.disassemble(puzzle)) # get puzzle and solution innerpuzzlereveal = solution.rest().rest().rest( ).first() innersol = solution.rest().rest().rest().rest().first() # Get output amounts by running innerpuzzle and solution out_amount = cc_wallet_puzzles.get_output_amount_for_puzzle_and_solution( innerpuzzlereveal, innersol) # add discrepancy to dict of discrepancies if colour in cc_discrepancies: cc_discrepancies[ colour] += coinsol.coin.amount - out_amount else: cc_discrepancies[ colour] = coinsol.coin.amount - out_amount else: # standard chia coin coin_amount = coinsol.coin.amount out_amount = cc_wallet_puzzles.get_output_amount_for_puzzle_and_solution( puzzle, solution) diff = coin_amount - out_amount if "chia" in cc_discrepancies: cc_discrepancies[ "chia"] = cc_discrepancies["chia"] + diff else: cc_discrepancies["chia"] = diff return True, cc_discrepancies, None except Exception as e: return False, None, e
async def test_clvm_strict_mode(self, rust_checker: bool): block = Program.from_bytes(bytes(SMALL_BLOCK_GENERATOR.program)) disassembly = binutils.disassemble(block) # this is a valid generator program except the first clvm # if-condition, that depends on executing an unknown operator # ("0xfe"). In strict mode, this should fail, but in non-strict # mode, the unknown operator should be treated as if it returns (). program = SerializedProgram.from_bytes( binutils.assemble( f"(i (0xfe (q . 0)) (q . ()) {disassembly})").as_bin()) generator = BlockGenerator(program, []) npc_result: NPCResult = get_name_puzzle_conditions( generator, test_constants.MAX_BLOCK_COST_CLVM, cost_per_byte=test_constants.COST_PER_BYTE, safe_mode=True, rust_checker=rust_checker, ) assert npc_result.error is not None npc_result = get_name_puzzle_conditions( generator, test_constants.MAX_BLOCK_COST_CLVM, cost_per_byte=test_constants.COST_PER_BYTE, safe_mode=False, rust_checker=rust_checker, ) assert npc_result.error is None
async def test_clvm_max_cost(self): block = Program.from_bytes(bytes(SMALL_BLOCK_GENERATOR.program)) disassembly = binutils.disassemble(block) # this is a valid generator program except the first clvm # if-condition, that depends on executing an unknown operator # ("0xfe"). In strict mode, this should fail, but in non-strict # mode, the unknown operator should be treated as if it returns (). # the CLVM program has a cost of 391969 program = SerializedProgram.from_bytes( binutils.assemble( f"(i (softfork (q . 10000000)) (q . ()) {disassembly})"). as_bin()) # ensure we fail if the program exceeds the cost generator = BlockGenerator(program, []) npc_result: NPCResult = get_name_puzzle_conditions( generator, 10000000, False) assert npc_result.error is not None assert npc_result.clvm_cost == 0 # raise the max cost to make sure this passes # ensure we pass if the program does not exceeds the cost npc_result: NPCResult = get_name_puzzle_conditions( generator, 20000000, False) assert npc_result.error is None assert npc_result.clvm_cost > 10000000
def as_generate_secret_hash(self, secret): secret_hash_cl = f"(sha256 (q {secret}))" sec = f"({secret})" cost, secret_hash_preformat = clvm.run_program( binutils.assemble("(sha256 (f (a)))"), binutils.assemble(sec)) secret_hash = binutils.disassemble(secret_hash_preformat) return secret_hash
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 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 update_auditors_in_solution(solution: SExp, auditor_info): old_solution = binutils.disassemble(solution) # auditor is (primary_input, innerpuzzlehash, amount) new_solution = old_solution.replace( "))) ()) () ()))", f"))) ()) (0x{auditor_info[0]} 0x{auditor_info[1]} {auditor_info[2]}) ()))", ) return binutils.assemble(new_solution)
def as_generate_secret_hash(self, secret): secret_hash_cl = "(sha256 (q %s))" % (secret) sec = "(%s)" % secret secret_hash_preformat = clvm.eval_f( clvm.eval_f, binutils.assemble("(sha256 (f (a)))"), binutils.assemble(sec)) secret_hash = binutils.disassemble(secret_hash_preformat) return secret_hash
async def test_strict_mode(self, rust_checker: bool): wallet_tool = bt.get_pool_wallet_tool() ph = wallet_tool.get_new_puzzlehash() num_blocks = 3 blocks = bt.get_consecutive_blocks(num_blocks, [], guarantee_transaction_block=True, pool_reward_puzzle_hash=ph, farmer_reward_puzzle_hash=ph) coinbase = None for coin in blocks[2].get_included_reward_coins(): if coin.puzzle_hash == ph: coinbase = coin break assert coinbase is not None spend_bundle = wallet_tool.generate_signed_transaction( coinbase.amount, BURN_PUZZLE_HASH, coinbase, ) assert spend_bundle is not None pk = bytes.fromhex( "88bc9360319e7c54ab42e19e974288a2d7a817976f7633f4b43f36ce72074e59c4ab8ddac362202f3e366f0aebbb6280" ) puzzle = p2_delegated_puzzle_or_hidden_puzzle.puzzle_for_pk(pk) disassembly = binutils.disassemble(puzzle) program = SerializedProgram.from_bytes( binutils.assemble( f"(q ((0x3d2331635a58c0d49912bc1427d7db51afe3f20a7b4bcaffa17ee250dcbcbfaa {disassembly} 300" f" (() (q . ((65 '00000000000000000000000000000000' 0x0cbba106e000))) ()))))" ).as_bin()) generator = BlockGenerator(program, []) npc_result: NPCResult = get_name_puzzle_conditions( generator, test_constants.MAX_BLOCK_COST_CLVM, cost_per_byte=test_constants.COST_PER_BYTE, safe_mode=True, rust_checker=rust_checker, ) assert npc_result.error is not None npc_result = get_name_puzzle_conditions( generator, test_constants.MAX_BLOCK_COST_CLVM, cost_per_byte=test_constants.COST_PER_BYTE, safe_mode=False, rust_checker=rust_checker, ) assert npc_result.error is None coin_name = npc_result.npc_list[0].coin_name error, puzzle, solution = get_puzzle_and_solution_for_coin( generator, coin_name, test_constants.MAX_BLOCK_COST_CLVM) assert error is None
def check_is_cc_puzzle(puzzle: Program): puzzle_string = binutils.disassemble(puzzle) inner_puzzle = extract_hex_64(puzzle_string, idx=0) if inner_puzzle is None: return False if all(c in string.hexdigits for c in inner_puzzle) is not True: return False genesisCoin = get_genesis_from_puzzle(puzzle) if all(c in string.hexdigits for c in genesisCoin) is not True: return False return cc_make_puzzle(inner_puzzle, cc_make_core(genesisCoin)) == puzzle
def curry_cmd(program, args, treehash, dump, include): prog = parse_program(program, include) curry_args = [assemble(arg) for arg in args] prog_final = prog.curry(*curry_args) if treehash: print(prog_final.get_tree_hash()) elif dump: print(prog_final) else: print(disassemble(prog_final))
def pull_preimage(self, body, removals): for coin in removals: for swap in self.as_swap_list: if coin.puzzle_hash.hex() == swap["outgoing puzzlehash"]: l = [(puzzle_hash, puzzle_solution_program) for (puzzle_hash, puzzle_solution_program ) in self.as_solution_list(body.solution_program) ] for x in l: if x[0].hex() == coin.puzzle_hash.hex(): pre1 = binutils.disassemble(x[1]) preimage = pre1[(len(pre1) - 515):(len(pre1) - 3)] swap["secret"] = preimage
def adaptor_for_singleton_inner_puzzle(puzzle: Program) -> Program: """ The singleton puzzle requires an inner puzzle which gets passed some "truths" from the singleton that are guaranteed to be correct. Using these truths may reduce the size of the inner puzzle, since any values can be used knowing they are checked elsewhere. However, an inner puzzle that is not aware that this first argument contains these values can be "adapted" using this function to ignore the first argument (and slide the subsequent arguments over), allowing any inner puzzle that thinks it's an outer puzzle to work as a singleton inner puzzle. """ # this is pretty slow and lame return Program.to( binutils.assemble("(a (q . %s) 3)" % binutils.disassemble(puzzle)))
async def test_clvm_strict_mode(self): block = Program.from_bytes(bytes(SMALL_BLOCK_GENERATOR)) disassembly = binutils.disassemble(block) # this is a valid generator program except the first clvm # if-condition, that depends on executing an unknown operator # ("0xfe"). In strict mode, this should fail, but in non-strict # mode, the unknown operator should be treated as if it returns (). program = SerializedProgram.from_bytes( binutils.assemble( f"(i (0xfe (q . 0)) (q . ()) {disassembly})").as_bin()) error, npc_list, cost = get_name_puzzle_conditions(program, True) assert error is not None error, npc_list, cost = get_name_puzzle_conditions(program, False) assert error is None
def check_is_cc_puzzle(puzzle: Program): puzzle_string = binutils.disassemble(puzzle) if len(puzzle_string) < 4000: return False inner_puzzle = puzzle_string[11:75] if all(c in string.hexdigits for c in inner_puzzle) is not True: return False genesisCoin = get_genesis_from_puzzle(puzzle_string) if all(c in string.hexdigits for c in genesisCoin) is not True: return False if cc_make_puzzle(inner_puzzle, cc_make_core(genesisCoin)) == puzzle: return True else: return False
def get_output_amount_for_puzzle_and_solution(puzzle, solution): conditions = run_program(puzzle, solution)[1] amount = 0 while conditions != b"": opcode = conditions.first().first() if opcode == b"3": # Check if CREATE_COIN amount_str = binutils.disassemble( conditions.first().rest().rest().first()) if amount_str == "()": conditions = conditions.rest() continue elif amount_str[0:2] == "0x": # Check for wonky decompilation amount += int(amount_str, 16) else: amount += int(amount_str, 10) conditions = conditions.rest() return amount
def lower_quote(prog, macro_lookup=None, symbol_table=None, run_program=None): if prog.nullp(): return prog if prog.listp(): if prog.first().as_atom() == b"quote": # Note: quote should have exactly one arg, so the length of # quoted list should be 2: "(quote arg)" if not prog.rest().rest().nullp(): raise SyntaxError( "Compilation error while compiling [%s]. quote takes exactly one argument." % disassemble(prog)) return prog.to(quote(lower_quote(prog.rest().first()))) else: return prog.to( (lower_quote(prog.first()), lower_quote(prog.rest()))) else: return prog
async def create_spend_bundle_relative_amount(self, cc_amount, zero_coin: Coin = None): # 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() innerpuz: Program = await self.inner_puzzle_for_cc_puzzle( coin.puzzle_hash) parent_info = await self.get_parent_for_coin(coin) assert parent_info is not None assert self.cc_info.my_core is not None # Use coin info to create solution and add coin and solution to list of CoinSolutions solution = cc_wallet_puzzles.cc_make_solution( self.cc_info.my_core, ( parent_info.parent_name, parent_info.inner_puzzle_hash, parent_info.amount, ), coin.amount, binutils.disassemble(innerpuz), binutils.disassemble(innersol), None, None, ) list_of_solutions.append( CoinSolution( coin, Program.to([ cc_wallet_puzzles.cc_make_puzzle( innerpuz.get_tree_hash(), self.cc_info.my_core), solution, ]), )) sigs = sigs + await self.get_sigs(innerpuz, innersol) aggsig = AugSchemeMPL.aggregate(sigs) spend_bundle = SpendBundle(list_of_solutions, aggsig) return spend_bundle
async def generate_signed_transaction( self, amount: uint64, to_address: bytes32, fee: uint64 = uint64(0), origin_id: bytes32 = None, coins: Set[Coin] = None, ) -> Optional[TransactionRecord]: sigs: List[G2Element] = [] # Get coins and calculate amount of change required if coins is None: selected_coins: Optional[Set[Coin]] = await self.select_coins( amount) else: selected_coins = coins if selected_coins is None: return None total_amount = sum([x.amount for x in selected_coins]) change = total_amount - amount # first coin becomes the auditor special case auditor = selected_coins.pop() puzzle_hash = auditor.puzzle_hash inner_puzzle: Program = await self.inner_puzzle_for_cc_puzzle( puzzle_hash) auditor_info = ( auditor.parent_coin_info, inner_puzzle.get_tree_hash(), auditor.amount, ) list_of_solutions = [] # auditees should be (primary_input, innerpuzhash, coin_amount, output_amount) auditees = [( auditor.parent_coin_info, inner_puzzle.get_tree_hash(), auditor.amount, total_amount, )] for coin in selected_coins: coin_inner_puzzle: Program = await self.inner_puzzle_for_cc_puzzle( coin.puzzle_hash) auditees.append(( coin.parent_coin_info, coin_inner_puzzle[coin], coin.amount, 0, )) primaries = [{"puzzlehash": to_address, "amount": amount}] if change > 0: changepuzzlehash = await self.get_new_inner_hash() primaries.append({ "puzzlehash": changepuzzlehash, "amount": change }) innersol = self.standard_wallet.make_solution(primaries=primaries) sigs = sigs + await self.get_sigs(inner_puzzle, innersol) parent_info = await self.get_parent_for_coin(auditor) assert parent_info is not None assert self.cc_info.my_core is not None solution = cc_wallet_puzzles.cc_make_solution( self.cc_info.my_core, ( parent_info.parent_name, parent_info.inner_puzzle_hash, parent_info.amount, ), auditor.amount, binutils.disassemble(inner_puzzle), binutils.disassemble(innersol), auditor_info, auditees, False, ) main_coin_solution = CoinSolution( auditor, Program.to([ cc_wallet_puzzles.cc_make_puzzle( inner_puzzle.get_tree_hash(), self.cc_info.my_core, ), solution, ]), ) list_of_solutions.append(main_coin_solution) # main = SpendBundle([main_coin_solution], ZERO96) ephemeral_coin_solution = create_spend_for_ephemeral( auditor, auditor, total_amount) list_of_solutions.append(ephemeral_coin_solution) # eph = SpendBundle([ephemeral_coin_solution], ZERO96) auditor_coin_colution = create_spend_for_auditor(auditor, auditor) list_of_solutions.append(auditor_coin_colution) # aud = SpendBundle([auditor_coin_colution], ZERO96) # loop through remaining spends, treating them as aggregatees for coin in selected_coins: coin_inner_puzzle = await self.inner_puzzle_for_cc_puzzle( coin.puzzle_hash) innersol = self.standard_wallet.make_solution() parent_info = await self.get_parent_for_coin(coin) assert parent_info is not None sigs = sigs + await self.get_sigs(coin_inner_puzzle, innersol) solution = cc_wallet_puzzles.cc_make_solution( self.cc_info.my_core, ( parent_info.parent_name, parent_info.inner_puzzle_hash, parent_info.amount, ), coin.amount, binutils.disassemble(coin_inner_puzzle), binutils.disassemble(innersol), auditor_info, None, ) list_of_solutions.append( CoinSolution( coin, Program.to([ cc_wallet_puzzles.cc_make_puzzle( coin_inner_puzzle.get_tree_hash(), self.cc_info.my_core, ), solution, ]), )) list_of_solutions.append( create_spend_for_ephemeral(coin, auditor, 0)) list_of_solutions.append(create_spend_for_auditor(auditor, coin)) aggsig = AugSchemeMPL.aggregate(sigs) spend_bundle = SpendBundle(list_of_solutions, aggsig) tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=to_address, amount=uint64(amount), fee_amount=uint64(0), incoming=False, 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, ) return tx_record
async def search_for_parent_info(self, block_program: Program, removals: List[Coin]) -> bool: """ Returns an error if it's unable to evaluate, otherwise returns a list of NPC (coin_name, solved_puzzle_hash, conditions_dict) """ cost_sum = 0 try: cost_run, sexp = run_program(block_program, []) cost_sum += cost_run except EvalError: return False for name_solution in sexp.as_iter(): _ = name_solution.as_python() if len(_) != 2: return False if not isinstance(_[0], bytes) or len(_[0]) != 32: return False coin_name = bytes32(_[0]) if not isinstance(_[1], list) or len(_[1]) != 2: return False puzzle_solution_program = name_solution.rest().first() puzzle_program = puzzle_solution_program.first() try: error, conditions_dict, cost_run = conditions_dict_for_solution( puzzle_solution_program) cost_sum += cost_run if error: return False except EvalError: return False if conditions_dict is None: conditions_dict = {} if ConditionOpcode.CREATE_COIN in conditions_dict: created_output_conditions = conditions_dict[ ConditionOpcode.CREATE_COIN] else: continue for cvp in created_output_conditions: result = await self.wallet_state_manager.puzzle_store.wallet_info_for_puzzle_hash( cvp.var1) if result is None: continue wallet_id, wallet_type = result if wallet_id != self.wallet_info.id: continue coin = None for removed in removals: if removed.name() == coin_name: coin = removed break if coin is not None: if cc_wallet_puzzles.check_is_cc_puzzle(puzzle_program): puzzle_string = binutils.disassemble(puzzle_program) inner_puzzle_hash = hexstr_to_bytes( get_innerpuzzle_from_puzzle(puzzle_string)) self.log.info( f"parent: {coin_name} inner_puzzle for parent is {inner_puzzle_hash.hex()}" ) await self.add_parent( coin_name, CCParent(coin.parent_coin_info, inner_puzzle_hash, coin.amount), ) return True return False
def do_com_prog(prog, macro_lookup, symbol_table, run_program): """ Turn the given program `prog` into a clvm program using the macros to do transformation. prog is an uncompiled s-expression. Return a new expanded s-expression PROG_EXP that is equivalent by rewriting based upon the operator, where "equivalent" means (a (com (q PROG) (MACROS)) ARGS) == (a (q PROG_EXP) ARGS) for all ARGS. Also, (opt (com (q PROG) (MACROS))) == (opt (com (q PROG_EXP) (MACROS))) """ # lower "quote" to "q" prog = lower_quote(prog, macro_lookup, symbol_table, run_program) # quote atoms if prog.nullp() or not prog.listp(): atom = prog.as_atom() if atom == b"@": return prog.to(TOP.as_path()) for pair in symbol_table.as_iter(): symbol, value = pair.first(), pair.rest().first() if symbol == atom: return prog.to(value) return prog.to(quote(prog)) operator = prog.first() if operator.listp(): # (com ((OP) . RIGHT)) => (a (com (q OP)) 1) inner_exp = eval( prog.to([ b"com", quote(operator), quote(macro_lookup), quote(symbol_table) ]), TOP.as_path()) return prog.to([inner_exp]) as_atom = operator.as_atom() for macro_pair in macro_lookup.as_iter(): macro_name = macro_pair.first().as_atom() if macro_name == as_atom: macro_code = macro_pair.rest().first() post_prog = brun(macro_code, prog.rest()) return eval( post_prog.to([ b"com", post_prog, quote(macro_lookup), quote(symbol_table) ]), TOP.as_short_path()) if as_atom in COMPILE_BINDINGS: f = COMPILE_BINDINGS[as_atom] post_prog = f(prog.rest(), macro_lookup, symbol_table, run_program) return eval(prog.to(quote(post_prog)), TOP.as_path()) if operator == QUOTE_ATOM: return prog compiled_args = [ do_com_prog(_, macro_lookup, symbol_table, run_program) for _ in prog.rest().as_iter() ] r = prog.to([operator] + compiled_args) if as_atom in PASS_THROUGH_OPERATORS or as_atom.startswith(b"_"): return r for (symbol, value) in symbol_table.as_python(): if symbol == b"*": return r if symbol == as_atom: new_args = eval( prog.to([ b"opt", [ b"com", quote([b"list"] + list(prog.rest().as_iter())), quote(macro_lookup), quote(symbol_table) ] ]), TOP.as_path()) r = prog.to( [APPLY_ATOM, value, [CONS_ATOM, LEFT.as_path(), new_args]]) return r raise SyntaxError("can't compile %s, unknown operator" % disassemble(prog))
async def respond_to_offer( self, file_path: Path ) -> Tuple[bool, Optional[TradeRecord], Optional[str]]: has_wallets = await self.maybe_create_wallets_for_offer(file_path) if not has_wallets: return False, None, "Unknown Error" trade_offer_hex = file_path.read_text() trade_offer: TradeRecord = TradeRecord.from_bytes( hexstr_to_bytes(trade_offer_hex)) offer_spend_bundle = trade_offer.spend_bundle coinsols = [] # [] of CoinSolutions cc_coinsol_outamounts: Dict[bytes32, List[Tuple[Any, int]]] = dict() # Used for generating auditor solution, key is colour auditees: Dict[bytes32, List[Tuple[bytes32, bytes32, Any, int]]] = dict() aggsig = offer_spend_bundle.aggregated_signature cc_discrepancies: Dict[bytes32, int] = dict() chia_discrepancy = None wallets: Dict[bytes32, Any] = dict() # colour to wallet dict for coinsol in offer_spend_bundle.coin_solutions: puzzle = coinsol.solution.first() solution = coinsol.solution.rest().first() # work out the deficits between coin amount and expected output for each if cc_wallet_puzzles.check_is_cc_puzzle(puzzle): if not cc_wallet_puzzles.is_ephemeral_solution(solution): # Calculate output amounts colour = cc_wallet_puzzles.get_genesis_from_puzzle(puzzle) if colour not in wallets: wallets[ colour] = await self.wallet_state_manager.get_wallet_for_colour( colour) unspent = await self.wallet_state_manager.get_spendable_coins_for_wallet( wallets[colour].wallet_info.id) if coinsol.coin in [record.coin for record in unspent]: return False, None, "can't respond to own offer" innerpuzzlereveal = cc_wallet_puzzles.inner_puzzle( solution) innersol = cc_wallet_puzzles.inner_puzzle_solution( solution) out_amount = cc_wallet_puzzles.get_output_amount_for_puzzle_and_solution( innerpuzzlereveal, innersol) if colour in cc_discrepancies: cc_discrepancies[ colour] += coinsol.coin.amount - out_amount else: cc_discrepancies[ colour] = coinsol.coin.amount - out_amount # Store coinsol and output amount for later if colour in cc_coinsol_outamounts: cc_coinsol_outamounts[colour].append( (coinsol, out_amount)) else: cc_coinsol_outamounts[colour] = [(coinsol, out_amount)] # auditees should be (primary_input, innerpuzhash, coin_amount, output_amount) if colour in auditees: auditees[colour].append(( coinsol.coin.parent_coin_info, Program(innerpuzzlereveal).get_tree_hash(), coinsol.coin.amount, out_amount, )) else: auditees[colour] = [( coinsol.coin.parent_coin_info, Program(innerpuzzlereveal).get_tree_hash(), coinsol.coin.amount, out_amount, )] else: coinsols.append(coinsol) else: # standard chia coin unspent = await self.wallet_state_manager.get_spendable_coins_for_wallet( 1) if coinsol.coin in [record.coin for record in unspent]: return False, None, "can't respond to own offer" if chia_discrepancy is None: chia_discrepancy = cc_wallet_puzzles.get_output_discrepancy_for_puzzle_and_solution( coinsol.coin, puzzle, solution) else: chia_discrepancy += cc_wallet_puzzles.get_output_discrepancy_for_puzzle_and_solution( coinsol.coin, puzzle, solution) coinsols.append(coinsol) chia_spend_bundle: Optional[SpendBundle] = None if chia_discrepancy is not None: chia_spend_bundle = await self.wallet_state_manager.main_wallet.create_spend_bundle_relative_chia( chia_discrepancy, []) zero_spend_list: List[SpendBundle] = [] # create coloured coin self.log.info(cc_discrepancies) for colour in cc_discrepancies.keys(): if cc_discrepancies[colour] < 0: my_cc_spends = await wallets[colour].select_coins( abs(cc_discrepancies[colour])) else: if chia_spend_bundle is None: to_exclude: List = [] else: to_exclude = chia_spend_bundle.removals() my_cc_spends = await wallets[colour].select_coins(0) if my_cc_spends is None or my_cc_spends == set(): zero_spend_bundle: SpendBundle = await wallets[ colour].generate_zero_val_coin(False, to_exclude) if zero_spend_bundle is None: return ( False, None, "Unable to generate zero value coin. Confirm that you have chia available", ) zero_spend_list.append(zero_spend_bundle) additions = zero_spend_bundle.additions() removals = zero_spend_bundle.removals() my_cc_spends = set() for add in additions: if add not in removals and add.amount == 0: my_cc_spends.add(add) if my_cc_spends == set() or my_cc_spends is None: return False, None, "insufficient funds" auditor = my_cc_spends.pop() auditor_inner_puzzle = await self.get_inner_puzzle_for_puzzle_hash( auditor.puzzle_hash) assert auditor_inner_puzzle is not None inner_hash = auditor_inner_puzzle.get_tree_hash() auditor_info = ( auditor.parent_coin_info, inner_hash, auditor.amount, ) core = cc_wallet_puzzles.cc_make_core(colour) parent_info = await wallets[colour].get_parent_for_coin(auditor) for coloured_coin in my_cc_spends: inner_solution = self.wallet_state_manager.main_wallet.make_solution( consumed=[auditor.name()]) sig = await wallets[ colour].get_sigs_for_innerpuz_with_innersol( await self.get_inner_puzzle_for_puzzle_hash( coloured_coin.puzzle_hash), inner_solution, ) aggsig = AugSchemeMPL.aggregate([sig, aggsig]) inner_puzzle = await self.get_inner_puzzle_for_puzzle_hash( coloured_coin.puzzle_hash) assert inner_puzzle is not None # auditees should be (primary_input, innerpuzhash, coin_amount, output_amount) auditees[colour].append(( coloured_coin.parent_coin_info, inner_puzzle.get_tree_hash(), coloured_coin.amount, 0, )) solution = cc_wallet_puzzles.cc_make_solution( core, ( parent_info.parent_name, parent_info.inner_puzzle_hash, parent_info.amount, ), coloured_coin.amount, binutils.disassemble(inner_puzzle), binutils.disassemble(inner_solution), auditor_info, None, ) coin_spend = CoinSolution( coloured_coin, Program.to([ cc_wallet_puzzles.cc_make_puzzle( inner_puzzle.get_tree_hash(), core, ), solution, ]), ) coinsols.append(coin_spend) ephemeral = cc_wallet_puzzles.create_spend_for_ephemeral( coloured_coin, auditor, 0) coinsols.append(ephemeral) auditor = cc_wallet_puzzles.create_spend_for_auditor( auditor, coloured_coin) coinsols.append(auditor) # Tweak the offer's solution to include the new auditor for cc_coinsol_out in cc_coinsol_outamounts[colour]: cc_coinsol = cc_coinsol_out[0] new_solution = cc_wallet_puzzles.update_auditors_in_solution( cc_coinsol.solution, auditor_info) new_coinsol = CoinSolution(cc_coinsol.coin, new_solution) coinsols.append(new_coinsol) eph = cc_wallet_puzzles.create_spend_for_ephemeral( cc_coinsol.coin, auditor, cc_coinsol_out[1]) coinsols.append(eph) aud = cc_wallet_puzzles.create_spend_for_auditor( auditor, cc_coinsol.coin) coinsols.append(aud) # Finish the auditor CoinSolution with new information newinnerpuzhash = await wallets[colour].get_new_inner_hash() outputamount = (sum([c.amount for c in my_cc_spends]) + cc_discrepancies[colour] + auditor.amount) innersol = self.wallet_state_manager.main_wallet.make_solution( primaries=[{ "puzzlehash": newinnerpuzhash, "amount": outputamount }]) parent_info = await wallets[colour].get_parent_for_coin(auditor) auditees[colour].append(( auditor.parent_coin_info, auditor_inner_puzzle.get_tree_hash(), auditor.amount, outputamount, )) sigs: List[G2Element] = await wallets[colour].get_sigs( auditor_inner_puzzle, innersol) aggsig = AugSchemeMPL.aggregate(sigs + [aggsig]) solution = cc_wallet_puzzles.cc_make_solution( core, ( parent_info.parent_name, parent_info.inner_puzzle_hash, parent_info.amount, ), auditor.amount, binutils.disassemble(auditor_inner_puzzle), binutils.disassemble(innersol), auditor_info, auditees[colour], ) cs = CoinSolution( auditor, Program.to([ cc_wallet_puzzles.cc_make_puzzle( auditor_inner_puzzle.get_tree_hash(), core), solution, ]), ) coinsols.append(cs) cs_eph = create_spend_for_ephemeral(auditor, auditor, outputamount) coinsols.append(cs_eph) cs_aud = create_spend_for_auditor(auditor, auditor) coinsols.append(cs_aud) spend_bundle = SpendBundle(coinsols, aggsig) my_tx_records = [] if zero_spend_list is not None: zero_spend_list.append(spend_bundle) spend_bundle = SpendBundle.aggregate(zero_spend_list) # Add transaction history hor this trade now = uint64(int(time.time())) if chia_spend_bundle is not None: spend_bundle = SpendBundle.aggregate( [spend_bundle, chia_spend_bundle]) if chia_discrepancy < 0: tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=now, to_puzzle_hash=token_bytes(), amount=uint64(abs(chia_discrepancy)), fee_amount=uint64(0), incoming=False, confirmed=False, sent=uint32(10), spend_bundle=chia_spend_bundle, additions=chia_spend_bundle.additions(), removals=chia_spend_bundle.removals(), wallet_id=uint32(1), sent_to=[], trade_id=std_hash(spend_bundle.name() + bytes(now)), ) else: tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=token_bytes(), amount=uint64(abs(chia_discrepancy)), fee_amount=uint64(0), incoming=True, confirmed=False, sent=uint32(10), spend_bundle=chia_spend_bundle, additions=chia_spend_bundle.additions(), removals=chia_spend_bundle.removals(), wallet_id=uint32(1), sent_to=[], trade_id=std_hash(spend_bundle.name() + bytes(now)), ) my_tx_records.append(tx_record) for colour, amount in cc_discrepancies.items(): wallet = wallets[colour] if chia_discrepancy > 0: tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=token_bytes(), amount=uint64(abs(amount)), fee_amount=uint64(0), incoming=False, confirmed=False, sent=uint32(10), spend_bundle=spend_bundle, additions=spend_bundle.additions(), removals=spend_bundle.removals(), wallet_id=wallet.wallet_info.id, sent_to=[], trade_id=std_hash(spend_bundle.name() + bytes(now)), ) else: tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=token_bytes(), amount=uint64(abs(amount)), fee_amount=uint64(0), incoming=True, confirmed=False, sent=uint32(10), spend_bundle=spend_bundle, additions=spend_bundle.additions(), removals=spend_bundle.removals(), wallet_id=wallet.wallet_info.id, sent_to=[], trade_id=std_hash(spend_bundle.name() + bytes(now)), ) my_tx_records.append(tx_record) tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=token_bytes(), amount=uint64(0), fee_amount=uint64(0), incoming=False, confirmed=False, sent=uint32(0), spend_bundle=spend_bundle, additions=spend_bundle.additions(), removals=spend_bundle.removals(), wallet_id=uint32(0), sent_to=[], trade_id=std_hash(spend_bundle.name() + bytes(now)), ) now = uint64(int(time.time())) trade_record: TradeRecord = TradeRecord( confirmed_at_index=uint32(0), accepted_at_time=now, created_at_time=now, my_offer=False, sent=uint32(0), spend_bundle=offer_spend_bundle, tx_spend_bundle=spend_bundle, additions=spend_bundle.additions(), removals=spend_bundle.removals(), trade_id=std_hash(spend_bundle.name() + bytes(now)), status=uint32(TradeStatus.PENDING_CONFIRM.value), sent_to=[], ) await self.save_trade(trade_record) await self.wallet_state_manager.add_pending_transaction(tx_record) for tx in my_tx_records: await self.wallet_state_manager.add_transaction(tx) return True, trade_record, None
def adaptor_for_singleton_inner_puzzle(puzzle: Program) -> Program: # this is prety slow return Program.to( binutils.assemble("(a (q . %s) 3)" % binutils.disassemble(puzzle)))
def get_genesis_from_puzzle(puzzle: SExp): return extract_hex_64(binutils.disassemble(puzzle))
def compile_mod(args, macro_lookup, symbol_table, run_program): """ Deal with the "mod" keyword. """ (functions, constants, macros) = compile_mod_stage_1(args, run_program) # move macros into the macro lookup macro_lookup_program = build_macro_lookup_program(macro_lookup, macros, run_program) # get a list of all symbols that are possibly used all_constants_names = build_used_constants_names(functions, constants, macros) has_constants_tree = len(all_constants_names) > 0 # build defuns table, with function names as keys constants_tree = args.to(build_tree(all_constants_names)) constants_root_node = LEFT if has_constants_tree: args_root_node = RIGHT else: args_root_node = TOP constants_symbol_table = symbol_table_for_tree(constants_tree, constants_root_node) compiled_functions = compile_functions(functions, macro_lookup_program, constants_symbol_table, args_root_node) main_path_src = binutils.disassemble(compiled_functions[MAIN_NAME]) if has_constants_tree: all_constants_lookup = { k: v for k, v in compiled_functions.items() if k in all_constants_names } all_constants_lookup.update(constants) all_constants_list = [ all_constants_lookup[_] for _ in all_constants_names ] all_constants_tree_program = args.to( build_tree_program(all_constants_list)) all_constants_tree_src = binutils.disassemble( all_constants_tree_program) arg_tree_src = "(c %s 1)" % all_constants_tree_src else: arg_tree_src = "1" main_code = "(opt (q . (a %s %s)))" % (main_path_src, arg_tree_src) if has_constants_tree: build_symbol_dump(all_constants_lookup, run_program, "main.sym") return binutils.assemble(main_code)
# tool to decompile a fuzz_run_program test case to human readable form import sys import io from ir import reader from clvm_tools import binutils from clvm.serialize import sexp_from_stream from clvm import to_sexp_f with open(sys.argv[1], 'rb') as f: blob = f.read() sexp = sexp_from_stream(io.BytesIO(blob), to_sexp_f) print(binutils.disassemble(sexp))
def disassemble_cmd(programs): for program in programs: print(disassemble(parse_program(program)))