From 77db90ba6a99b8bfec6db20c2b24e545bb5765e2 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 24 Jan 2022 06:45:41 +0100 Subject: [PATCH] move member function get_memos() out of SpendBundle and into a free-function living in the wallet code. It does not belong to the full node. Also rename it to indicate that it's expensive (and dangerous) to call (#9907) --- chia/types/spend_bundle.py | 26 +------------------------- chia/wallet/cat_wallet/cat_wallet.py | 3 ++- chia/wallet/did_wallet/did_wallet.py | 13 +++++++------ chia/wallet/rl_wallet/rl_wallet.py | 7 ++++--- chia/wallet/util/compute_memos.py | 28 ++++++++++++++++++++++++++++ chia/wallet/wallet.py | 3 ++- tests/wallet/rpc/test_wallet_rpc.py | 19 ++++++++++++------- tests/wallet/test_wallet.py | 3 ++- 8 files changed, 58 insertions(+), 44 deletions(-) create mode 100644 chia/wallet/util/compute_memos.py diff --git a/chia/types/spend_bundle.py b/chia/types/spend_bundle.py index 9dacec241d..f8e9977cce 100644 --- a/chia/types/spend_bundle.py +++ b/chia/types/spend_bundle.py @@ -2,20 +2,17 @@ import dataclasses import warnings from dataclasses import dataclass -from typing import List, Dict +from typing import List from blspy import AugSchemeMPL, G2Element -from clvm.casts import int_from_bytes from chia.consensus.default_constants import DEFAULT_CONSTANTS from chia.types.blockchain_format.coin import Coin from chia.types.blockchain_format.sized_bytes import bytes32 from chia.util.streamable import Streamable, dataclass_from_dict, recurse_jsonify, streamable from chia.wallet.util.debug_spend_bundle import debug_spend_bundle -from .blockchain_format.program import Program from .coin_spend import CoinSpend -from .condition_opcodes import ConditionOpcode @dataclass(frozen=True) @@ -80,27 +77,6 @@ class SpendBundle(Streamable): return result - def get_memos(self) -> 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 self.coin_spends: - result = Program.from_bytes(bytes(coin_spend.puzzle_reveal)).run( - Program.from_bytes(bytes(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 - # Note that `coin_spends` used to have the bad name `coin_solutions`. # Some API still expects this name. For now, we accept both names. # diff --git a/chia/wallet/cat_wallet/cat_wallet.py b/chia/wallet/cat_wallet/cat_wallet.py index ca3f0fb525..b934e87a3e 100644 --- a/chia/wallet/cat_wallet/cat_wallet.py +++ b/chia/wallet/cat_wallet/cat_wallet.py @@ -46,6 +46,7 @@ from chia.wallet.util.wallet_types import WalletType, AmountWithPuzzlehash from chia.wallet.wallet import Wallet from chia.wallet.wallet_coin_record import WalletCoinRecord from chia.wallet.wallet_info import WalletInfo +from chia.wallet.util.compute_memos import compute_memos # This should probably not live in this file but it's for experimental right now @@ -720,7 +721,7 @@ class CATWallet: trade_id=None, type=uint32(TransactionType.OUTGOING_TX.value), name=spend_bundle.name(), - memos=list(spend_bundle.get_memos().items()), + memos=list(compute_memos(spend_bundle).items()), ) ] diff --git a/chia/wallet/did_wallet/did_wallet.py b/chia/wallet/did_wallet/did_wallet.py index cdf3a50473..82bf886185 100644 --- a/chia/wallet/did_wallet/did_wallet.py +++ b/chia/wallet/did_wallet/did_wallet.py @@ -20,6 +20,7 @@ from chia.wallet.did_wallet.did_info import DIDInfo from chia.wallet.lineage_proof import LineageProof from chia.wallet.transaction_record import TransactionRecord from chia.wallet.util.wallet_types import WalletType +from chia.wallet.util.compute_memos import compute_memos from chia.wallet.wallet import Wallet from chia.wallet.wallet_coin_record import WalletCoinRecord from chia.wallet.wallet_info import WalletInfo @@ -129,7 +130,7 @@ class DIDWallet: trade_id=None, type=uint32(TransactionType.OUTGOING_TX.value), name=bytes32(token_bytes()), - memos=list(spend_bundle.get_memos().items()), + memos=list(compute_memos(spend_bundle).items()), ) await self.standard_wallet.push_transaction(regular_record) await self.standard_wallet.push_transaction(did_record) @@ -513,7 +514,7 @@ class DIDWallet: trade_id=None, type=uint32(TransactionType.OUTGOING_TX.value), name=token_bytes(), - memos=list(spend_bundle.get_memos().items()), + memos=list(compute_memos(spend_bundle).items()), ) await self.standard_wallet.push_transaction(did_record) return spend_bundle @@ -582,7 +583,7 @@ class DIDWallet: trade_id=None, type=uint32(TransactionType.OUTGOING_TX.value), name=bytes32(token_bytes()), - memos=list(spend_bundle.get_memos().items()), + memos=list(compute_memos(spend_bundle).items()), ) await self.standard_wallet.push_transaction(did_record) return spend_bundle @@ -649,7 +650,7 @@ class DIDWallet: trade_id=None, type=uint32(TransactionType.OUTGOING_TX.value), name=bytes32(token_bytes()), - memos=list(spend_bundle.get_memos().items()), + memos=list(compute_memos(spend_bundle).items()), ) await self.standard_wallet.push_transaction(did_record) return spend_bundle @@ -718,7 +719,7 @@ class DIDWallet: trade_id=None, type=uint32(TransactionType.INCOMING_TX.value), name=bytes32(token_bytes()), - memos=list(spend_bundle.get_memos().items()), + memos=list(compute_memos(spend_bundle).items()), ) await self.standard_wallet.push_transaction(did_record) if filename is not None: @@ -859,7 +860,7 @@ class DIDWallet: trade_id=None, type=uint32(TransactionType.OUTGOING_TX.value), name=bytes32(token_bytes()), - memos=list(spend_bundle.get_memos().items()), + memos=list(compute_memos(spend_bundle).items()), ) await self.standard_wallet.push_transaction(did_record) new_did_info = DIDInfo( diff --git a/chia/wallet/rl_wallet/rl_wallet.py b/chia/wallet/rl_wallet/rl_wallet.py index 8a3fdcbba3..b18e0372cc 100644 --- a/chia/wallet/rl_wallet/rl_wallet.py +++ b/chia/wallet/rl_wallet/rl_wallet.py @@ -29,6 +29,7 @@ from chia.wallet.rl_wallet.rl_wallet_puzzles import ( from chia.wallet.transaction_record import TransactionRecord from chia.wallet.util.transaction_type import TransactionType from chia.wallet.util.wallet_types import WalletType +from chia.wallet.util.compute_memos import compute_memos from chia.wallet.wallet import Wallet from chia.wallet.wallet_coin_record import WalletCoinRecord from chia.wallet.wallet_info import WalletInfo @@ -320,7 +321,7 @@ class RLWallet: trade_id=None, type=uint32(TransactionType.OUTGOING_TX.value), name=spend_bundle.name(), - memos=list(spend_bundle.get_memos().items()), + memos=list(compute_memos(spend_bundle).items()), ) asyncio.create_task(self.push_transaction(tx_record)) @@ -546,7 +547,7 @@ class RLWallet: trade_id=None, type=uint32(TransactionType.OUTGOING_TX.value), name=spend_bundle.name(), - memos=list(spend_bundle.get_memos().items()), + memos=list(compute_memos(spend_bundle).items()), ) async def rl_sign_transaction(self, spends: List[CoinSpend]) -> SpendBundle: @@ -623,7 +624,7 @@ class RLWallet: trade_id=None, type=uint32(TransactionType.OUTGOING_TX.value), name=spend_bundle.name(), - memos=list(spend_bundle.get_memos().items()), + memos=list(compute_memos(spend_bundle).items()), ) # This is for using the AC locked coin and aggregating it into wallet - must happen in same block as RL Mode 2 diff --git a/chia/wallet/util/compute_memos.py b/chia/wallet/util/compute_memos.py new file mode 100644 index 0000000000..9394714c09 --- /dev/null +++ b/chia/wallet/util/compute_memos.py @@ -0,0 +1,28 @@ +from typing import List, Dict + +from clvm.casts import int_from_bytes +from chia.types.blockchain_format.program import Program +from chia.types.spend_bundle import SpendBundle +from chia.types.blockchain_format.sized_bytes import bytes32 +from chia.types.blockchain_format.coin import Coin +from chia.types.condition_opcodes import ConditionOpcode + + +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 = Program.from_bytes(bytes(coin_spend.puzzle_reveal)).run(Program.from_bytes(bytes(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 diff --git a/chia/wallet/wallet.py b/chia/wallet/wallet.py index 063edf1d98..b1739be947 100644 --- a/chia/wallet/wallet.py +++ b/chia/wallet/wallet.py @@ -40,6 +40,7 @@ from chia.wallet.util.transaction_type import TransactionType from chia.wallet.util.wallet_types import WalletType, AmountWithPuzzlehash from chia.wallet.wallet_coin_record import WalletCoinRecord from chia.wallet.wallet_info import WalletInfo +from chia.wallet.util.compute_memos import compute_memos class Wallet: @@ -485,7 +486,7 @@ class Wallet: trade_id=None, type=uint32(TransactionType.OUTGOING_TX.value), name=spend_bundle.name(), - memos=list(spend_bundle.get_memos().items()), + memos=list(compute_memos(spend_bundle).items()), ) async def push_transaction(self, tx: TransactionRecord) -> None: diff --git a/tests/wallet/rpc/test_wallet_rpc.py b/tests/wallet/rpc/test_wallet_rpc.py index 4051517404..53f177e57c 100644 --- a/tests/wallet/rpc/test_wallet_rpc.py +++ b/tests/wallet/rpc/test_wallet_rpc.py @@ -31,6 +31,7 @@ from chia.wallet.cat_wallet.cat_constants import DEFAULT_CATS from chia.wallet.trading.trade_status import TradeStatus from chia.wallet.transaction_record import TransactionRecord from chia.wallet.transaction_sorting import SortKey +from chia.wallet.util.compute_memos import compute_memos from tests.setup_nodes import bt, setup_simulators_and_wallets, self_hostname from tests.time_out_assert import time_out_assert @@ -293,7 +294,7 @@ class TestWalletRpc: addition.parent_coin_info, cr.confirmed_block_index ) sb: SpendBundle = SpendBundle([spend], G2Element()) - assert sb.get_memos() == {addition.name(): [b"hhh"]} + assert compute_memos(sb) == {addition.name(): [b"hhh"]} found = True assert found @@ -364,12 +365,16 @@ class TestWalletRpc: # Checks that the memo can be retrieved tx_confirmed = await client.get_transaction("1", send_tx_res.name) assert tx_confirmed.confirmed - assert len(tx_confirmed.get_memos()) == 2 - print(tx_confirmed.get_memos()) - assert [b"FiMemo"] in tx_confirmed.get_memos().values() - assert [b"SeMemo"] in tx_confirmed.get_memos().values() - assert list(tx_confirmed.get_memos().keys())[0] in [a.name() for a in send_tx_res.spend_bundle.additions()] - assert list(tx_confirmed.get_memos().keys())[1] in [a.name() for a in send_tx_res.spend_bundle.additions()] + if isinstance(tx_confirmed, SpendBundle): + memos = compute_memos(tx_confirmed) + else: + memos = tx_confirmed.get_memos() + assert len(memos) == 2 + print(memos) + assert [b"FiMemo"] in memos.values() + assert [b"SeMemo"] in memos.values() + assert list(memos.keys())[0] in [a.name() for a in send_tx_res.spend_bundle.additions()] + assert list(memos.keys())[1] in [a.name() for a in send_tx_res.spend_bundle.additions()] ############## # CATS # diff --git a/tests/wallet/test_wallet.py b/tests/wallet/test_wallet.py index d398d00d76..98b84a7e58 100644 --- a/tests/wallet/test_wallet.py +++ b/tests/wallet/test_wallet.py @@ -11,6 +11,7 @@ from chia.types.peer_info import PeerInfo from chia.util.ints import uint16, uint32, uint64 from chia.wallet.derive_keys import master_sk_to_wallet_sk from chia.wallet.util.transaction_type import TransactionType +from chia.wallet.util.compute_memos import compute_memos from chia.wallet.transaction_record import TransactionRecord from chia.wallet.wallet_node import WalletNode from chia.wallet.wallet_state_manager import WalletStateManager @@ -617,7 +618,7 @@ class TestWalletSimulator: trade_id=None, type=uint32(TransactionType.OUTGOING_TX.value), name=name, - memos=list(stolen_sb.get_memos().items()), + memos=list(compute_memos(stolen_sb).items()), ) await wallet.push_transaction(stolen_tx)