mmgen-{txcreate,txdo}: new --autochg-ignore-labels option

As of this commit, addresses in the tracking wallet with labels are considered
reserved, i.e. equivalent to used, for purposes of automatic change address
selection.

Use of this option restores the former default behavior of ignoring labels
during automatic change address selection, with one small difference: when
an address with a label is chosen as a change address candidate, a warning
is displayed before prompting the user for confirmation.

The option may also be set in the configuration file.
This commit is contained in:
The MMGen Project 2023-01-30 10:11:21 +00:00
commit 9412505231
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
7 changed files with 68 additions and 7 deletions

View file

@ -79,6 +79,11 @@
# also turns off all information output for the configured wordlists:
# mnemonic_entry_modes mmgen:minimal bip39:fixed xmrseed:short
# Uncomment to allow addresses with labels to be used as change addresses.
# This option is meaningful only for automatic change address selection.
# When change addresses are chosen manually the option is ignored:
# autochg_ignore_labels true
############################
## Ignore daemon versions ##
############################

View file

@ -1 +1 @@
13.3.dev35
13.3.dev36

View file

@ -86,6 +86,7 @@ class GlobalContext(Lockable):
testnet = False
regtest = False
accept_defaults = False
autochg_ignore_labels = False
# rpc:
rpc_host = ''
@ -152,6 +153,7 @@ class GlobalContext(Lockable):
# global var sets user opt:
global_sets_opt = (
'autochg_ignore_labels',
'debug',
'minconf',
'quiet',
@ -198,6 +200,7 @@ class GlobalContext(Lockable):
('tx_id','terse_info'),
)
cfg_file_opts = (
'autochg_ignore_labels',
'color',
'daemon_data_dir',
'debug',

View file

@ -50,6 +50,7 @@ opts_data = {
MMGen IDs or coin addresses). Note that ALL unspent
outputs associated with each address will be included.
-l, --locktime= t Lock time (block height or unix seconds) (default: 0)
-L, --autochg-ignore-labels Ignore labels when autoselecting change addresses
-m, --minconf= n Minimum number of confirmations required to spend
outputs (default: 1)
-q, --quiet Suppress warnings; overwrite files without prompting

View file

@ -62,6 +62,7 @@ opts_data = {
-K, --keygen-backend=n Use backend 'n' for public key generation. Options
for {coin_id}: {kgs}
-l, --locktime= t Lock time (block height or unix seconds) (default: 0)
-L, --autochg-ignore-labels Ignore labels when autoselecting change addresses
-m, --minconf=n Minimum number of confirmations required to spend
outputs (default: 1)
-M, --mmgen-keys-from-file=f Provide keys for {pnm} addresses in a key-

View file

@ -16,7 +16,7 @@ from ..util import msg,suf,is_int
from ..objmethods import MMGenObject
from ..obj import MMGenListItem,ImmutableAttr,ListItemAttr,TwComment,NonNegativeInt
from ..addr import CoinAddr,MMGenID,MMGenAddrType
from ..color import red,green
from ..color import red,green,yellow
from .view import TwView
from .shared import TwMMGenID
@ -320,9 +320,18 @@ class TwAddresses(TwView):
top = len(data) - 1 if top is None else top )
if start is not None:
from ..opts import opt
for d in data[start:]:
if d.al_id == al_id:
if not d.recvd:
if not d.recvd and (opt.autochg_ignore_labels or not d.comment):
if d.comment:
msg('{} {} {} {}{}'.format(
yellow('WARNING: address'),
d.twmmid.hl(),
yellow('has a label,'),
d.comment.hl2(encl='‘’'),
yellow(',\n but allowing it for change anyway by user request')
))
return d
else:
break
@ -339,10 +348,19 @@ class TwAddresses(TwView):
"""
def choose_address(addrs):
from ..ui import line_input
prompt = '\nChoose a change address:\n\n{m}\n\nEnter a number> '.format(
m = '\n'.join(f'{n:3}) {a.twmmid.hl()}' for n,a in enumerate(addrs,1))
def format_line(n,d):
return '{a:3}) {b}{c}'.format(
a = n,
b = d.twmmid.hl(),
c = yellow(' <== has a label!') if d.comment else ''
)
prompt = '\nChoose a change address:\n\n{}\n\nEnter a number> '.format(
'\n'.join(format_line(n,d) for n,d in enumerate(addrs,1))
)
from ..ui import line_input
while True:
res = line_input(prompt)
if is_int(res) and 0 < int(res) <= len(addrs):

View file

@ -386,6 +386,12 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
('bob_auto_chg_addrtype2', 'creating an automatic change address transaction by addrtype (B)'),
('bob_auto_chg_addrtype3', 'creating an automatic change address transaction by addrtype (S)'),
('bob_auto_chg_addrtype4', 'creating an automatic change address transaction by addrtype (single address)'),
('bob_add_comment_uua1', 'adding a comment for unused address in tracking wallet (C)'),
('bob_auto_chg5', 'creating an auto-chg-address TX, skipping unused address with label (C)'),
('bob_auto_chg_addrtype5', 'creating an auto-chg-address TX by addrtype, skipping unused address with label (C)'),
('bob_auto_chg6', 'creating an auto-chg-address TX, using unused address with label (C)'),
('bob_auto_chg_addrtype6', 'creating an auto-chg-address TX by addrtype, using unused address with label (C)'),
('bob_remove_comment_uua1', 'removing a comment for unused address in tracking wallet (C)'),
('bob_auto_chg_bad1', 'error handling for auto change address transaction (bad ID FFFFFFFF:C)'),
('bob_auto_chg_bad2', 'error handling for auto change address transaction (bad ID 00000000:C)'),
('bob_auto_chg_bad3', 'error handling for auto change address transaction (no unused addresses)'),
@ -1652,13 +1658,14 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
return 'skip'
return self.generate()
def _usr_auto_chg(self,user,mmtype,idx,by_mmtype=False,include_dest=True,by_addrtype=False):
def _usr_auto_chg(self,user,mmtype,idx,by_mmtype=False,include_dest=True,by_addrtype=False,ignore_labels=False):
if mmtype in ('S','B') and not self.proto.cap('segwit'):
return 'skip'
sid = self._user_sid('bob')
t = self.spawn(
'mmgen-txcreate',
[f'--outdir={self.tr.trash_dir}', '--no-blank', f'--{user}'] +
(['--autochg-ignore-labels'] if ignore_labels else []) +
[mmtype if by_mmtype else f'{sid}:{mmtype}'] +
([self.burn_addr+',0.01'] if include_dest else [])
)
@ -1692,6 +1699,32 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
def bob_auto_chg_addrtype4(self):
return self._usr_auto_chg( 'bob', 'C', '3', True, include_dest=False )
def _bob_add_comment_uua(self,addrspec,comment):
sid = self._user_sid('bob')
return self.user_add_comment('bob',sid+addrspec,comment)
def bob_add_comment_uua1(self):
return self._bob_add_comment_uua(':C:3','comment for unused address')
def bob_auto_chg5(self):
return self._usr_auto_chg( 'bob', 'C', '4' )
def bob_auto_chg_addrtype5(self):
return self._usr_auto_chg( 'bob', 'C', '4', True )
def bob_auto_chg6(self):
return self._usr_auto_chg( 'bob', 'C', '3', ignore_labels=True )
def bob_auto_chg_addrtype6(self):
return self._usr_auto_chg( 'bob', 'C', '3', True, ignore_labels=True )
def _bob_remove_comment_uua(self,addrspec):
sid = self._user_sid('bob')
return self.user_remove_comment('bob',sid+addrspec)
def bob_remove_comment_uua1(self):
return self._bob_remove_comment_uua(':C:3')
def _usr_auto_chg_bad(self,user,al_id,expect):
t = self.spawn(
'mmgen-txcreate',