Skip to content

Commit

Permalink
mmgen-{txcreate,txdo}: new --autochg-ignore-labels option
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mmgen committed Jan 30, 2023
1 parent 56a8652 commit 9412505
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 7 deletions.
5 changes: 5 additions & 0 deletions mmgen/data/mmgen.cfg
Expand Up @@ -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 ##
############################
Expand Down
2 changes: 1 addition & 1 deletion mmgen/data/version
@@ -1 +1 @@
13.3.dev35
13.3.dev36
3 changes: 3 additions & 0 deletions mmgen/globalvars.py
Expand Up @@ -86,6 +86,7 @@ class GlobalContext(Lockable):
testnet = False
regtest = False
accept_defaults = False
autochg_ignore_labels = False

# rpc:
rpc_host = ''
Expand Down Expand Up @@ -152,6 +153,7 @@ class GlobalContext(Lockable):

# global var sets user opt:
global_sets_opt = (
'autochg_ignore_labels',
'debug',
'minconf',
'quiet',
Expand Down Expand Up @@ -198,6 +200,7 @@ class GlobalContext(Lockable):
('tx_id','terse_info'),
)
cfg_file_opts = (
'autochg_ignore_labels',
'color',
'daemon_data_dir',
'debug',
Expand Down
1 change: 1 addition & 0 deletions mmgen/main_txcreate.py
Expand Up @@ -50,6 +50,7 @@
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
Expand Down
1 change: 1 addition & 0 deletions mmgen/main_txdo.py
Expand Up @@ -62,6 +62,7 @@
-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-
Expand Down
28 changes: 23 additions & 5 deletions mmgen/tw/addresses.py
Expand Up @@ -16,7 +16,7 @@
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

Expand Down Expand Up @@ -320,9 +320,18 @@ def get_start(bot,top):
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
Expand All @@ -339,10 +348,19 @@ def get_change_address_by_addrtype(self,mmtype):
"""

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):
Expand Down
35 changes: 34 additions & 1 deletion test/test_py_d/ts_regtest.py
Expand Up @@ -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)'),
Expand Down Expand Up @@ -1652,13 +1658,14 @@ def bob_auto_chg_generate(self):
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 [])
)
Expand Down Expand Up @@ -1692,6 +1699,32 @@ def bob_auto_chg_addrtype3(self):
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',
Expand Down

0 comments on commit 9412505

Please sign in to comment.