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'])