def spend_coin_to_singleton( puzzle_db: PuzzleDB, launcher_puzzle: Program, coin_store: CoinStore, now: CoinTimestamp) -> Tuple[List[Coin], List[CoinSpend]]: farmed_coin_amount = 100000 metadata = [("foo", "bar")] now = CoinTimestamp(10012300, 1) farmed_coin = coin_store.farm_coin(ANYONE_CAN_SPEND_PUZZLE.get_tree_hash(), now, amount=farmed_coin_amount) now.seconds += 500 now.height += 1 launcher_amount: uint64 = uint64(1) launcher_puzzle = LAUNCHER_PUZZLE launcher_puzzle_hash = launcher_puzzle.get_tree_hash() initial_singleton_puzzle = adaptor_for_singleton_inner_puzzle( ANYONE_CAN_SPEND_PUZZLE) launcher_id, condition_list, launcher_spend_bundle = launcher_conditions_and_spend_bundle( puzzle_db, farmed_coin.name(), launcher_amount, initial_singleton_puzzle, metadata, launcher_puzzle) conditions = Program.to(condition_list) coin_spend = CoinSpend(farmed_coin, ANYONE_CAN_SPEND_PUZZLE, conditions) spend_bundle = SpendBundle.aggregate( [launcher_spend_bundle, SpendBundle([coin_spend], G2Element())]) additions, removals = coin_store.update_coin_store_for_spend_bundle( spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE) launcher_coin = launcher_spend_bundle.coin_spends[0].coin assert_coin_spent(coin_store, launcher_coin) assert_coin_spent(coin_store, farmed_coin) # TODO: address hint error and remove ignore # error: Argument 1 to "singleton_puzzle" has incompatible type "bytes32"; expected "Program" [arg-type] singleton_expected_puzzle = singleton_puzzle( launcher_id, # type: ignore[arg-type] launcher_puzzle_hash, initial_singleton_puzzle, ) singleton_expected_puzzle_hash = singleton_expected_puzzle.get_tree_hash() expected_singleton_coin = Coin(launcher_coin.name(), singleton_expected_puzzle_hash, launcher_amount) assert_coin_spent(coin_store, expected_singleton_coin, is_spent=False) return additions, removals
def test_pool_lifecycle(self): # START TESTS # Generate starting info key_lookup = KeyTool() sk: PrivateKey = PrivateKey.from_bytes( secret_exponent_for_index(1).to_bytes(32, "big"), ) pk: G1Element = G1Element.from_bytes( public_key_for_index(1, key_lookup)) starting_puzzle: Program = puzzle_for_pk(pk) starting_ph: bytes32 = starting_puzzle.get_tree_hash() # Get our starting standard coin created START_AMOUNT: uint64 = 1023 coin_db = CoinStore() time = CoinTimestamp(10000000, 1) coin_db.farm_coin(starting_ph, time, START_AMOUNT) starting_coin: Coin = next(coin_db.all_unspent_coins()) # LAUNCHING # Create the escaping inner puzzle GENESIS_CHALLENGE = bytes32.fromhex( "ccd5bb71183532bff220ba46c268991a3ff07eb358e8255a65c30a2dce0e5fbb") launcher_coin = singleton_top_layer.generate_launcher_coin( starting_coin, START_AMOUNT, ) DELAY_TIME = uint64(60800) DELAY_PH = starting_ph launcher_id = launcher_coin.name() relative_lock_height: uint32 = uint32(5000) # use a dummy pool state pool_state = PoolState( owner_pubkey=pk, pool_url="", relative_lock_height=relative_lock_height, state=3, # farming to pool target_puzzle_hash=starting_ph, version=1, ) # create a new dummy pool state for travelling target_pool_state = PoolState( owner_pubkey=pk, pool_url="", relative_lock_height=relative_lock_height, state=2, # Leaving pool target_puzzle_hash=starting_ph, version=1, ) # Standard format comment comment = Program.to([("p", bytes(pool_state)), ("t", DELAY_TIME), ("h", DELAY_PH)]) pool_wr_innerpuz: bytes32 = create_waiting_room_inner_puzzle( starting_ph, relative_lock_height, pk, launcher_id, GENESIS_CHALLENGE, DELAY_TIME, DELAY_PH, ) pool_wr_inner_hash = pool_wr_innerpuz.get_tree_hash() pooling_innerpuz: Program = create_pooling_inner_puzzle( starting_ph, pool_wr_inner_hash, pk, launcher_id, GENESIS_CHALLENGE, DELAY_TIME, DELAY_PH, ) # Driver tests assert is_pool_singleton_inner_puzzle(pooling_innerpuz) assert is_pool_singleton_inner_puzzle(pool_wr_innerpuz) assert get_pubkey_from_member_inner_puzzle(pooling_innerpuz) == pk # Generating launcher information conditions, launcher_coinsol = singleton_top_layer.launch_conditions_and_coinsol( starting_coin, pooling_innerpuz, comment, START_AMOUNT) # Creating solution for standard transaction delegated_puzzle: Program = puzzle_for_conditions(conditions) full_solution: Program = solution_for_conditions(conditions) starting_coinsol = CoinSolution( starting_coin, starting_puzzle, full_solution, ) # Create the spend bundle sig: G2Element = sign_delegated_puz(delegated_puzzle, starting_coin) spend_bundle = SpendBundle( [starting_coinsol, launcher_coinsol], sig, ) # Spend it! coin_db.update_coin_store_for_spend_bundle( spend_bundle, time, DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM, ) # Test that we can retrieve the extra data assert get_delayed_puz_info_from_launcher_spend(launcher_coinsol) == ( DELAY_TIME, DELAY_PH) assert solution_to_extra_data(launcher_coinsol) == pool_state # TEST TRAVEL AFTER LAUNCH # fork the state fork_coin_db: CoinStore = copy.deepcopy(coin_db) post_launch_coinsol, _ = create_travel_spend( launcher_coinsol, launcher_coin, pool_state, target_pool_state, GENESIS_CHALLENGE, DELAY_TIME, DELAY_PH, ) # Spend it! fork_coin_db.update_coin_store_for_spend_bundle( SpendBundle([post_launch_coinsol], G2Element()), time, DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM, ) # HONEST ABSORB time = CoinTimestamp(10000030, 2) # create the farming reward p2_singleton_puz: Program = create_p2_singleton_puzzle( SINGLETON_MOD_HASH, launcher_id, DELAY_TIME, DELAY_PH, ) p2_singleton_ph: bytes32 = p2_singleton_puz.get_tree_hash() assert uncurry_pool_waitingroom_inner_puzzle(pool_wr_innerpuz) == ( starting_ph, relative_lock_height, pk, p2_singleton_ph, ) assert launcher_id_to_p2_puzzle_hash(launcher_id, DELAY_TIME, DELAY_PH) == p2_singleton_ph assert get_seconds_and_delayed_puzhash_from_p2_singleton_puzzle( p2_singleton_puz) == (DELAY_TIME, DELAY_PH) coin_db.farm_coin(p2_singleton_ph, time, 1750000000000) coin_sols: List[CoinSolution] = create_absorb_spend( launcher_coinsol, pool_state, launcher_coin, 2, GENESIS_CHALLENGE, DELAY_TIME, DELAY_PH, # height ) # Spend it! coin_db.update_coin_store_for_spend_bundle( SpendBundle(coin_sols, G2Element()), time, DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM, ) # ABSORB A NON EXISTENT REWARD (Negative test) last_coinsol: CoinSolution = list( filter( lambda e: e.coin.amount == START_AMOUNT, coin_sols, ))[0] coin_sols: List[CoinSolution] = create_absorb_spend( last_coinsol, pool_state, launcher_coin, 2, GENESIS_CHALLENGE, DELAY_TIME, DELAY_PH, # height ) # filter for only the singleton solution singleton_coinsol: CoinSolution = list( filter( lambda e: e.coin.amount == START_AMOUNT, coin_sols, ))[0] # Spend it and hope it fails! try: coin_db.update_coin_store_for_spend_bundle( SpendBundle([singleton_coinsol], G2Element()), time, DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM, ) except BadSpendBundleError as e: assert str( e ) == "condition validation failure Err.ASSERT_ANNOUNCE_CONSUMED_FAILED" # SPEND A NON-REWARD P2_SINGLETON (Negative test) # create the dummy coin non_reward_p2_singleton = Coin( bytes32(32 * b"3"), p2_singleton_ph, uint64(1337), ) coin_db._add_coin_entry(non_reward_p2_singleton, time) # construct coin solution for the p2_singleton coin bad_coinsol = CoinSolution( non_reward_p2_singleton, p2_singleton_puz, Program.to([ pooling_innerpuz.get_tree_hash(), non_reward_p2_singleton.name(), ]), ) # Spend it and hope it fails! try: coin_db.update_coin_store_for_spend_bundle( SpendBundle([singleton_coinsol, bad_coinsol], G2Element()), time, DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM, ) except BadSpendBundleError as e: assert str( e ) == "condition validation failure Err.ASSERT_ANNOUNCE_CONSUMED_FAILED" # ENTER WAITING ROOM # find the singleton singleton = get_most_recent_singleton_coin_from_coin_solution( last_coinsol) # get the relevant coin solution travel_coinsol, _ = create_travel_spend( last_coinsol, launcher_coin, pool_state, target_pool_state, GENESIS_CHALLENGE, DELAY_TIME, DELAY_PH, ) # Test that we can retrieve the extra data assert solution_to_extra_data(travel_coinsol) == target_pool_state # sign the serialized state data = Program.to(bytes(target_pool_state)).get_tree_hash() sig: G2Element = AugSchemeMPL.sign( sk, (data + singleton.name() + DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA), ) # Spend it! coin_db.update_coin_store_for_spend_bundle( SpendBundle([travel_coinsol], sig), time, DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM, ) # ESCAPE TOO FAST (Negative test) # find the singleton singleton = get_most_recent_singleton_coin_from_coin_solution( travel_coinsol) # get the relevant coin solution return_coinsol, _ = create_travel_spend( travel_coinsol, launcher_coin, target_pool_state, pool_state, GENESIS_CHALLENGE, DELAY_TIME, DELAY_PH, ) # sign the serialized target state sig = AugSchemeMPL.sign( sk, (data + singleton.name() + DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA), ) # Spend it and hope it fails! try: coin_db.update_coin_store_for_spend_bundle( SpendBundle([return_coinsol], sig), time, DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM, ) except BadSpendBundleError as e: assert str( e ) == "condition validation failure Err.ASSERT_HEIGHT_RELATIVE_FAILED" # ABSORB WHILE IN WAITING ROOM time = CoinTimestamp(10000060, 3) # create the farming reward coin_db.farm_coin(p2_singleton_ph, time, 1750000000000) # generate relevant coin solutions coin_sols: List[CoinSolution] = create_absorb_spend( travel_coinsol, target_pool_state, launcher_coin, 3, GENESIS_CHALLENGE, DELAY_TIME, DELAY_PH, # height ) # Spend it! coin_db.update_coin_store_for_spend_bundle( SpendBundle(coin_sols, G2Element()), time, DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM, ) # LEAVE THE WAITING ROOM time = CoinTimestamp(20000000, 10000) # find the singleton singleton_coinsol: CoinSolution = list( filter( lambda e: e.coin.amount == START_AMOUNT, coin_sols, ))[0] singleton: Coin = get_most_recent_singleton_coin_from_coin_solution( singleton_coinsol) # get the relevant coin solution return_coinsol, _ = create_travel_spend( singleton_coinsol, launcher_coin, target_pool_state, pool_state, GENESIS_CHALLENGE, DELAY_TIME, DELAY_PH, ) # Test that we can retrieve the extra data assert solution_to_extra_data(return_coinsol) == pool_state # sign the serialized target state data = Program.to([ pooling_innerpuz.get_tree_hash(), START_AMOUNT, bytes(pool_state) ]).get_tree_hash() sig: G2Element = AugSchemeMPL.sign( sk, (data + singleton.name() + DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA), ) # Spend it! coin_db.update_coin_store_for_spend_bundle( SpendBundle([return_coinsol], sig), time, DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM, ) # ABSORB ONCE MORE FOR GOOD MEASURE time = CoinTimestamp(20000000, 10005) # create the farming reward coin_db.farm_coin(p2_singleton_ph, time, 1750000000000) coin_sols: List[CoinSolution] = create_absorb_spend( return_coinsol, pool_state, launcher_coin, 10005, GENESIS_CHALLENGE, DELAY_TIME, DELAY_PH, # height ) # Spend it! coin_db.update_coin_store_for_spend_bundle( SpendBundle(coin_sols, G2Element()), time, DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM, )
def test_lifecycle_with_coinstore_as_wallet(): PUZZLE_DB = PuzzleDB() interested_singletons = [] ####### # farm a coin coin_store = CoinStore(int.from_bytes(POOL_REWARD_PREFIX_MAINNET, "big")) now = CoinTimestamp(10012300, 1) DELAY_SECONDS = 86400 DELAY_PUZZLE_HASH = bytes([0] * 32) ####### # spend coin to a singleton additions, removals = spend_coin_to_singleton(PUZZLE_DB, LAUNCHER_PUZZLE, coin_store, now) assert len(list(coin_store.all_unspent_coins())) == 1 new_singletons = find_interesting_singletons(PUZZLE_DB, removals) interested_singletons.extend(new_singletons) assert len(interested_singletons) == 1 SINGLETON_WALLET = interested_singletons[0] ####### # farm a `p2_singleton` pool_reward_puzzle_hash = p2_singleton_puzzle_hash_for_launcher( PUZZLE_DB, SINGLETON_WALLET.launcher_id, SINGLETON_WALLET.launcher_puzzle_hash, DELAY_SECONDS, DELAY_PUZZLE_HASH) farmed_coin = coin_store.farm_coin(pool_reward_puzzle_hash, now) now.seconds += 500 now.height += 1 p2_singleton_coins = filter_p2_singleton(PUZZLE_DB, SINGLETON_WALLET, [farmed_coin]) assert p2_singleton_coins == [farmed_coin] assert len(list(coin_store.all_unspent_coins())) == 2 ####### # now collect the `p2_singleton` using the singleton for coin in p2_singleton_coins: p2_singleton_coin_spend, singleton_conditions = claim_p2_singleton( PUZZLE_DB, SINGLETON_WALLET, coin) coin_spend = SINGLETON_WALLET.coin_spend_for_conditions( PUZZLE_DB, conditions=singleton_conditions) spend_bundle = SpendBundle([coin_spend, p2_singleton_coin_spend], G2Element()) additions, removals = coin_store.update_coin_store_for_spend_bundle( spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE) now.seconds += 500 now.height += 1 SINGLETON_WALLET.update_state(PUZZLE_DB, removals) assert len(list(coin_store.all_unspent_coins())) == 1 ####### # farm and collect another `p2_singleton` pool_reward_puzzle_hash = p2_singleton_puzzle_hash_for_launcher( PUZZLE_DB, SINGLETON_WALLET.launcher_id, SINGLETON_WALLET.launcher_puzzle_hash, DELAY_SECONDS, DELAY_PUZZLE_HASH) farmed_coin = coin_store.farm_coin(pool_reward_puzzle_hash, now) now.seconds += 500 now.height += 1 p2_singleton_coins = filter_p2_singleton(PUZZLE_DB, SINGLETON_WALLET, [farmed_coin]) assert p2_singleton_coins == [farmed_coin] assert len(list(coin_store.all_unspent_coins())) == 2 for coin in p2_singleton_coins: p2_singleton_coin_spend, singleton_conditions = claim_p2_singleton( PUZZLE_DB, SINGLETON_WALLET, coin) coin_spend = SINGLETON_WALLET.coin_spend_for_conditions( PUZZLE_DB, conditions=singleton_conditions) spend_bundle = SpendBundle([coin_spend, p2_singleton_coin_spend], G2Element()) additions, removals = coin_store.update_coin_store_for_spend_bundle( spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE) now.seconds += 500 now.height += 1 SINGLETON_WALLET.update_state(PUZZLE_DB, removals) assert len(list(coin_store.all_unspent_coins())) == 1 ####### # loan the singleton to a pool # puzzle_for_loan_singleton_to_pool( # pool_puzzle_hash, p2_singleton_puzzle_hash, owner_public_key, pool_reward_prefix, relative_lock_height) # calculate the series owner_public_key = bytes(create_throwaway_pubkey(b"foo")) pool_puzzle_hash = Program.to(bytes( create_throwaway_pubkey(b""))).get_tree_hash() pool_reward_prefix = POOL_REWARD_PREFIX_MAINNET relative_lock_height = 1440 pool_escaping_puzzle = POOL_WAITINGROOM_MOD.curry(pool_puzzle_hash, pool_reward_puzzle_hash, owner_public_key, pool_reward_prefix, relative_lock_height) pool_escaping_puzzle_hash = pool_escaping_puzzle.get_tree_hash() pool_member_puzzle = POOL_MEMBER_MOD.curry( pool_puzzle_hash, pool_reward_puzzle_hash, owner_public_key, pool_reward_prefix, pool_escaping_puzzle_hash, ) pool_member_puzzle_hash = pool_member_puzzle.get_tree_hash() PUZZLE_DB.add_puzzle(pool_escaping_puzzle) PUZZLE_DB.add_puzzle( singleton_puzzle(SINGLETON_WALLET.launcher_id, SINGLETON_WALLET.launcher_puzzle_hash, pool_escaping_puzzle)) PUZZLE_DB.add_puzzle(pool_member_puzzle) full_puzzle = singleton_puzzle(SINGLETON_WALLET.launcher_id, SINGLETON_WALLET.launcher_puzzle_hash, pool_member_puzzle) PUZZLE_DB.add_puzzle(full_puzzle) conditions = [ Program.to([ConditionOpcode.CREATE_COIN, pool_member_puzzle_hash, 1]) ] singleton_coin_spend = SINGLETON_WALLET.coin_spend_for_conditions( PUZZLE_DB, conditions=conditions) spend_bundle = SpendBundle([singleton_coin_spend], G2Element()) additions, removals = coin_store.update_coin_store_for_spend_bundle( spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE) assert len(list(coin_store.all_unspent_coins())) == 1 SINGLETON_WALLET.update_state(PUZZLE_DB, removals) ####### # farm a `p2_singleton` pool_reward_puzzle_hash = p2_singleton_puzzle_hash_for_launcher( PUZZLE_DB, SINGLETON_WALLET.launcher_id, SINGLETON_WALLET.launcher_puzzle_hash, DELAY_SECONDS, DELAY_PUZZLE_HASH) farmed_coin = coin_store.farm_coin(pool_reward_puzzle_hash, now) now.seconds += 500 now.height += 1 p2_singleton_coins = filter_p2_singleton(PUZZLE_DB, SINGLETON_WALLET, [farmed_coin]) assert p2_singleton_coins == [farmed_coin] assert len(list(coin_store.all_unspent_coins())) == 2 ####### # now collect the `p2_singleton` for the pool for coin in p2_singleton_coins: p2_singleton_coin_spend, singleton_conditions = claim_p2_singleton( PUZZLE_DB, SINGLETON_WALLET, coin) coin_spend = SINGLETON_WALLET.coin_spend_for_conditions( PUZZLE_DB, pool_member_spend_type="claim-p2-nft", pool_reward_amount=p2_singleton_coin_spend.coin.amount, pool_reward_height=now.height - 1, ) spend_bundle = SpendBundle([coin_spend, p2_singleton_coin_spend], G2Element()) spend_bundle.debug() additions, removals = coin_store.update_coin_store_for_spend_bundle( spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE) now.seconds += 500 now.height += 1 SINGLETON_WALLET.update_state(PUZZLE_DB, removals) assert len(list(coin_store.all_unspent_coins())) == 2 ####### # spend the singleton into the "leaving the pool" state coin_spend = SINGLETON_WALLET.coin_spend_for_conditions( PUZZLE_DB, pool_member_spend_type="to-waiting-room", key_value_list=Program.to([("foo", "bar")])) spend_bundle = SpendBundle([coin_spend], G2Element()) additions, removals = coin_store.update_coin_store_for_spend_bundle( spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE) now.seconds += 500 now.height += 1 change_count = SINGLETON_WALLET.update_state(PUZZLE_DB, removals) assert change_count == 1 assert len(list(coin_store.all_unspent_coins())) == 2 ####### # farm a `p2_singleton` pool_reward_puzzle_hash = p2_singleton_puzzle_hash_for_launcher( PUZZLE_DB, SINGLETON_WALLET.launcher_id, SINGLETON_WALLET.launcher_puzzle_hash, DELAY_SECONDS, DELAY_PUZZLE_HASH) farmed_coin = coin_store.farm_coin(pool_reward_puzzle_hash, now) now.seconds += 500 now.height += 1 p2_singleton_coins = filter_p2_singleton(PUZZLE_DB, SINGLETON_WALLET, [farmed_coin]) assert p2_singleton_coins == [farmed_coin] assert len(list(coin_store.all_unspent_coins())) == 3 ####### # now collect the `p2_singleton` for the pool for coin in p2_singleton_coins: p2_singleton_coin_spend, singleton_conditions = claim_p2_singleton( PUZZLE_DB, SINGLETON_WALLET, coin) coin_spend = SINGLETON_WALLET.coin_spend_for_conditions( PUZZLE_DB, pool_leaving_spend_type="claim-p2-nft", pool_reward_amount=p2_singleton_coin_spend.coin.amount, pool_reward_height=now.height - 1, ) spend_bundle = SpendBundle([coin_spend, p2_singleton_coin_spend], G2Element()) additions, removals = coin_store.update_coin_store_for_spend_bundle( spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE) now.seconds += 500 now.height += 1 SINGLETON_WALLET.update_state(PUZZLE_DB, removals) assert len(list(coin_store.all_unspent_coins())) == 3 ####### # now finish leaving the pool initial_singleton_puzzle = adaptor_for_singleton_inner_puzzle( ANYONE_CAN_SPEND_PUZZLE) coin_spend = SINGLETON_WALLET.coin_spend_for_conditions( PUZZLE_DB, pool_leaving_spend_type="exit-waiting-room", key_value_list=[("foo1", "bar2"), ("foo2", "baz5")], destination_puzzle_hash=initial_singleton_puzzle.get_tree_hash(), ) spend_bundle = SpendBundle([coin_spend], G2Element()) full_puzzle = singleton_puzzle(SINGLETON_WALLET.launcher_id, SINGLETON_WALLET.launcher_puzzle_hash, initial_singleton_puzzle) PUZZLE_DB.add_puzzle(full_puzzle) try: additions, removals = coin_store.update_coin_store_for_spend_bundle( spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE) assert 0 except BadSpendBundleError as ex: assert ex.args[ 0] == "condition validation failure Err.ASSERT_HEIGHT_RELATIVE_FAILED" now.seconds += 350000 now.height += 1445 additions, removals = coin_store.update_coin_store_for_spend_bundle( spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE) SINGLETON_WALLET.update_state(PUZZLE_DB, removals) assert len(list(coin_store.all_unspent_coins())) == 3 ####### # now spend to oblivion with the `-113` hack coin_spend = SINGLETON_WALLET.coin_spend_for_conditions( PUZZLE_DB, conditions=[[ConditionOpcode.CREATE_COIN, 0, -113]]) spend_bundle = SpendBundle([coin_spend], G2Element()) spend_bundle.debug() additions, removals = coin_store.update_coin_store_for_spend_bundle( spend_bundle, now, MAX_BLOCK_COST_CLVM, COST_PER_BYTE) update_count = SINGLETON_WALLET.update_state(PUZZLE_DB, removals) assert update_count == 0 assert len(list(coin_store.all_unspent_coins())) == 2 return 0