mmgen-txsend: support transaction selection with --status

Examples (assumes --autosign):

    # View status of last sent transaction:
    $ mmgen-txsend --status

    # Same as above:
    $ mmgen-txsend --status 0

    # View status of next-to-last sent transaction:
    $ mmgen-txsend --status 1

Testing/demo:

    $ test/cmdtest.py -e -X alice_txstatus8 autosign_automount
This commit is contained in:
The MMGen Project 2026-01-30 09:20:21 +00:00
commit 4f1b16f489
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
4 changed files with 40 additions and 12 deletions

View file

@ -334,19 +334,22 @@ class Signable:
shred_file(self.cfg, fn, iterations=15)
sys.exit(0)
async def get_last_sent(self):
async def get_last_sent(self, *, idx=0):
return await self.get_last_created(
# compat fallback - ‘sent_timestamp’ attr is missing in some old TX files:
sort_key = lambda x: x.sent_timestamp or x.timestamp)
sort_key = lambda x: x.sent_timestamp or x.timestamp,
idx = idx)
async def get_last_created(self, *, sort_key=lambda x: x.timestamp):
async def get_last_created(self, *, sort_key=lambda x: x.timestamp, idx=0):
from .tx import CompletedTX
fns = [f for f in self.dir.iterdir() if f.name.endswith(self.subext)]
files = sorted(
[await CompletedTX(cfg=self.cfg, filename=str(txfile), quiet_open=True)
for txfile in fns],
key = sort_key)
return files[-1]
if not (0 <= idx < len(files)):
die(2, f'{idx}: invalid transaction index (must be less than {len(files)})')
return files[-1 - idx]
class xmr_signable: # mixin class
automount = True

View file

@ -1 +1 @@
16.1.dev27
16.1.dev28

View file

@ -23,7 +23,7 @@ mmgen-txsend: Broadcast a transaction signed by 'mmgen-txsign' to the network
import sys
from .cfg import gc, Config
from .util import async_run, die
from .util import async_run, die, is_int
opts_data = {
'sets': [
@ -35,6 +35,7 @@ opts_data = {
'usage2': [
'[opts] <signed transaction file>',
'[opts] --autosign',
'[opts] --autosign (--status | --receipt) [IDX]',
],
'options': """
-h, --help Print this help message
@ -68,6 +69,12 @@ opts_data = {
Use special value env to honor *_PROXY environment vars
instead.
-y, --yes Answer 'yes' to prompts, suppress non-essential output
""",
'notes': """
With --autosign, combined with --status or --receipt, the optional IDX arg
represents an index into the list of sent transaction files on the removable
device, in reverse chronological order. 0 (the default) specifies the
last sent transaction, 1 the next-to-last, and so on.
"""
},
'code': {
@ -95,8 +102,8 @@ post_send_op = cfg.status or cfg.receipt
asi = None
def init_autosign():
global asi, si, infile
def init_autosign(arg):
global asi, si, infile, tx_idx
from .tx.util import mount_removable_device
from .autosign import Signable
asi = mount_removable_device(cfg)
@ -108,13 +115,18 @@ def init_autosign():
die(1, 'Transaction is unsent')
if si.unsigned:
die(1, 'Transaction is unsigned')
if not is_int(arg):
die(2, f'{arg}: invalid transaction index (must be a non-negative integer)')
tx_idx = int(arg)
else:
infile = si.get_unsent()
cfg._util.qmsg(f'Got signed transaction file ‘{infile}')
match cfg._args:
case [arg] if cfg.autosign and post_send_op:
init_autosign(arg)
case [] if cfg.autosign:
init_autosign()
init_autosign(0)
case [infile]:
from .fileutil import check_infile
check_infile(infile)
@ -132,7 +144,7 @@ async def main():
global cfg
if cfg.autosign and post_send_op:
tx = await si.get_last_sent()
tx = await si.get_last_sent(idx=tx_idx)
else:
tx = await OnlineSignedTX(
cfg = cfg,

View file

@ -82,6 +82,9 @@ class CmdTestAutosignAutomount(CmdTestAutosignThreaded, CmdTestRegtest):
('alice_txbump5', 'bumping the transaction (new outputs)'),
('alice_txsend5', 'sending the bumped transaction'),
('alice_txstatus5', 'getting transaction status (in mempool)'),
('alice_txstatus6', 'getting transaction status (idx=0, in mempool)'),
('alice_txstatus7', 'getting transaction status (idx=1, replaced)'),
('alice_txstatus8', 'getting transaction status (idx=3, 2 confirmations)'),
('generate', 'mining a block'),
('alice_bal2', 'checking Alice’s balance'),
('wait_loop_kill', 'stopping autosign wait loop'),
@ -221,7 +224,7 @@ class CmdTestAutosignAutomount(CmdTestAutosignThreaded, CmdTestRegtest):
def alice_txsend5(self):
return self._user_txsend('alice', need_rbf=True)
def _alice_txstatus(self, expect, exit_val=None, need_rbf=False):
def _alice_txstatus(self, expect, exit_val=None, need_rbf=False, idx=None):
if need_rbf and not self.proto.cap('rbf'):
return 'skip'
@ -229,7 +232,8 @@ class CmdTestAutosignAutomount(CmdTestAutosignThreaded, CmdTestRegtest):
self.insert_device_online()
t = self.spawn(
'mmgen-txsend',
['--alice', '--autosign', '--status', '--verbose'],
['--alice', '--autosign', '--status', '--verbose']
+ ([] if idx is None else [str(idx)]),
no_passthru_opts = ['coin'],
exit_val = exit_val)
t.expect(expect)
@ -255,6 +259,15 @@ class CmdTestAutosignAutomount(CmdTestAutosignThreaded, CmdTestRegtest):
def alice_txstatus5(self):
return self._alice_txstatus('in mempool', need_rbf=True)
def alice_txstatus6(self):
return self._alice_txstatus('in mempool', need_rbf=True, idx=0)
def alice_txstatus7(self):
return self._alice_txstatus('replaced', need_rbf=True, idx=1)
def alice_txstatus8(self):
return self._alice_txstatus('2 confirmations', need_rbf=True, idx=3)
def alice_txsend_bad_no_unsent(self):
self.insert_device_online()
t = self.spawn('mmgen-txsend', ['--quiet', '--autosign'], exit_val=2, no_passthru_opts=['coin'])