async def test_delegated_tail(self, setup_sim): sim, sim_client = setup_sim try: standard_acs = Program.to(1) standard_acs_ph: bytes32 = standard_acs.get_tree_hash() await sim.farm_block(standard_acs_ph) starting_coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(standard_acs_ph))[0].coin sk = PrivateKey.from_bytes(secret_exponent_for_index(1).to_bytes(32, "big")) tail: Program = DelegatedLimitations.construct([Program.to(sk.get_g1())]) cat_puzzle: Program = construct_cat_puzzle(CAT_MOD, tail.get_tree_hash(), acs) cat_ph: bytes32 = cat_puzzle.get_tree_hash() await sim_client.push_tx( SpendBundle( [CoinSpend(starting_coin, standard_acs, Program.to([[51, cat_ph, starting_coin.amount]]))], G2Element(), ) ) await sim.farm_block() # We're signing a different tail to use here name_as_program = Program.to(starting_coin.name()) new_tail: Program = GenesisById.construct([name_as_program]) checker_solution: Program = DelegatedLimitations.solve( [name_as_program], { "signed_program": { "identifier": "genesis_by_id", "args": [str(name_as_program)], }, "program_arguments": {}, }, ) signature: G2Element = AugSchemeMPL.sign(sk, new_tail.get_tree_hash()) await self.do_spend( sim, sim_client, tail, [(await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False))[0].coin], [NO_LINEAGE_PROOF], [ Program.to( [ [51, acs.get_tree_hash(), starting_coin.amount], [51, 0, -113, tail, checker_solution], ] ) ], (MempoolInclusionStatus.SUCCESS, None), signatures=[signature], limitations_solutions=[checker_solution], cost_str="Delegated Genesis", ) finally: await sim.close()
async def generate_issuance_bundle( cls, wallet, _: Dict, amount: uint64) -> Tuple[TransactionRecord, SpendBundle]: coins = await wallet.standard_wallet.select_coins(amount) origin = coins.copy().pop() origin_id = origin.name() cc_inner: Program = await wallet.get_new_inner_puzzle() await wallet.add_lineage(origin_id, LineageProof()) genesis_coin_checker: Program = cls.construct([Program.to(origin_id)]) minted_cc_puzzle_hash: bytes32 = construct_cat_puzzle( CAT_MOD, genesis_coin_checker.get_tree_hash(), cc_inner).get_tree_hash() tx_record: TransactionRecord = await wallet.standard_wallet.generate_signed_transaction( amount, minted_cc_puzzle_hash, uint64(0), origin_id, coins) assert tx_record.spend_bundle is not None inner_solution = wallet.standard_wallet.add_condition_to_solution( Program.to([51, 0, -113, genesis_coin_checker, []]), wallet.standard_wallet.make_solution(primaries=[{ "puzzlehash": cc_inner.get_tree_hash(), "amount": amount }], ), ) eve_spend = unsigned_spend_bundle_for_spendable_cats( CAT_MOD, [ SpendableCAT( list( filter(lambda a: a.amount == amount, tx_record.additions))[0], genesis_coin_checker.get_tree_hash(), cc_inner, inner_solution, limitations_program_reveal=genesis_coin_checker, ) ], ) signed_eve_spend = await wallet.sign(eve_spend) if wallet.cat_info.my_tail is None: await wallet.save_info( CATInfo(genesis_coin_checker.get_tree_hash(), genesis_coin_checker, wallet.cat_info.lineage_proofs), False, ) return tx_record, SpendBundle.aggregate( [tx_record.spend_bundle, signed_eve_spend])
async def check_all_there(): spendable = await cat_wallet.get_cat_spendable_coins() spendable_name_set = set() for record in spendable: spendable_name_set.add(record.coin.name()) puzzle_hash = construct_cat_puzzle( CAT_MOD, cat_wallet.cat_info.limitations_program_hash, cat_2).get_tree_hash() for i in range(1, 50): coin = Coin(spent_coint.name(), puzzle_hash, i) if coin.name() not in spendable_name_set: return False return True
async def test_genesis_by_puzhash(self, setup_sim): sim, sim_client = setup_sim try: standard_acs = Program.to(1) standard_acs_ph: bytes32 = standard_acs.get_tree_hash() await sim.farm_block(standard_acs_ph) starting_coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(standard_acs_ph))[0].coin tail: Program = GenesisByPuzhash.construct([Program.to(starting_coin.puzzle_hash)]) checker_solution: Program = GenesisByPuzhash.solve([], starting_coin.to_json_dict()) cat_puzzle: Program = construct_cat_puzzle(CAT_MOD, tail.get_tree_hash(), acs) cat_ph: bytes32 = cat_puzzle.get_tree_hash() await sim_client.push_tx( SpendBundle( [CoinSpend(starting_coin, standard_acs, Program.to([[51, cat_ph, starting_coin.amount]]))], G2Element(), ) ) await sim.farm_block() await self.do_spend( sim, sim_client, tail, [(await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False))[0].coin], [NO_LINEAGE_PROOF], [ Program.to( [ [51, acs.get_tree_hash(), starting_coin.amount], [51, 0, -113, tail, checker_solution], ] ) ], (MempoolInclusionStatus.SUCCESS, None), limitations_solutions=[checker_solution], cost_str="Genesis by Puzhash", ) finally: await sim.close()
async def test_everything_with_signature(self, setup_sim): sim, sim_client = setup_sim try: sk = PrivateKey.from_bytes(secret_exponent_for_index(1).to_bytes(32, "big")) tail: Program = EverythingWithSig.construct([Program.to(sk.get_g1())]) checker_solution: Program = EverythingWithSig.solve([], {}) cat_puzzle: Program = construct_cat_puzzle(CAT_MOD, tail.get_tree_hash(), acs) cat_ph: bytes32 = cat_puzzle.get_tree_hash() await sim.farm_block(cat_ph) # Test eve spend # We don't sign any message data because CLVM 0 translates to b'' apparently starting_coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(cat_ph))[0].coin signature: G2Element = AugSchemeMPL.sign( sk, (starting_coin.name() + sim.defaults.AGG_SIG_ME_ADDITIONAL_DATA) ) await self.do_spend( sim, sim_client, tail, [starting_coin], [NO_LINEAGE_PROOF], [ Program.to( [ [51, acs.get_tree_hash(), starting_coin.amount], [51, 0, -113, tail, checker_solution], ] ) ], (MempoolInclusionStatus.SUCCESS, None), limitations_solutions=[checker_solution], signatures=[signature], cost_str="Signature Issuance", ) # Test melting value coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False))[0].coin signature = AugSchemeMPL.sign( sk, (int_to_bytes(-1) + coin.name() + sim.defaults.AGG_SIG_ME_ADDITIONAL_DATA) ) await self.do_spend( sim, sim_client, tail, [coin], [NO_LINEAGE_PROOF], [ Program.to( [ [51, acs.get_tree_hash(), coin.amount - 1], [51, 0, -113, tail, checker_solution], ] ) ], (MempoolInclusionStatus.SUCCESS, None), extra_deltas=[-1], limitations_solutions=[checker_solution], signatures=[signature], cost_str="Signature Melt", ) # Test minting value coin = (await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False))[0].coin signature = AugSchemeMPL.sign(sk, (int_to_bytes(1) + coin.name() + sim.defaults.AGG_SIG_ME_ADDITIONAL_DATA)) # Need something to fund the minting temp_p = Program.to(1) temp_ph: bytes32 = temp_p.get_tree_hash() await sim.farm_block(temp_ph) acs_coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(temp_ph, include_spent_coins=False))[ 0 ].coin acs_bundle = SpendBundle( [ CoinSpend( acs_coin, temp_p, Program.to([]), ) ], G2Element(), ) await self.do_spend( sim, sim_client, tail, [coin], [NO_LINEAGE_PROOF], [ Program.to( [ [51, acs.get_tree_hash(), coin.amount + 1], [51, 0, -113, tail, checker_solution], ] ) ], (MempoolInclusionStatus.SUCCESS, None), extra_deltas=[1], limitations_solutions=[checker_solution], signatures=[signature], additional_spends=[acs_bundle], cost_str="Signature Mint", ) finally: await sim.close()
async def test_complex_spend(self, setup_sim): sim, sim_client = setup_sim try: tail = Program.to([]) checker_solution = Program.to([]) cat_puzzle: Program = construct_cat_puzzle(CAT_MOD, tail.get_tree_hash(), acs) cat_ph: bytes32 = cat_puzzle.get_tree_hash() await sim.farm_block(cat_ph) await sim.farm_block(cat_ph) cat_records = await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False) parent_of_mint = cat_records[0].coin parent_of_melt = cat_records[1].coin eve_to_mint = cat_records[2].coin eve_to_melt = cat_records[3].coin # Spend two of them to make them non-eve await self.do_spend( sim, sim_client, tail, [parent_of_mint, parent_of_melt], [NO_LINEAGE_PROOF, NO_LINEAGE_PROOF], [ Program.to( [ [51, acs.get_tree_hash(), parent_of_mint.amount], [51, 0, -113, tail, checker_solution], ] ), Program.to( [ [51, acs.get_tree_hash(), parent_of_melt.amount], [51, 0, -113, tail, checker_solution], ] ), ], (MempoolInclusionStatus.SUCCESS, None), limitations_solutions=[checker_solution] * 2, cost_str="Spend two eves", ) # Make the lineage proofs for the non-eves mint_lineage = LineageProof(parent_of_mint.parent_coin_info, acs_ph, parent_of_mint.amount) melt_lineage = LineageProof(parent_of_melt.parent_coin_info, acs_ph, parent_of_melt.amount) # Find the two new coins all_cats = await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False) all_cat_coins = [cr.coin for cr in all_cats] standard_to_mint = list(filter(lambda cr: cr.parent_coin_info == parent_of_mint.name(), all_cat_coins))[0] standard_to_melt = list(filter(lambda cr: cr.parent_coin_info == parent_of_melt.name(), all_cat_coins))[0] # Do the complex spend # We have both and eve and non-eve doing both minting and melting await self.do_spend( sim, sim_client, tail, [eve_to_mint, eve_to_melt, standard_to_mint, standard_to_melt], [NO_LINEAGE_PROOF, NO_LINEAGE_PROOF, mint_lineage, melt_lineage], [ Program.to( [ [51, acs.get_tree_hash(), eve_to_mint.amount + 13], [51, 0, -113, tail, checker_solution], ] ), Program.to( [ [51, acs.get_tree_hash(), eve_to_melt.amount - 21], [51, 0, -113, tail, checker_solution], ] ), Program.to( [ [51, acs.get_tree_hash(), standard_to_mint.amount + 21], [51, 0, -113, tail, checker_solution], ] ), Program.to( [ [51, acs.get_tree_hash(), standard_to_melt.amount - 13], [51, 0, -113, tail, checker_solution], ] ), ], (MempoolInclusionStatus.SUCCESS, None), limitations_solutions=[checker_solution] * 4, extra_deltas=[13, -21, 21, -13], cost_str="Complex Spend", ) finally: await sim.close()
async def test_cat_mod(self, setup_sim): sim, sim_client = setup_sim try: tail = Program.to([]) checker_solution = Program.to([]) cat_puzzle: Program = construct_cat_puzzle(CAT_MOD, tail.get_tree_hash(), acs) cat_ph: bytes32 = cat_puzzle.get_tree_hash() await sim.farm_block(cat_ph) starting_coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(cat_ph))[0].coin # Testing the eve spend await self.do_spend( sim, sim_client, tail, [starting_coin], [NO_LINEAGE_PROOF], [ Program.to( [ [51, acs.get_tree_hash(), starting_coin.amount - 3, [b"memo"]], [51, acs.get_tree_hash(), 1], [51, acs.get_tree_hash(), 2], [51, 0, -113, tail, checker_solution], ] ) ], (MempoolInclusionStatus.SUCCESS, None), limitations_solutions=[checker_solution], cost_str="Eve Spend", ) # There's 4 total coins at this point. A farming reward and the three children of the spend above. # Testing a combination of two coins: List[Coin] = [ record.coin for record in (await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False)) ] coins = [coins[0], coins[1]] await self.do_spend( sim, sim_client, tail, coins, [NO_LINEAGE_PROOF] * 2, [ Program.to( [ [51, acs.get_tree_hash(), coins[0].amount + coins[1].amount], [51, 0, -113, tail, checker_solution], ] ), Program.to([[51, 0, -113, tail, checker_solution]]), ], (MempoolInclusionStatus.SUCCESS, None), limitations_solutions=[checker_solution] * 2, cost_str="Two CATs", ) # Testing a combination of three coins = [ record.coin for record in (await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False)) ] total_amount: uint64 = uint64(sum([c.amount for c in coins])) await self.do_spend( sim, sim_client, tail, coins, [NO_LINEAGE_PROOF] * 3, [ Program.to( [ [51, acs.get_tree_hash(), total_amount], [51, 0, -113, tail, checker_solution], ] ), Program.to([[51, 0, -113, tail, checker_solution]]), Program.to([[51, 0, -113, tail, checker_solution]]), ], (MempoolInclusionStatus.SUCCESS, None), limitations_solutions=[checker_solution] * 3, cost_str="Three CATs", ) # Spend with a standard lineage proof parent_coin: Coin = coins[0] # The first one is the one we didn't light on fire _, curried_args = cat_puzzle.uncurry() _, _, innerpuzzle = curried_args.as_iter() lineage_proof = LineageProof(parent_coin.parent_coin_info, innerpuzzle.get_tree_hash(), parent_coin.amount) await self.do_spend( sim, sim_client, tail, [(await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False))[0].coin], [lineage_proof], [Program.to([[51, acs.get_tree_hash(), total_amount]])], (MempoolInclusionStatus.SUCCESS, None), reveal_limitations_program=False, cost_str="Standard Lineage Check", ) # Melt some value await self.do_spend( sim, sim_client, tail, [(await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False))[0].coin], [NO_LINEAGE_PROOF], [ Program.to( [ [51, acs.get_tree_hash(), total_amount - 1], [51, 0, -113, tail, checker_solution], ] ) ], (MempoolInclusionStatus.SUCCESS, None), extra_deltas=[-1], limitations_solutions=[checker_solution], cost_str="Melting Value", ) # Mint some value temp_p = Program.to(1) temp_ph: bytes32 = temp_p.get_tree_hash() await sim.farm_block(temp_ph) acs_coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(temp_ph, include_spent_coins=False))[ 0 ].coin acs_bundle = SpendBundle( [ CoinSpend( acs_coin, temp_p, Program.to([]), ) ], G2Element(), ) await self.do_spend( sim, sim_client, tail, [(await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False))[0].coin], [NO_LINEAGE_PROOF], [ Program.to( [ [51, acs.get_tree_hash(), total_amount], [51, 0, -113, tail, checker_solution], ] ) ], # We subtracted 1 last time so it's normal now (MempoolInclusionStatus.SUCCESS, None), extra_deltas=[1], additional_spends=[acs_bundle], limitations_solutions=[checker_solution], cost_str="Mint Value", ) finally: await sim.close()
async def generate_coins( self, sim, sim_client, requested_coins: Dict[Optional[str], List[uint64]], ) -> Dict[Optional[str], List[Coin]]: await sim.farm_block(acs_ph) parent_coin: Coin = [ cr.coin for cr in await ( sim_client.get_coin_records_by_puzzle_hash(acs_ph)) ][0] # We need to gather a list of initial coins to create as well as spends that do the eve spend for every CAT payments: List[Payment] = [] cat_bundles: List[SpendBundle] = [] for tail_str, amounts in requested_coins.items(): for amount in amounts: if tail_str: tail: Program = str_to_tail( tail_str) # Making a fake but unique TAIL cat_puzzle: Program = construct_cat_puzzle( CAT_MOD, tail.get_tree_hash(), acs) payments.append( Payment(cat_puzzle.get_tree_hash(), amount, [])) cat_bundles.append( unsigned_spend_bundle_for_spendable_cats( CAT_MOD, [ SpendableCAT( Coin(parent_coin.name(), cat_puzzle.get_tree_hash(), amount), tail.get_tree_hash(), acs, Program.to([[51, acs_ph, amount], [51, 0, -113, tail, []]]), ) ], )) else: payments.append(Payment(acs_ph, amount, [])) # This bundle create all of the initial coins parent_bundle = SpendBundle( [ CoinSpend( parent_coin, acs, Program.to([[51, p.puzzle_hash, p.amount] for p in payments]), ) ], G2Element(), ) # Then we aggregate it with all of the eve spends await sim_client.push_tx( SpendBundle.aggregate([parent_bundle, *cat_bundles])) await sim.farm_block() # Search for all of the coins and put them into a dictionary coin_dict: Dict[Optional[str], List[Coin]] = {} for tail_str, _ in requested_coins.items(): if tail_str: tail_hash: bytes32 = str_to_tail_hash(tail_str) cat_ph: bytes32 = construct_cat_puzzle(CAT_MOD, tail_hash, acs).get_tree_hash() coin_dict[tail_str] = [ cr.coin for cr in await ( sim_client.get_coin_records_by_puzzle_hash( cat_ph, include_spent_coins=False)) ] else: coin_dict[None] = list( filter( lambda c: c.amount < 250000000000, [ cr.coin for cr in await ( sim_client.get_coin_records_by_puzzle_hash( acs_ph, include_spent_coins=False)) ], )) return coin_dict
def str_to_cat_hash(tail_str: str) -> bytes32: return construct_cat_puzzle(CAT_MOD, str_to_tail_hash(tail_str), acs).get_tree_hash()