fixes and cleanups throughout

This commit is contained in:
The MMGen Project 2025-02-24 11:27:44 +00:00
commit 7b6717d85a
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
11 changed files with 79 additions and 62 deletions

View file

@ -164,34 +164,26 @@ async def main():
kal = kl = sign_and_send = None
else:
orig_tx = await CompletedTX(cfg=cfg, filename=tx_file)
kal = get_keyaddrlist(cfg, orig_tx.proto)
kl = get_keylist(cfg)
sign_and_send = any([seed_files, kl, kal])
if not silent:
msg(green('ORIGINAL TRANSACTION'))
msg(orig_tx.info.format(terse=True))
if not cfg.autosign:
kal = get_keyaddrlist(cfg, orig_tx.proto)
kl = get_keylist(cfg)
sign_and_send = any([seed_files, kl, kal])
from .tw.ctl import TwCtl
tx = await BumpTX(
cfg = cfg,
data = orig_tx.__dict__,
automount = cfg.autosign,
check_sent = cfg.autosign or sign_and_send,
new_outputs = bool(cfg._args),
twctl = await TwCtl(cfg, orig_tx.proto) if orig_tx.proto.tokensym else None)
tx.orig_rel_fee = tx.get_orig_rel_fee()
if cfg._args:
tx.new_outputs = True
tx.is_swap = False
tx.outputs = tx.OutputList(tx)
tx.cfg = cfg # NB: with --automount, must use current cfg opts, not those from orig_tx
if tx.new_outputs:
await tx.create(cfg._args, caller='txdo' if sign_and_send else 'txcreate')
else:
tx.new_outputs = False
await tx.create_feebump(silent=silent)
if not silent:

View file

@ -21,8 +21,8 @@ from .new import New, TokenNew
class Bump(Completed, New, TxBase.Bump):
desc = 'fee-bumped transaction'
def get_orig_rel_fee(self): # disable this check for ETH
return 0
def get_orig_rel_fee(self):
return self.txobj['gasPrice'].to_unit('Gwei')
@property
def min_fee(self):

View file

@ -15,16 +15,29 @@ tx.bump: transaction bump class
from .new import New
from .completed import Completed
from ..util import msg, ymsg, is_int, die
from ..color import pink
class Bump(Completed, New):
desc = 'fee-bumped transaction'
ext = 'rawtx'
bump_output_idx = None
is_bump = True
swap_attrs = ('is_swap',)
def __init__(self, check_sent, *args, **kwargs):
def __init__(self, *, check_sent, new_outputs, **kwargs):
super().__init__(*args, **kwargs)
super().__init__(**kwargs)
self.new_outputs = new_outputs
self.orig_rel_fee = self.get_orig_rel_fee()
if new_outputs:
from .base import Base
if self.is_swap:
for attr in self.swap_attrs:
setattr(self, attr, getattr(Base, attr))
self.outputs = self.OutputList(self)
self.cfg = kwargs['cfg'] # must use current cfg opts, not those from orig_tx
if not self.is_replaceable():
die(1, f'Transaction {self.txid} is not replaceable')
@ -60,7 +73,11 @@ class Bump(Completed, New):
output_idx = self.choose_output()
if not silent:
msg(f'Minimum fee for new transaction: {self.min_fee.hl()} {self.proto.coin}')
msg('Minimum fee for new transaction: {} {} ({} {})'.format(
self.min_fee.hl(),
self.proto.coin,
pink(self.fee_abs2rel(self.min_fee)),
self.rel_fee_disp))
self.usr_fee = self.get_usr_fee_interactive(fee=self.cfg.fee, desc='User-selected')

View file

@ -83,7 +83,9 @@ class New(Base):
_funds_available = namedtuple('funds_available', ['is_positive', 'amt'])
def __init__(self, *args, target=None, **kwargs):
self.is_swap = target == 'swaptx'
if target == 'swaptx':
self.is_swap = True
self.swap_proto = kwargs['cfg'].swap_proto
super().__init__(*args, **kwargs)
def warn_insufficient_funds(self, amt, coin):
@ -183,6 +185,8 @@ class New(Base):
arg, amt = arg_in.split(',', 1) if ',' in arg_in else (arg_in, None)
coin_addr, mmid = (None, None)
if mmid := get_obj(MMGenID, proto=proto, id_str=arg, silent=True):
coin_addr = mmaddr2coinaddr(self.cfg, arg, ad_w, ad_f, proto)
elif is_coin_addr(proto, arg):
@ -191,7 +195,6 @@ class New(Base):
if proto.base_proto_coin != 'BTC':
die(2, f'Change addresses not supported for {proto.name} protocol')
self.chg_autoselected = True
coin_addr = None
else:
die(2, f'{arg_in}: invalid command-line argument')
@ -219,7 +222,7 @@ class New(Base):
parsed_args = [self.parse_cmdline_arg(self.proto, arg, ad_f, ad_w) for arg in cmd_args]
chg_args = [a for a in parsed_args if not ((a.amt and a.addr) or a.data)]
chg_args = [a for a in parsed_args if not (a.amt or a.data)]
if len(chg_args) > 1:
desc = 'requested' if self.chg_autoselected else 'listed'
@ -229,13 +232,15 @@ class New(Base):
if a.data:
self.add_output(None, self.proto.coin_amt('0'), data=a.data)
else:
exclude = [a.mmid for a in parsed_args if a.mmid]
self.add_output(
coinaddr = a.addr or (
await self.get_autochg_addr(self.proto, a.arg, exclude=exclude, desc='change address')
).addr,
amt = self.proto.coin_amt(a.amt or '0'),
is_chg = not a.amt)
await self.get_autochg_addr(
self.proto,
a.arg,
exclude = [a.mmid for a in parsed_args if a.mmid],
desc = 'change address')).addr,
amt = self.proto.coin_amt(a.amt or '0'),
is_chg = not a.amt)
if self.chg_idx is None:
die(2,
@ -387,13 +392,14 @@ class New(Base):
sel_unspent,
outputs_sum):
return False
self.copy_inputs_from_tw(sel_unspent) # makes self.inputs
return True
async def get_fee(self, fee, outputs_sum):
async def get_fee(self, fee, outputs_sum, start_fee_desc):
if fee:
self.usr_fee = self.get_usr_fee_interactive(fee, 'User-selected')
self.usr_fee = self.get_usr_fee_interactive(fee, start_fee_desc)
else:
fee_per_kb, fe_type = await self.get_rel_fee_from_network()
self.usr_fee = self.get_usr_fee_interactive(
@ -468,7 +474,10 @@ class New(Base):
fee_hint = None
if self.is_swap:
fee_hint = self.update_vault_output(self.vault_output.amt or self.sum_inputs())
if funds_left := await self.get_fee(fee_hint or self.cfg.fee, outputs_sum):
if funds_left := await self.get_fee(
self.cfg.fee or fee_hint,
outputs_sum,
'User-selected' if self.cfg.fee else 'Recommended' if fee_hint else None):
break
self.check_non_mmgen_inputs(caller)

View file

@ -123,6 +123,15 @@ def exec_wrapper_tracemalloc_log():
s = sum(stat.size for stat in stats) / 1024,
w = col1w))
def exec_wrapper_do_exit(e, exit_val):
if exit_val != 0:
exec_wrapper_write_traceback(e, exit_val)
else:
if exec_wrapper_os.getenv('MMGEN_TRACEMALLOC'):
exec_wrapper_tracemalloc_log()
exec_wrapper_end_msg()
exec_wrapper_sys.exit(exit_val)
import sys as exec_wrapper_sys
import os as exec_wrapper_os
import time as exec_wrapper_time
@ -145,17 +154,10 @@ try:
with open(exec_wrapper_execed_file) as fp:
exec(fp.read())
except SystemExit as e:
if e.code != 0:
exec_wrapper_write_traceback(e, e.code)
else:
if exec_wrapper_os.getenv('MMGEN_TRACEMALLOC'):
exec_wrapper_tracemalloc_log()
exec_wrapper_end_msg()
exec_wrapper_sys.exit(e.code)
exec_wrapper_do_exit(e, e.code)
except Exception as e:
exit_val = e.mmcode if hasattr(e, 'mmcode') else e.code if hasattr(e, 'code') else 1
exec_wrapper_write_traceback(e, exit_val)
exec_wrapper_sys.exit(exit_val)
exec_wrapper_do_exit(
e, e.mmcode if hasattr(e, 'mmcode') else e.code if hasattr(e, 'code') else 1)
if exec_wrapper_os.getenv('MMGEN_TRACEMALLOC'):
exec_wrapper_tracemalloc_log()

View file

@ -447,7 +447,7 @@ class CmdGroupMgr:
yield ' {} - {}'.format(
yellow(name.ljust(13)),
(cls.__doc__.strip() if cls.__doc__ else cls.__name__))
if hasattr(cls, 'cmd_subgroups'):
if 'cmd_subgroups' in cls.__dict__:
subgroups = {k:v for k, v in cls.cmd_subgroups.items() if not k.startswith('_')}
max_w = max(len(k) for k in subgroups)
for k, v in subgroups.items():
@ -762,7 +762,8 @@ class CmdTestRunner:
if isinstance(e, KeyError) and e.args[0] == cmdname:
ret = getattr(self.tg, cmdname)()
if type(ret).__name__ == 'coroutine':
asyncio.run(ret)
ret = asyncio.run(ret)
self.process_retval(cmdname, ret)
else:
raise
do_between()

View file

@ -14,14 +14,15 @@ test.cmdtest_d.ct_automount: autosigning with automount tests for the cmdtest.py
import time
from .ct_autosign import CmdTestAutosignThreaded
from .ct_regtest import CmdTestRegtestBDBWallet, rt_pw
from .ct_regtest import CmdTestRegtest, rt_pw
from ..include.common import cfg, gr_uc
class CmdTestAutosignAutomount(CmdTestAutosignThreaded, CmdTestRegtestBDBWallet):
class CmdTestAutosignAutomount(CmdTestAutosignThreaded, CmdTestRegtest):
'automounted transacting operations via regtest mode'
networks = ('btc', 'bch', 'ltc')
tmpdir_nums = [49]
bdb_wallet = True
rt_data = {
'rtFundAmt': {'btc':'500', 'bch':'500', 'ltc':'5500'},
@ -78,7 +79,7 @@ class CmdTestAutosignAutomount(CmdTestAutosignThreaded, CmdTestRegtestBDBWallet)
self.coins = [cfg.coin.lower()]
CmdTestAutosignThreaded.__init__(self, trunner, cfgs, spawn)
CmdTestRegtestBDBWallet.__init__(self, trunner, cfgs, spawn)
CmdTestRegtest.__init__(self, trunner, cfgs, spawn)
if trunner is None:
return

View file

@ -441,19 +441,22 @@ class CmdTestAutosignThreaded(CmdTestAutosignBase):
no_insert_check = False
threaded = True
def _wait_loop_start(self):
def _wait_loop_start(self, add_opts=[]):
t = self.spawn(
'mmgen-autosign',
self.opts + ['--full-summary', 'wait'],
self.opts + add_opts + ['--full-summary', 'wait'],
direct_exec = True,
no_passthru_opts = True,
spawn_env_override = self.spawn_env | {'EXEC_WRAPPER_DO_RUNTIME_MSG': ''})
self.write_to_tmpfile('autosign_thread_pid', str(t.ep.pid))
return t
def wait_loop_start(self):
def wait_loop_start(self, add_opts=[]):
import threading
threading.Thread(target=self._wait_loop_start, name='Autosign wait loop').start()
threading.Thread(
target = self._wait_loop_start,
kwargs = {'add_opts': add_opts},
name = 'Autosign wait loop').start()
time.sleep(0.1) # try to ensure test output is displayed before next test starts
return 'silent'

View file

@ -280,8 +280,8 @@ class CmdTestRegtest(CmdTestBase, CmdTestShared):
('bob_split1', 'splitting Bob’s funds'),
('generate', 'mining a block'),
('bob_bal2', 'Bob’s balance'),
('bob_rbf_1output_create', 'creating RBF tx with one output'),
('bob_rbf_1output_bump', 'bumping RBF tx with one output'),
('bob_rbf_1output_create', 'creating RBF TX with one output'),
('bob_rbf_1output_bump', 'creating replacement TX with one output'),
('bob_bal2a', 'Bob’s balance (age_fmt=confs)'),
('bob_bal2b', 'Bob’s balance (showempty=1)'),
('bob_bal2c', 'Bob’s balance (showempty=1 minconf=2 age_fmt=days)'),
@ -1122,7 +1122,7 @@ class CmdTestRegtest(CmdTestBase, CmdTestShared):
one_output = True)
def bob_send_maybe_rbf(self):
outputs_cl = self._create_tx_outputs('alice', (('L', 1, ', 60'), ('C', 1, ', 40')))
outputs_cl = self._create_tx_outputs('alice', (('L', 1, ',60'), ('C', 1, ',40')))
outputs_cl += [self._user_sid('bob')+':'+rtBobOp3]
return self.user_txdo(
user = 'bob',
@ -2174,4 +2174,5 @@ class CmdTestRegtest(CmdTestBase, CmdTestShared):
return 'ok'
class CmdTestRegtestBDBWallet(CmdTestRegtest):
'transacting and tracking wallet operations via regtest mode (legacy BDB wallet)'
bdb_wallet = True

View file

@ -13,15 +13,8 @@ test.cmdtest_d.ct_swap: asset swap tests for the cmdtest.py test suite
"""
from mmgen.protocol import init_proto
from ..include.common import gr_uc
from .ct_regtest import (
CmdTestRegtest,
rt_data,
dfl_wcls,
rt_pw,
cfg)
from .ct_regtest import CmdTestRegtest, rt_data, dfl_wcls, rt_pw, cfg
sample1 = gr_uc[:24]
sample2 = '00010203040506'

View file

@ -217,9 +217,7 @@ do_reexec() {
install_secp256k1_mod_maybe() {
if [[ "$repo" =~ ^mmgen[-_]wallet ]]; then
[ -e mmgen/proto/secp256k1/secp256k1*$(python3 --version | sed 's/.* //;s/\.//;s/\..*//')* ] || {
eval "python3 setup.py build_ext --inplace $STDOUT_DEVNULL"
}
eval "python3 setup.py build_ext --inplace $STDOUT_DEVNULL"
fi
}