From b47fff4a9fa796b3af08f65be7dd3e58479595a6 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Tue, 3 Nov 2026 10:16:03 +0000 Subject: [PATCH] various cleanups --- mmgen/proto/rune/tx/protobuf.py | 2 +- mmgen/proto/xmr/addrgen.py | 18 ++++++------ mmgen/tx/file.py | 21 ++++++------- mmgen/xmrwallet/ops/wallet.py | 15 ++++++---- test/cmdtest_d/autosign.py | 13 +++++---- test/cmdtest_d/xmr_autosign.py | 52 ++++++++++++++++++++++++++++++--- test/cmdtest_d/xmrswap.py | 2 +- test/cmdtest_d/xmrwallet.py | 22 ++++++++------ 8 files changed, 99 insertions(+), 46 deletions(-) diff --git a/mmgen/proto/rune/tx/protobuf.py b/mmgen/proto/rune/tx/protobuf.py index aba0653d..3076bbeb 100644 --- a/mmgen/proto/rune/tx/protobuf.py +++ b/mmgen/proto/rune/tx/protobuf.py @@ -189,7 +189,7 @@ def tx_info(tx, proto): yield f'To: {to_addr}' yield f'Asset: {asset}' yield f'Amount: {amt}' - yield f'Fee: {None if fee is None else fee.hl(color=None)}' + yield f'Fee: {None if fee is None else fee.hl(color=False)}' yield f'Sequence: {int(s.sequence)}' yield f'Gas limit: {tx.authInfo.fee.gasLimit}' yield f'Memo: {memo}' diff --git a/mmgen/proto/xmr/addrgen.py b/mmgen/proto/xmr/addrgen.py index 20ad5b12..07b42aaf 100644 --- a/mmgen/proto/xmr/addrgen.py +++ b/mmgen/proto/xmr/addrgen.py @@ -13,22 +13,22 @@ proto.xmr.addrgen: Monero address generation class for the MMGen suite from ...addrgen import addr_generator, check_data from ...addr import CoinAddr -class monero(addr_generator.keccak): +def b58enc(addr_bytes): + from ...baseconv import baseconv + enc = baseconv('b58').frombytes + l = len(addr_bytes) + a = ''.join([enc(addr_bytes[i*8:i*8+8], pad=11, tostr=True) for i in range(l//8)]) + b = enc(addr_bytes[l-l%8:], pad=7, tostr=True) + return a + b - def b58enc(self, addr_bytes): - from ...baseconv import baseconv - enc = baseconv('b58').frombytes - l = len(addr_bytes) - a = ''.join([enc(addr_bytes[i*8:i*8+8], pad=11, tostr=True) for i in range(l//8)]) - b = enc(addr_bytes[l-l%8:], pad=7, tostr=True) - return a + b +class monero(addr_generator.keccak): @check_data def to_addr(self, data): step1 = self.proto.addr_fmt_to_ver_bytes['monero'] + data.pubkey return CoinAddr( proto = self.proto, - addr = self.b58enc(step1 + self.keccak_256(step1).digest()[:4])) + addr = b58enc(step1 + self.keccak_256(step1).digest()[:4])) @check_data def to_viewkey(self, data): diff --git a/mmgen/tx/file.py b/mmgen/tx/file.py index 2430fdce..ceb86868 100644 --- a/mmgen/tx/file.py +++ b/mmgen/tx/file.py @@ -57,18 +57,19 @@ def eval_io_data(tx, data, *, desc): class MMGenTxFile(MMGenObject): data_label = 'MMGenTransaction' xmr_data_label = 'MoneroMMGenTX' - attrs = { - 'chain': None, - 'txid': MMGenTxID, - 'send_amt': 'skip', - 'timestamp': None, - 'blockcount': None, - 'serialized': None} - def __init__(self, tx): self.tx = tx self.fmt_data = None self.filename = None + self.attrs = { + 'chain': None, + 'txid': MMGenTxID, + 'send_amt': 'skip', + 'timestamp': None, + 'blockcount': None, + 'serialized': None} + if tx.is_compat: + del self.attrs['timestamp'] # property for XMR (mmgen/proto/xmr/tx/completed.py) self.extra_attrs = { 'locktime': None, 'comment': MMGenTxComment, @@ -76,8 +77,8 @@ class MMGenTxFile(MMGenObject): 'is_swap': None, 'is_refreq': None} | ( {} if tx.is_compat else { - 'coin_txid': CoinTxID, - 'sent_timestamp': None}) + 'coin_txid': CoinTxID, # set from compat_data (see below) + 'sent_timestamp': None}) # property for XMR (mmgen/proto/xmr/tx/completed.py) def parse(self, infile, *, get_proto_only=False, quiet_open=False): tx = self.tx diff --git a/mmgen/xmrwallet/ops/wallet.py b/mmgen/xmrwallet/ops/wallet.py index 33edba44..969e84bd 100644 --- a/mmgen/xmrwallet/ops/wallet.py +++ b/mmgen/xmrwallet/ops/wallet.py @@ -86,12 +86,7 @@ class OpWallet(OpBase): ignore_in_fmt = True) gmsg('\nCreating ephemeral key-address list for offline wallets') - self.kal = KeyAddrList( - cfg = cfg, - proto = self.proto, - seed = self.seed_src.seed, - addr_idxs = self.uargs.wallets, - skip_chksum_msg = True) + self.kal = self.gen_keyaddr_list(self.uargs.wallets) else: self.mount_removable_device() self.kal = (ViewKeyAddrList if self.cfg.watch_only else KeyAddrList)( @@ -131,6 +126,14 @@ class OpWallet(OpBase): def get_idx_from_fn(cls, fn): return int(re.match(r'[0-9a-fA-F]{8}-(\d+)-Monero(WatchOnly)?Wallet.*', fn.name)[1]) + def gen_keyaddr_list(self, wallets_spec): + return KeyAddrList( + cfg = self.cfg, + proto = self.proto, + seed = self.seed_src.seed, + addr_idxs = wallets_spec, + skip_chksum_msg = True) + def pre_init_action(self): if self.cfg.skip_empty_accounts: msg(orange('Skipping display of empty accounts where applicable')) diff --git a/test/cmdtest_d/autosign.py b/test/cmdtest_d/autosign.py index eae22575..84ed41d7 100644 --- a/test/cmdtest_d/autosign.py +++ b/test/cmdtest_d/autosign.py @@ -56,6 +56,7 @@ class CmdTestAutosignBase(CmdTestBase): platform_skip = ('win32',) threaded = False daemon_coins = [] + extra_asi_cfg = {} filedir_map = ( ('btc', ''), @@ -117,12 +118,12 @@ class CmdTestAutosignBase(CmdTestBase): d['online'] = {'name':'asi_online'} for subdir, data in d.items(): - asi = Autosign( - Config({ - 'coins': ','.join(self.coins), - 'test_suite_autosign_threaded': self.threaded, - 'test_suite_autosign_root_dir': None if self.live else self.tmpdir, - 'online': subdir == 'online'})) + asi_cfg = { + 'coins': ','.join(self.coins), + 'test_suite_autosign_threaded': self.threaded, + 'test_suite_autosign_root_dir': None if self.live else self.tmpdir, + 'online': subdir == 'online'} + asi = Autosign(Config(asi_cfg | self.extra_asi_cfg)) if create_dirs and not self.live: for k in ('mountpoint', 'shm_dir', 'wallet_dir'): diff --git a/test/cmdtest_d/xmr_autosign.py b/test/cmdtest_d/xmr_autosign.py index d35ef037..9e36e2d3 100644 --- a/test/cmdtest_d/xmr_autosign.py +++ b/test/cmdtest_d/xmr_autosign.py @@ -13,7 +13,9 @@ test.cmdtest_d.xmr_autosign: xmr autosigning tests for the cmdtest.py test suite import os, re, asyncio, json +from mmgen.util import suf from mmgen.color import blue, cyan, brown +from mmgen.fileutil import get_data_from_file from ..include.common import ( imsg, @@ -256,6 +258,9 @@ class CmdTestXMRAutosign(CmdTestXMRWallet, CmdTestAutosignThreaded, CmdTestShare return self.autosign_xmr_setup(write_viewkeys=False) def autosign_xmr_setup(self, write_viewkeys=True): + from mmgen.addrlist import AddrIdxList + al = AddrIdxList(fmt_str=self.users[self.user].kal_range) + self.insert_device_online() self.do_mount_online() self.asi_online.xmr_dir.mkdir(exist_ok=True) @@ -264,6 +269,7 @@ class CmdTestXMRAutosign(CmdTestXMRWallet, CmdTestAutosignThreaded, CmdTestShare self.remove_device_online() self.insert_device() + t = self.spawn( 'mmgen-autosign', self.opts + self.autosign_setup_opts + ['xmr_setup'], @@ -272,6 +278,11 @@ class CmdTestXMRAutosign(CmdTestXMRWallet, CmdTestAutosignThreaded, CmdTestShare t.written_to_file('View keys') else: t.expect('already exists, skipping') + + for n in range(len(al) + 1): + t.expect('Creating') + + t.expect(f'{len(al)} wallet{suf(al)} created') t.read() self.remove_device() return t @@ -568,14 +579,14 @@ class CmdTestXMRCompat(CmdTestXMRAutosign): ('user_twview_chk3', 'viewing user’s tracking wallets (check balances)'), ('user_txcreate_sweep2', 'creating a sweep transaction (address sweep)'), ('user_txsend3', 'sending the transaction'), + ('wait_loop_kill', 'stopping autosign wait loop'), ('mine_blocks_10', 'mining some blocks'), ('user_twview_chk4', 'viewing user’s tracking wallets (check balances)'), - ('wait_loop_kill', 'stopping autosign wait loop'), ('delete_offline_shmdir', 'deleting offline autosign wallet dir'), ('autosign_setup', 'autosign setup with user’s seed'), ('autosign_xmr_setup_redo', 'autosign setup (creation of Monero signing wallets, redo)'), - ('wait_loop_start_compat', 'starting autosign wait loop in XMR compat mode [--coins=xmr]'), ('user_txcreate_sweep3', 'creating a sweep transaction (sweep to empty account)'), + ('wait_loop_start_compat2', 'starting autosign wait loop in XMR compat mode [--coins=xmr]'), ('user_txsend4', 'sending the transaction'), ('mine_blocks_10', 'mining some blocks'), ('user_twview_chk5', 'viewing user’s tracking wallets (check balances)'), @@ -818,6 +829,8 @@ class CmdTestXMRCompat(CmdTestXMRAutosign): def wait_loop_start_compat(self): return self.wait_loop_start(opts=['--xmrwallet-compat', '--coins=xmr']) + wait_loop_start_compat2 = wait_loop_start_compat + def wait_loop_start_ltc(self): return self.wait_loop_start(opts=['--xmrwallet-compat', '--coins=ltc,xmr']) @@ -935,6 +948,7 @@ class CmdTestXMRCompatDev(CmdTestXMRCompat): """ Monero autosigning operations (compat mode, for development) """ + extra_asi_cfg = {'xmrwallet_compat': True} extra_daemons = [] tx_relay_user = None user_data = ( @@ -951,11 +965,41 @@ class CmdTestXMRCompatDev(CmdTestXMRCompat): ('mine_initial_coins', 'mining initial coins'), ('fund_user1', 'sending funds to user (wallet #1)'), ('check_bal_alice', 'mining, checking balance'), - ('user_txcreate1', 'creating a transaction'), + # ('user_txcreate1', 'creating a transaction'), + ('user_txcreate_sweep1', 'creating a sweep transaction'), ('wait_loop_start_xmr', 'starting autosign wait loop in XMR compat mode [--coins=xmr]'), - ('wait_signed1', 'autosigning the transaction'), + # ('wait_signed1', 'autosigning the transaction'), + ('user_txsend1', 'sending the transaction'), + ('user_gettxdata', 'getting transaction data'), + # ('user_listaddresses_refresh', 'refreshing wallet'), ('wait_loop_kill', 'stopping autosign wait loop'), ('stop_daemons', 'stopping all wallet and coin daemons')) + def user_view(self): + return self.sync_wallets(self.user, op='listview', wallets='1') + + def user_txcreate_sweep1(self): + return self._user_txops('txcreate', menu='s', sweep_menu='1', sweep_type='sweep') + def wait_loop_start_xmr(self): return self.wait_loop_start(opts=['--xmrwallet-compat', '--coins=xmr']) + + async def user_gettxdata(self): + self.insert_device_online() + self.do_mount_online() + fn = get_file_with_ext(self.asi_online.txauto_dir, 'asubtx') + txdata = json.loads(get_data_from_file(self.cfg, fn))['MMGenTransaction']['MoneroMMGenTX']['data'] + from mmgen.util import pp_msg + pp_msg(txdata) + self.do_umount_online() + self.remove_device_online() + udata = self.users[self.user] + rpc_data = udata.md_rpc.call_raw( + 'get_transactions', + txs_hashes = [txdata['txid']], + decode_as_json = True) + tx_parsed = json.loads(rpc_data['txs'][0]['as_json']) + pp_msg(rpc_data['txs_as_hex'][0]) + pp_msg(txdata['blob']) + pp_msg(tx_parsed) + return 'ok' diff --git a/test/cmdtest_d/xmrswap.py b/test/cmdtest_d/xmrswap.py index fba44de1..c760c838 100644 --- a/test/cmdtest_d/xmrswap.py +++ b/test/cmdtest_d/xmrswap.py @@ -333,7 +333,7 @@ class CmdTestXMRSwap(CmdTestXMRSwapMethods, CmdTestSwap): return self._swaptxcreate_refnum_xmr(['XMR', 'LTC'], exit_val=1) def swaptxcreate_refnum7(self): - from mmgen.rpc import get_remote_rpc + from mmgen.rpc import get_remote_rpc # pylint: disable=no-name-in-module from mmgen.protocol import init_proto rpc = get_remote_rpc(self.cfg, init_proto(self.cfg, 'RUNE', network='regtest')) vault_addr = rpc.inbound_addrs(coin='XMR')['address'] diff --git a/test/cmdtest_d/xmrwallet.py b/test/cmdtest_d/xmrwallet.py index ca6c988b..984515ec 100644 --- a/test/cmdtest_d/xmrwallet.py +++ b/test/cmdtest_d/xmrwallet.py @@ -85,20 +85,22 @@ class CmdTestXMRWallet(CmdTestBase): cmd_group = ( ('daemon_version', 'checking daemon version'), ('gen_kafiles_miner_alice', 'generating key-address files for Miner and Alice'), - ('create_wallets_miner', 'creating Monero wallets (Miner)'), - ('set_label_miner', 'setting an address label (Miner, primary account)'), - ('mine_initial_coins', 'mining initial coins'), - ('create_wallets_alice', 'creating Monero wallets (Alice)'), - ('fund_alice', 'sending funds'), - ('check_bal_alice', 'mining, checking balance'), - ('sync_wallets_all', 'syncing all wallets'), + ('create_wallets_alice', 'creating Monero wallets (Alice)'), ('new_account_alice', 'creating a new account (Alice)'), ('new_account_alice_label', 'creating a new account (Alice, with label)'), ('new_address_alice', 'creating a new address (Alice)'), ('new_address_alice_label', 'creating a new address (Alice, with label)'), ('remove_label_alice', 'removing an address label (Alice, subaddress)'), ('set_label_alice', 'setting an address label (Alice, subaddress)'), + + ('create_wallets_miner', 'creating Monero wallets (Miner)'), + ('set_label_miner', 'setting an address label (Miner, primary account)'), + ('mine_initial_coins', 'mining initial coins'), + ('fund_alice', 'sending funds'), + ('check_bal_alice', 'mining, checking balance'), + + ('sync_wallets_all', 'syncing all wallets'), ('sync_wallets_selected', 'syncing selected wallets'), ('sweep_to_wallet', 'sweeping to new account in another wallet'), @@ -328,13 +330,14 @@ class CmdTestXMRWallet(CmdTestBase): self._create_address_files(t, user, wallet=wallet, watch_only=watch_only) return t - def _new_addr_user(self, user, spec, cfg, expect, kafile=None, do_autosign=False): + def _new_addr_user(self, user, spec, cfg, expect, kafile=None, do_autosign=False, add_opts=[]): data = self.users[user] if do_autosign: self.insert_device_online() t = self.spawn( 'mmgen-xmrwallet', self.extra_opts + + add_opts + (self.autosign_opts if do_autosign else []) + [f'--{user}'] + (['--compat'] if self.compat else []) @@ -378,7 +381,8 @@ class CmdTestXMRWallet(CmdTestBase): 'alice', '4:2,Alice’s new address', 'stop', - r'Creating new address for wallet .*4.*, account .*#2.* with label .*‘Alice’s new address .*y/N\): ') + r'Creating new address for wallet .*4.*, account .*#2.* with label .*‘Alice’s new address .*y/N\): ', + add_opts = ['--full-address']) async def mine_initial_coins(self): self.spawn(msg_only=True, extra_desc='(opening wallet)')