def launcher_conditions_and_spend_bundle( parent_coin_id: bytes32, launcher_amount: uint64, initial_singleton_inner_puzzle: Program, metadata: List[Tuple[str, str]], launcher_puzzle: Program = LAUNCHER_PUZZLE, ) -> Tuple[Program, bytes32, List[Program], SpendBundle]: launcher_puzzle_hash = launcher_puzzle.get_tree_hash() launcher_coin = Coin(parent_coin_id, launcher_puzzle_hash, launcher_amount) singleton_full_puzzle = SINGLETON_MOD.curry( SINGLETON_MOD_HASH, launcher_coin.name(), launcher_puzzle_hash, initial_singleton_inner_puzzle) singleton_full_puzzle_hash = singleton_full_puzzle.get_tree_hash() message_program = Program.to( [singleton_full_puzzle_hash, launcher_amount, metadata]) expected_announcement = Announcement(launcher_coin.name(), message_program.get_tree_hash()) expected_conditions = [] expected_conditions.append( Program.to( binutils.assemble( f"(0x{ConditionOpcode.ASSERT_COIN_ANNOUNCEMENT.hex()} 0x{expected_announcement.name()})" ))) expected_conditions.append( Program.to( binutils.assemble( f"(0x{ConditionOpcode.CREATE_COIN.hex()} 0x{launcher_puzzle_hash} {launcher_amount})" ))) launcher_solution = Program.to( [singleton_full_puzzle_hash, launcher_amount, metadata]) coin_spend = CoinSpend(launcher_coin, launcher_puzzle, launcher_solution) spend_bundle = SpendBundle([coin_spend], G2Element()) lineage_proof = Program.to([parent_coin_id, launcher_amount]) return lineage_proof, launcher_coin.name( ), expected_conditions, spend_bundle
def claim_p2_singleton( p2_singleton_coin: Coin, singleton_inner_puzhash: bytes32, launcher_id: bytes32, delay_time: Optional[uint64] = None, delay_ph: Optional[bytes32] = None, ) -> Tuple[Program, Program, CoinSpend]: assertion = Program.to([ ConditionOpcode.ASSERT_COIN_ANNOUNCEMENT, std_hash(p2_singleton_coin.name() + b"$") ]) announcement = Program.to( [ConditionOpcode.CREATE_PUZZLE_ANNOUNCEMENT, p2_singleton_coin.name()]) if delay_time is None or delay_ph is None: puzzle: Program = pay_to_singleton_puzzle(launcher_id) else: puzzle = pay_to_singleton_or_delay_puzzle( launcher_id, delay_time, delay_ph, ) claim_coinsol = CoinSpend( p2_singleton_coin, puzzle, solution_for_p2_singleton(p2_singleton_coin, singleton_inner_puzhash), ) return assertion, announcement, claim_coinsol
async def generate_eve_spend(self, coin: Coin, full_puzzle: Program, innerpuz: Program): assert self.did_info.origin_coin is not None # innerpuz solution is (mode amount message my_id my_puzhash parent_innerpuzhash_amounts_for_recovery_ids) innersol = Program.to([ 0, coin.amount, coin.puzzle_hash, coin.name(), coin.puzzle_hash, [] ]) # full solution is (parent_info my_amount innersolution) fullsol = Program.to([ [ self.did_info.origin_coin.parent_coin_info, self.did_info.origin_coin.amount ], coin.parent_coin_info, coin.amount, innersol, ]) list_of_solutions = [CoinSolution(coin, full_puzzle, fullsol)] # sign for AGG_SIG_ME message = ( Program.to([coin.amount, coin.puzzle_hash]).get_tree_hash() + coin.name() + self.wallet_state_manager.constants.AGG_SIG_ME_ADDITIONAL_DATA) pubkey = did_wallet_puzzles.get_pubkey_from_innerpuz(innerpuz) index = await self.wallet_state_manager.puzzle_store.index_for_pubkey( pubkey) private = master_sk_to_wallet_sk(self.wallet_state_manager.private_key, index) signature = AugSchemeMPL.sign(private, message) sigs = [signature] aggsig = AugSchemeMPL.aggregate(sigs) spend_bundle = SpendBundle(list_of_solutions, aggsig) return spend_bundle
async def coin_removed(self, coin: Coin, height: uint32, wallet_id: int): """ Called when coin gets spent """ await self.coin_store.set_spent(coin.name(), height) unconfirmed_record: List[ TransactionRecord] = await self.tx_store.unconfirmed_with_removal_coin( coin.name()) for unconfirmed in unconfirmed_record: await self.tx_store.set_confirmed(unconfirmed.name, height) self.state_changed("coin_removed", wallet_id)
async def get_unspent_coins_for_wallet( self, wallet_id: int) -> Set[WalletCoinRecord]: """ Returns set of CoinRecords that have not been spent yet for a wallet. """ async with self.wallet_cache_lock: if wallet_id in self.coin_wallet_record_cache: wallet_coins: Dict[ bytes32, WalletCoinRecord] = self.coin_wallet_record_cache[ wallet_id] return set(wallet_coins.values()) coin_set = set() cursor = await self.db_connection.execute( "SELECT * from coin_record WHERE spent=0 and wallet_id=?", (wallet_id, ), ) rows = await cursor.fetchall() await cursor.close() cache_dict = {} for row in rows: coin = Coin(bytes32(bytes.fromhex(row[6])), bytes32(bytes.fromhex(row[5])), uint64.from_bytes(row[7])) coin_record = WalletCoinRecord(coin, row[1], row[2], row[3], row[4], WalletType(row[8]), row[9]) coin_set.add(coin_record) cache_dict[coin.name()] = coin_record self.coin_wallet_record_cache[wallet_id] = cache_dict return coin_set
def claim_p2_singleton( puzzle_db: PuzzleDB, singleton_wallet: SingletonWallet, p2_singleton_coin: Coin) -> Tuple[CoinSpend, List[Program]]: inner_puzzle = singleton_wallet.inner_puzzle(puzzle_db) assert inner_puzzle inner_puzzle_hash = inner_puzzle.get_tree_hash() p2_singleton_puzzle = puzzle_db.puzzle_for_hash( p2_singleton_coin.puzzle_hash) assert p2_singleton_puzzle is not None p2_singleton_coin_name = p2_singleton_coin.name() p2_singleton_solution = solve_puzzle( puzzle_db, p2_singleton_puzzle, p2_singleton_spend_type="claim-p2-nft", singleton_inner_puzzle_hash=inner_puzzle_hash, p2_singleton_coin_name=p2_singleton_coin_name, ) p2_singleton_coin_spend = CoinSpend( p2_singleton_coin, p2_singleton_puzzle.to_serialized_program(), p2_singleton_solution, ) expected_p2_singleton_announcement = Announcement(p2_singleton_coin_name, bytes(b"$")).name() singleton_conditions = [ Program.to([ ConditionOpcode.CREATE_PUZZLE_ANNOUNCEMENT, p2_singleton_coin_name ]), Program.to([ConditionOpcode.CREATE_COIN, inner_puzzle_hash, 1]), Program.to([ ConditionOpcode.ASSERT_COIN_ANNOUNCEMENT, expected_p2_singleton_announcement ]), ] return p2_singleton_coin_spend, singleton_conditions
async def coin_added(self, coin: Coin, _: uint32): """Notification from wallet state manager that wallet has been received.""" self.log.info("DID wallet has been notified that coin was added") inner_puzzle = await self.inner_puzzle_for_did_puzzle(coin.puzzle_hash) if self.did_info.temp_coin is not None: self.wallet_state_manager.state_changed("did_coin_added", self.wallet_info.id) new_info = DIDInfo( self.did_info.origin_coin, self.did_info.backup_ids, self.did_info.num_of_backup_ids_needed, self.did_info.parent_info, inner_puzzle, None, None, None, False, ) await self.save_info(new_info, True) future_parent = LineageProof( coin.parent_coin_info, inner_puzzle.get_tree_hash(), coin.amount, ) await self.add_parent(coin.name(), future_parent, True)
async def fetch_puzzle_solution(self, peer, height: uint32, coin: Coin) -> CoinSpend: solution_response = await peer.request_puzzle_solution( wallet_protocol.RequestPuzzleSolution(coin.name(), height) ) if solution_response is None or not isinstance(solution_response, wallet_protocol.RespondPuzzleSolution): raise ValueError(f"Was not able to obtain solution {solution_response}") return CoinSpend(coin, solution_response.response.puzzle, solution_response.response.solution)
async def generate_eve_spend(self, coin: Coin, full_puzzle: Program, innerpuz: Program): assert self.did_info.origin_coin is not None # innerpuz solution is (mode amount message new_puzhash) innersol = Program.to([1, coin.amount, [], innerpuz.get_tree_hash()]) # full solution is (lineage_proof my_amount inner_solution) fullsol = Program.to( [ [self.did_info.origin_coin.parent_coin_info, self.did_info.origin_coin.amount], coin.amount, innersol, ] ) list_of_solutions = [CoinSpend(coin, full_puzzle, fullsol)] # sign for AGG_SIG_ME message = ( Program.to([innerpuz.get_tree_hash(), coin.amount, []]).get_tree_hash() + coin.name() + self.wallet_state_manager.constants.AGG_SIG_ME_ADDITIONAL_DATA ) pubkey = did_wallet_puzzles.get_pubkey_from_innerpuz(innerpuz) record: Optional[DerivationRecord] = await self.wallet_state_manager.puzzle_store.record_for_pubkey(pubkey) assert record is not None private = master_sk_to_wallet_sk_unhardened(self.wallet_state_manager.private_key, record.index) signature = AugSchemeMPL.sign(private, message) sigs = [signature] aggsig = AugSchemeMPL.aggregate(sigs) spend_bundle = SpendBundle(list_of_solutions, aggsig) return spend_bundle
def launcher_conditions_and_spend_bundle( puzzle_db: PuzzleDB, parent_coin_id: bytes32, launcher_amount: uint64, initial_singleton_inner_puzzle: Program, metadata: List[Tuple[str, str]], launcher_puzzle: Program, ) -> Tuple[bytes32, List[Program], SpendBundle]: puzzle_db.add_puzzle(launcher_puzzle) launcher_puzzle_hash = launcher_puzzle.get_tree_hash() launcher_coin = Coin(parent_coin_id, launcher_puzzle_hash, launcher_amount) # TODO: address hint error and remove ignore # error: Argument 1 to "singleton_puzzle" has incompatible type "bytes32"; expected "Program" [arg-type] singleton_full_puzzle = singleton_puzzle( launcher_coin.name(), # type: ignore[arg-type] launcher_puzzle_hash, initial_singleton_inner_puzzle, ) puzzle_db.add_puzzle(singleton_full_puzzle) singleton_full_puzzle_hash = singleton_full_puzzle.get_tree_hash() message_program = Program.to( [singleton_full_puzzle_hash, launcher_amount, metadata]) expected_announcement = Announcement(launcher_coin.name(), message_program.get_tree_hash()) expected_conditions = [] expected_conditions.append( Program.to( binutils.assemble( f"(0x{ConditionOpcode.ASSERT_COIN_ANNOUNCEMENT.hex()} 0x{expected_announcement.name()})" ))) expected_conditions.append( Program.to( binutils.assemble( f"(0x{ConditionOpcode.CREATE_COIN.hex()} 0x{launcher_puzzle_hash} {launcher_amount})" ))) solution = solve_puzzle( puzzle_db, launcher_puzzle, destination_puzzle_hash=singleton_full_puzzle_hash, launcher_amount=launcher_amount, metadata=metadata, ) coin_spend = CoinSpend(launcher_coin, SerializedProgram.from_program(launcher_puzzle), solution) spend_bundle = SpendBundle([coin_spend], G2Element()) return launcher_coin.name(), expected_conditions, spend_bundle
def coin_spend_for_lock_coin( prev_coin: Coin, subtotal: int, coin: Coin, ) -> CoinSpend: puzzle_reveal = LOCK_INNER_PUZZLE.curry(prev_coin.as_list(), subtotal) coin = Coin(coin.name(), puzzle_reveal.get_tree_hash(), uint64(0)) coin_spend = CoinSpend(coin, puzzle_reveal, Program.to(0)) return coin_spend
def claim_p2_singleton( p2_singleton_coin: Coin, singleton_inner_puzhash: bytes32, launcher_id: bytes32, ) -> Tuple[Program, Program, CoinSolution]: assertion = Program.to([ ConditionOpcode.ASSERT_COIN_ANNOUNCEMENT, std_hash(p2_singleton_coin.name() + b"$") ]) announcement = Program.to( [ConditionOpcode.CREATE_PUZZLE_ANNOUNCEMENT, p2_singleton_coin.name()]) claim_coinsol = CoinSolution( p2_singleton_coin, pay_to_singleton_puzzle(launcher_id), solution_for_p2_singleton(p2_singleton_coin, singleton_inner_puzhash), ) return assertion, announcement, claim_coinsol
def _add_coin_entry(self, coin: Coin, birthday: CoinTimestamp) -> None: name = coin.name() # assert name not in self._db self._db[name] = CoinRecord( coin, uint32(birthday.height), uint32(0), False, uint64(birthday.seconds), ) self._ph_index[coin.puzzle_hash].append(name)
async def check_all_there(): spendable = await cc_wallet.get_cc_spendable_coins() spendable_name_set = set() for record in spendable: spendable_name_set.add(record.coin.name()) puzzle_hash = cc_puzzle_hash_for_inner_puzzle_hash(CC_MOD, cc_wallet.cc_info.my_genesis_checker, cc_2_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
def test_fun(coin_1: Coin, coin_2: Coin) -> SpendBundle: announce = Announcement(coin_2.name(), b"test") cvp = ConditionWithArgs(ConditionOpcode.ASSERT_COIN_ANNOUNCEMENT, [announce.name()]) dic = {cvp.opcode: [cvp]} cvp2 = ConditionWithArgs(ConditionOpcode.CREATE_COIN_ANNOUNCEMENT, [b"test"]) dic2 = {cvp.opcode: [cvp2]} spend_bundle1 = generate_test_spend_bundle(coin_1, dic) spend_bundle2 = generate_test_spend_bundle(coin_2, dic2) bundle = SpendBundle.aggregate([spend_bundle1, spend_bundle2]) return bundle
def coin_announcements_for_conditions_dict( conditions_dict: Dict[ConditionOpcode, List[ConditionWithArgs]], input_coin: Coin, ) -> Set[Announcement]: output_announcements: Set[Announcement] = set() for cvp in conditions_dict.get(ConditionOpcode.CREATE_COIN_ANNOUNCEMENT, []): message = cvp.vars[0] announcement = Announcement(input_coin.name(), message) output_announcements.add(announcement) return output_announcements
def sign_delegated_puz(self, del_puz: Program, coin: Coin) -> G2Element: synthetic_secret_key: PrivateKey = p2_delegated_puzzle_or_hidden_puzzle.calculate_synthetic_secret_key( # noqa PrivateKey.from_bytes( secret_exponent_for_index(1).to_bytes(32, "big"), ), p2_delegated_puzzle_or_hidden_puzzle.DEFAULT_HIDDEN_PUZZLE_HASH, ) return AugSchemeMPL.sign( synthetic_secret_key, (del_puz.get_tree_hash() + coin.name() + DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA), # noqa )
async def coin_added(self, coin: Coin, header_hash: bytes32, removals: List[Coin], height: uint32): """Notification from wallet state manager that wallet has been received.""" self.log.info(f"CC wallet has been notified that {coin} was added") search_for_parent: bool = True inner_puzzle = await self.inner_puzzle_for_cc_puzhash(coin.puzzle_hash) lineage_proof = Program.to((1, [ coin.parent_coin_info, inner_puzzle.get_tree_hash(), coin.amount ])) await self.add_lineage(coin.name(), lineage_proof, True) for name, lineage_proofs in self.cc_info.lineage_proofs: if coin.parent_coin_info == name: search_for_parent = False break if search_for_parent: data: Dict[str, Any] = { "data": { "action_data": { "api_name": "request_puzzle_solution", "height": height, "coin_name": coin.parent_coin_info, "received_coin": coin.name(), } } } data_str = dict_to_json_str(data) await self.wallet_state_manager.create_action( name="request_puzzle_solution", wallet_id=self.id(), wallet_type=self.type(), callback="puzzle_solution_received", done=False, data=data_str, in_transaction=True, )
async def generate_new_decentralised_id( self, amount: uint64) -> Optional[SpendBundle]: """ This must be called under the wallet state manager lock """ coins = await self.standard_wallet.select_coins(amount) if coins is None: return None origin = coins.copy().pop() did_inner: Program = await self.get_new_innerpuz() did_inner_hash = did_inner.get_tree_hash() did_puz = did_wallet_puzzles.create_fullpuz(did_inner, origin.puzzle_hash) did_puzzle_hash = did_puz.get_tree_hash() tx_record: Optional[ TransactionRecord] = await self.standard_wallet.generate_signed_transaction( amount, did_puzzle_hash, uint64(0), origin.name(), coins) eve_coin = Coin(origin.name(), did_puzzle_hash, amount) future_parent = CCParent( eve_coin.parent_coin_info, did_inner_hash, eve_coin.amount, ) eve_parent = CCParent( origin.parent_coin_info, origin.puzzle_hash, origin.amount, ) await self.add_parent(eve_coin.parent_coin_info, eve_parent, False) await self.add_parent(eve_coin.name(), future_parent, False) if tx_record is None or tx_record.spend_bundle is None: return None # Only want to save this information if the transaction is valid did_info: DIDInfo = DIDInfo( origin, self.did_info.backup_ids, self.did_info.num_of_backup_ids_needed, self.did_info.parent_info, did_inner, None, None, None, ) await self.save_info(did_info, False) eve_spend = await self.generate_eve_spend(eve_coin, did_puz, did_inner) full_spend = SpendBundle.aggregate([tx_record.spend_bundle, eve_spend]) return full_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 coin_added(self, coin: Coin, _: uint32): """Notification from wallet state manager that wallet has been received.""" self.log.info(f"DID wallet has been notified that coin was added: {coin.name()}:{coin}") inner_puzzle = await self.inner_puzzle_for_did_puzzle(coin.puzzle_hash) if self.did_info.temp_coin is not None: self.wallet_state_manager.state_changed("did_coin_added", self.wallet_info.id) new_info = DIDInfo( self.did_info.origin_coin, self.did_info.backup_ids, self.did_info.num_of_backup_ids_needed, self.did_info.parent_info, inner_puzzle, None, None, None, False, ) await self.save_info(new_info, True) future_parent = LineageProof( coin.parent_coin_info, inner_puzzle.get_tree_hash(), coin.amount, ) await self.add_parent(coin.name(), future_parent, True) parent = self.get_parent_for_coin(coin) if parent is None: parent_state: CoinState = ( await self.wallet_state_manager.wallet_node.get_coin_state([coin.parent_coin_info]) )[0] node = self.wallet_state_manager.wallet_node.get_full_node_peer() assert parent_state.spent_height is not None puzzle_solution_request = wallet_protocol.RequestPuzzleSolution( coin.parent_coin_info, parent_state.spent_height ) response = await node.request_puzzle_solution(puzzle_solution_request) req_puz_sol = response.response assert req_puz_sol.puzzle is not None parent_innerpuz = did_wallet_puzzles.get_innerpuzzle_from_puzzle(req_puz_sol.puzzle) assert parent_innerpuz is not None parent_info = LineageProof( parent_state.coin.parent_coin_info, parent_innerpuz.get_tree_hash(), parent_state.coin.amount, ) await self.add_parent(coin.parent_coin_info, parent_info, False)
def coin_serialize(amount: uint64, clvm_serialize: bytes, full_serialize: bytes): c = Coin(bytes32(b"a" * 32), bytes32(b"b" * 32), amount) expected_hash = (b"a" * 32) + (b"b" * 32) + clvm_serialize expected_serialization = (b"a" * 32) + (b"b" * 32) + full_serialize assert c.get_hash() == std_hash(expected_hash) assert c.name() == std_hash(expected_hash) f = io.BytesIO() c.stream(f) assert bytes(f.getvalue()) == expected_serialization # make sure the serialization round-trips f = io.BytesIO(expected_serialization) c2 = Coin.parse(f) assert c2 == c
def test_fun(coin_1: Coin, coin_2: Coin): announce = Announcement(coin_1.name(), b"test") cvp = ConditionWithArgs(ConditionOpcode.ASSERT_COIN_ANNOUNCEMENT, [announce.name()]) dic = {cvp.opcode: [cvp]} cvp2 = ConditionWithArgs( ConditionOpcode.CREATE_COIN_ANNOUNCEMENT, [b"test"], ) dic2 = {cvp.opcode: [cvp2]} spend_bundle1 = generate_test_spend_bundle(coin_1, dic) # coin 2 is making the announcement, right message wrong coin spend_bundle2 = generate_test_spend_bundle(coin_2, dic2) return SpendBundle.aggregate([spend_bundle1, spend_bundle2])
def compute_memos(bundle: SpendBundle) -> Dict[bytes32, List[bytes]]: """ Retrieves the memos for additions in this spend_bundle, which are formatted as a list in the 3rd parameter of CREATE_COIN. If there are no memos, the addition coin_id is not included. If they are not formatted as a list of bytes, they are not included. This is expensive to call, it should not be used in full node code. """ memos: Dict[bytes32, List[bytes]] = {} for coin_spend in bundle.coin_spends: _, result = coin_spend.puzzle_reveal.run_with_cost(INFINITE_COST, coin_spend.solution) for condition in result.as_python(): if condition[0] == ConditionOpcode.CREATE_COIN and len(condition) >= 4: # If only 3 elements (opcode + 2 args), there is no memo, this is ph, amount coin_added = Coin(coin_spend.coin.name(), bytes32(condition[1]), int_from_bytes(condition[2])) if type(condition[3]) != list: # If it's not a list, it's not the correct format continue memos[coin_added.name()] = condition[3] return memos
def get_root_removal(self, coin: Coin) -> Coin: all_removals: Set[Coin] = set(self.bundle.removals()) all_removal_ids: Set[bytes32] = {c.name() for c in all_removals} non_ephemeral_removals: Set[Coin] = { c for c in all_removals if c.parent_coin_info not in {r.name() for r in all_removals} } if coin.name( ) not in all_removal_ids and coin.parent_coin_info not in all_removal_ids: raise ValueError("The specified coin is not a coin in this bundle") while coin not in non_ephemeral_removals: coin = next(c for c in all_removals if c.name() == coin.parent_coin_info) return coin
async def test_store(self): db_filename = Path("wallet_store_test.db") if db_filename.exists(): db_filename.unlink() db_connection = await aiosqlite.connect(db_filename) db_wrapper = DBWrapper(db_connection) store = await WalletInterestedStore.create(db_wrapper) try: coin_1 = Coin(token_bytes(32), token_bytes(32), uint64(12312)) coin_2 = Coin(token_bytes(32), token_bytes(32), uint64(12312)) assert (await store.get_interested_coin_ids()) == [] await store.add_interested_coin_id(coin_1.name()) assert (await store.get_interested_coin_ids()) == [coin_1.name()] await store.add_interested_coin_id(coin_1.name()) assert (await store.get_interested_coin_ids()) == [coin_1.name()] await store.add_interested_coin_id(coin_2.name()) assert set(await store.get_interested_coin_ids()) == { coin_1.name(), coin_2.name() } puzzle_hash = token_bytes(32) assert len(await store.get_interested_puzzle_hashes()) == 0 await store.add_interested_puzzle_hash(puzzle_hash, 2) assert len(await store.get_interested_puzzle_hashes()) == 1 await store.add_interested_puzzle_hash(puzzle_hash, 2) assert len(await store.get_interested_puzzle_hashes()) == 1 assert ( await store.get_interested_puzzle_hash_wallet_id(puzzle_hash)) == 2 await store.add_interested_puzzle_hash(puzzle_hash, 3) assert len(await store.get_interested_puzzle_hashes()) == 1 assert ( await store.get_interested_puzzle_hash_wallet_id(puzzle_hash)) == 3 await store.remove_interested_puzzle_hash(puzzle_hash) assert (await store.get_interested_puzzle_hash_wallet_id( puzzle_hash)) is None assert len(await store.get_interested_puzzle_hashes()) == 0 finally: await db_connection.close() db_filename.unlink()
async def coin_added(self, coin: Coin, header_hash: bytes32, removals: List[Coin], height: int): """Notification from wallet state manager that wallet has been received.""" self.log.info("DID wallet has been notified that coin was added") inner_puzzle = await self.inner_puzzle_for_did_puzzle(coin.puzzle_hash) new_info = DIDInfo( self.did_info.origin_coin, self.did_info.backup_ids, self.did_info.num_of_backup_ids_needed, self.did_info.parent_info, inner_puzzle, None, None, None, ) await self.save_info(new_info, True) future_parent = CCParent( coin.parent_coin_info, inner_puzzle.get_tree_hash(), coin.amount, ) await self.add_parent(coin.name(), future_parent, True)
async def recovery_spend( self, coin: Coin, puzhash: bytes, parent_innerpuzhash_amounts_for_recovery_ids: List[Tuple[bytes, bytes, int]], pubkey: G1Element, spend_bundle: SpendBundle, ) -> SpendBundle: assert self.did_info.origin_coin is not None # innerpuz solution is (mode amount new_puz identity my_puz parent_innerpuzhash_amounts_for_recovery_ids) innersol = Program.to([ 2, coin.amount, puzhash, coin.name(), coin.puzzle_hash, parent_innerpuzhash_amounts_for_recovery_ids, bytes(pubkey), self.did_info.backup_ids, self.did_info.num_of_backup_ids_needed, ]) # full solution is (parent_info my_amount solution) innerpuz = self.did_info.current_inner full_puzzle: Program = did_wallet_puzzles.create_fullpuz( innerpuz, self.did_info.origin_coin.puzzle_hash, ) parent_info = await self.get_parent_for_coin(coin) assert parent_info is not None fullsol = Program.to([ [ self.did_info.origin_coin.parent_coin_info, self.did_info.origin_coin.amount ], [ parent_info.parent_name, parent_info.inner_puzzle_hash, parent_info.amount, ], coin.amount, innersol, ]) list_of_solutions = [CoinSolution(coin, full_puzzle, fullsol)] index = await self.wallet_state_manager.puzzle_store.index_for_pubkey( pubkey) if index is None: raise ValueError("Unknown pubkey.") private = master_sk_to_wallet_sk(self.wallet_state_manager.private_key, index) message = bytes(puzhash) sigs = [AugSchemeMPL.sign(private, message)] for _ in spend_bundle.coin_solutions: sigs.append(AugSchemeMPL.sign(private, message)) aggsig = AugSchemeMPL.aggregate(sigs) # assert AugSchemeMPL.verify(pubkey, message, aggsig) if spend_bundle is None: spend_bundle = SpendBundle(list_of_solutions, aggsig) else: spend_bundle = spend_bundle.aggregate( [spend_bundle, SpendBundle(list_of_solutions, aggsig)]) did_record = TransactionRecord( confirmed_at_height=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=puzhash, amount=uint64(coin.amount), fee_amount=uint64(0), 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, type=uint32(TransactionType.OUTGOING_TX.value), name=token_bytes(), ) await self.standard_wallet.push_transaction(did_record) return spend_bundle
async def coin_added( self, coin: Coin, coinbase: bool, fee_reward: bool, wallet_id: uint32, wallet_type: WalletType, height: uint32, ): """ Adding coin to DB """ self.log.info(f"Adding coin: {coin} at {height}") farm_reward = False if coinbase or fee_reward: farm_reward = True now = uint64(int(time.time())) if coinbase: tx_type: int = TransactionType.COINBASE_REWARD.value else: tx_type = TransactionType.FEE_REWARD.value tx_record = TransactionRecord( confirmed_at_height=uint32(height), created_at_time=now, to_puzzle_hash=coin.puzzle_hash, amount=coin.amount, fee_amount=uint64(0), confirmed=True, sent=uint32(0), spend_bundle=None, additions=[coin], removals=[], wallet_id=wallet_id, sent_to=[], trade_id=None, type=uint32(tx_type), name=coin.name(), ) await self.tx_store.add_transaction_record(tx_record, True) else: records = await self.tx_store.tx_with_addition_coin( coin.name(), wallet_id) if len(records) > 0: # This is the change from this transaction for record in records: if record.confirmed is False: await self.tx_store.set_confirmed(record.name, height) else: now = uint64(int(time.time())) tx_record = TransactionRecord( confirmed_at_height=uint32(height), created_at_time=now, to_puzzle_hash=coin.puzzle_hash, amount=coin.amount, fee_amount=uint64(0), confirmed=True, sent=uint32(0), spend_bundle=None, additions=[coin], removals=[], wallet_id=wallet_id, sent_to=[], trade_id=None, type=uint32(TransactionType.INCOMING_TX.value), name=coin.name(), ) if coin.amount > 0: await self.tx_store.add_transaction_record(tx_record, True) coin_record: WalletCoinRecord = WalletCoinRecord( coin, height, uint32(0), False, farm_reward, wallet_type, wallet_id) await self.coin_store.add_coin_record(coin_record) if wallet_type == WalletType.COLOURED_COIN or wallet_type == WalletType.DISTRIBUTED_ID: wallet = self.wallets[wallet_id] header_hash: bytes32 = self.blockchain.height_to_hash(height) block: Optional[ HeaderBlockRecord] = await self.block_store.get_header_block_record( header_hash) assert block is not None assert block.removals is not None await wallet.coin_added(coin, header_hash, block.removals, height) self.state_changed("coin_added", wallet_id)
def run_generator( block_generator: BlockGenerator, constants: ConsensusConstants, max_cost: int, height: uint32 ) -> List[CAT]: if height >= DEFAULT_CONSTANTS.SOFT_FORK_HEIGHT: # conditions must use integers in canonical encoding (i.e. no redundant # leading zeros) # the division operator may not be used with negative operands flags = COND_CANON_INTS | NO_NEG_DIV else: flags = 0 _, result = block_generator.program.run_with_cost(max_cost, flags, block_generator.generator_refs) coin_spends = result.first() cat_list: List[CAT] = [] for spend in coin_spends.as_iter(): parent, puzzle, amount, solution = spend.as_iter() matched, curried_args = match_cat_puzzle(puzzle) if not matched: continue _, tail_hash, _ = curried_args memo = "" result = puzzle.run(solution) conds: Dict[ConditionOpcode, List[ConditionWithArgs]] = {} for condition in result.as_python(): op = ConditionOpcode(condition[0]) if op not in conds: conds[op] = [] if condition[0] != ConditionOpcode.CREATE_COIN or len(condition) < 4: conds[op].append(ConditionWithArgs(op, [i for i in condition[1:3]])) continue # If only 3 elements (opcode + 2 args), there is no memo, this is ph, amount if type(condition[3]) != list: # If it's not a list, it's not the correct format conds[op].append(ConditionWithArgs(op, [i for i in condition[1:3]])) continue conds[op].append(ConditionWithArgs(op, [i for i in condition[1:3]] + [condition[3][0]])) # special retirement address if condition[3][0].hex() != "0000000000000000000000000000000000000000000000000000000000000000": continue if len(condition[3]) >= 2: try: memo = condition[3][1].decode("utf-8", errors="strict") except UnicodeError: pass # ignore this error which should leave memo as empty string # technically there could be more such create_coin ops in the list but our wallet does not # so leaving it for the future break puzzle_hash = puzzle.get_tree_hash() coin = Coin(parent.atom, puzzle_hash, int_from_bytes(amount.atom)) cat_list.append( CAT( tail_hash=bytes(tail_hash).hex()[2:], memo=memo, npc=NPC(coin.name(), puzzle_hash, [(op, cond) for op, cond in conds.items()]), ) ) return cat_list