tx.new + subclasses: method & import renames, refactor, cleanups
This commit is contained in:
parent
dc30edba48
commit
8b6c24cc07
4 changed files with 41 additions and 40 deletions
|
|
@ -15,7 +15,7 @@ proto.btc.tx.base: Bitcoin base transaction class
|
|||
from collections import namedtuple
|
||||
|
||||
from ....addr import CoinAddr
|
||||
from ....tx import base as TxBase
|
||||
from ....tx.base import Base as TxBase
|
||||
from ....obj import MMGenList, HexStr, ListItemAttr
|
||||
from ....util import msg, make_chksum_6, die, pp_fmt
|
||||
|
||||
|
|
@ -169,16 +169,16 @@ def DeserializeTX(proto, txhex):
|
|||
|
||||
return namedtuple('deserialized_tx', list(d.keys()))(**d)
|
||||
|
||||
class Base(TxBase.Base):
|
||||
class Base(TxBase):
|
||||
rel_fee_desc = 'satoshis per byte'
|
||||
rel_fee_disp = 'sat/byte'
|
||||
_deserialized = None
|
||||
|
||||
class Output(TxBase.Base.Output): # output contains either addr or data, but not both
|
||||
class Output(TxBase.Output): # output contains either addr or data, but not both
|
||||
addr = ListItemAttr(CoinAddr, include_proto=True) # ImmutableAttr in parent cls
|
||||
data = ListItemAttr(OpReturnData, include_proto=True) # type None in parent cls
|
||||
|
||||
class InputList(TxBase.Base.InputList):
|
||||
class InputList(TxBase.InputList):
|
||||
|
||||
# Lexicographical Indexing of Transaction Inputs and Outputs
|
||||
# https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki
|
||||
|
|
@ -189,7 +189,7 @@ class Base(TxBase.Base):
|
|||
+ int.to_bytes(a.vout, 4, 'big'))
|
||||
self.sort(key=sort_func)
|
||||
|
||||
class OutputList(TxBase.Base.OutputList):
|
||||
class OutputList(TxBase.OutputList):
|
||||
|
||||
def sort_bip69(self):
|
||||
def sort_func(a):
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@
|
|||
proto.btc.tx.new: Bitcoin new transaction class
|
||||
"""
|
||||
|
||||
from ....tx import new as TxBase
|
||||
from ....tx.new import New as TxNew
|
||||
from ....obj import MMGenTxID
|
||||
from ....util import msg, fmt, make_chksum_6, die, suf
|
||||
from ....color import pink
|
||||
from .base import Base
|
||||
|
||||
class New(Base, TxBase.New):
|
||||
class New(Base, TxNew):
|
||||
usr_fee_prompt = 'Enter transaction fee: '
|
||||
fee_fail_fs = 'Network fee estimation for {c} confirmations failed ({t})'
|
||||
no_chg_msg = 'Warning: Change address will be deleted as transaction produces no change'
|
||||
|
|
@ -105,7 +105,7 @@ class New(Base, TxBase.New):
|
|||
msg(err)
|
||||
return False
|
||||
|
||||
async def get_input_addrs_from_cmdline(self):
|
||||
async def get_input_addrs_from_inputs_opt(self):
|
||||
# Bitcoin full node, call doesn't go to the network, so just call listunspent with addrs=[]
|
||||
return []
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ class New(Base, TxBase.New):
|
|||
amt = self.proto.coin_amt(arg.amt or '0'),
|
||||
is_chg = not arg.amt)
|
||||
|
||||
def select_unspent(self, unspent):
|
||||
def get_unspent_nums_from_user(self, unspent):
|
||||
from ....ui import line_input
|
||||
while True:
|
||||
reply = line_input(self.cfg, 'Enter an account to spend from: ').strip()
|
||||
|
|
@ -152,7 +152,7 @@ class New(Base, TxBase.New):
|
|||
if self.outputs and self.outputs[0].is_chg:
|
||||
self.update_output_amt(0, funds_left)
|
||||
|
||||
async def get_input_addrs_from_cmdline(self):
|
||||
async def get_input_addrs_from_inputs_opt(self):
|
||||
ret = []
|
||||
if self.cfg.inputs:
|
||||
data_root = (await TwCtl(self.cfg, self.proto)).data_root # must create new instance here
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ class New(Base):
|
|||
o['amt'] = amt
|
||||
self.outputs[idx] = self.Output(self.proto, **o)
|
||||
|
||||
def add_mmaddrs_to_outputs(self, ad_w, ad_f):
|
||||
def add_mmaddrs_to_outputs(self, ad_f, ad_w):
|
||||
a = [e.addr for e in self.outputs]
|
||||
d = ad_w.make_reverse_dict(a)
|
||||
if ad_f:
|
||||
|
|
@ -243,8 +243,17 @@ class New(Base):
|
|||
if not self.outputs:
|
||||
die(2, 'At least one output must be specified on the command line')
|
||||
|
||||
async def get_outputs_from_cmdline(self, cmd_args):
|
||||
from ..addrdata import AddrData, TwAddrData
|
||||
self.add_mmaddrs_to_outputs(ad_f, ad_w)
|
||||
self.check_dup_addrs('outputs')
|
||||
|
||||
if self.chg_output is not None:
|
||||
if self.chg_autoselected:
|
||||
self.confirm_autoselected_addr(self.chg_output)
|
||||
elif len(self.outputs) > 1:
|
||||
await self.warn_chg_addr_used(self.chg_output)
|
||||
|
||||
def get_addrdata_from_files(self, cmd_args):
|
||||
from ..addrdata import AddrData
|
||||
from ..addrlist import AddrList
|
||||
from ..addrfile import AddrFile
|
||||
addrfiles = remove_dups(
|
||||
|
|
@ -257,25 +266,12 @@ class New(Base):
|
|||
desc = 'command line',
|
||||
edesc = 'argument',
|
||||
)
|
||||
|
||||
ad_f = AddrData(self.proto)
|
||||
from ..fileutil import check_infile
|
||||
for addrfile in addrfiles:
|
||||
check_infile(addrfile)
|
||||
ad_f.add(AddrList(self.cfg, self.proto, addrfile))
|
||||
|
||||
ad_w = await TwAddrData(self.cfg, self.proto, twctl=self.twctl)
|
||||
|
||||
await self.process_cmd_args(cmd_args, ad_f, ad_w)
|
||||
|
||||
self.add_mmaddrs_to_outputs(ad_w, ad_f)
|
||||
self.check_dup_addrs('outputs')
|
||||
|
||||
if self.chg_output is not None:
|
||||
if self.chg_autoselected:
|
||||
self.confirm_autoselected_addr(self.chg_output)
|
||||
elif len(self.outputs) > 1:
|
||||
await self.warn_chg_addr_used(self.chg_output)
|
||||
return ad_f, cmd_args
|
||||
|
||||
def confirm_autoselected_addr(self, chg):
|
||||
from ..ui import keypress_confirm
|
||||
|
|
@ -304,7 +300,7 @@ class New(Base):
|
|||
die(1, 'Exiting at user request')
|
||||
|
||||
# inputs methods
|
||||
def select_unspent(self, unspent):
|
||||
def get_unspent_nums_from_user(self, unspent):
|
||||
prompt = 'Enter a range or space-separated list of outputs to spend: '
|
||||
from ..ui import line_input
|
||||
while True:
|
||||
|
|
@ -317,13 +313,12 @@ class New(Base):
|
|||
return selected
|
||||
msg(f'Unspent output number must be <= {len(unspent)}')
|
||||
|
||||
def select_unspent_cmdline(self, unspent):
|
||||
def get_unspent_nums_from_inputs_opt(self, unspent):
|
||||
|
||||
def idx2num(idx):
|
||||
def do_add_msg(idx):
|
||||
uo = unspent[idx]
|
||||
mmid_disp = f' ({uo.twmmid})' if uo.twmmid.type == 'mmgen' else ''
|
||||
msg(f'Adding input: {idx + 1} {uo.addr}{mmid_disp}')
|
||||
return idx + 1
|
||||
mm_disp = f' ({uo.twmmid})' if uo.twmmid.type == 'mmgen' else ''
|
||||
msg('Adding input: {} {}{}'.format(idx + 1, uo.addr, mm_disp))
|
||||
|
||||
def get_uo_nums():
|
||||
for addr in self.cfg.inputs.split(','):
|
||||
|
|
@ -335,9 +330,10 @@ class New(Base):
|
|||
die(1, f'{addr!r}: not an MMGen ID or {self.coin} address')
|
||||
|
||||
found = False
|
||||
for idx, us in enumerate(unspent):
|
||||
if getattr(us, attr) == addr:
|
||||
yield idx2num(idx)
|
||||
for idx, e in enumerate(unspent):
|
||||
if getattr(e, attr) == addr:
|
||||
do_add_msg(idx)
|
||||
yield idx + 1
|
||||
found = True
|
||||
|
||||
if not found:
|
||||
|
|
@ -364,8 +360,10 @@ class New(Base):
|
|||
async def get_inputs_from_user(self, outputs_sum):
|
||||
|
||||
while True:
|
||||
us_f = self.select_unspent_cmdline if self.cfg.inputs else self.select_unspent
|
||||
sel_nums = us_f(self.twuo.data)
|
||||
sel_nums = (
|
||||
self.get_unspent_nums_from_inputs_opt if self.cfg.inputs else
|
||||
self.get_unspent_nums_from_user
|
||||
)(self.twuo.data)
|
||||
|
||||
msg(f'Selected output{suf(sel_nums)}: {{}}'.format(' '.join(str(n) for n in sel_nums)))
|
||||
sel_unspent = MMGenList(self.twuo.data[i-1] for i in sel_nums)
|
||||
|
|
@ -405,13 +403,16 @@ class New(Base):
|
|||
if self.cfg.comment_file:
|
||||
self.add_comment(self.cfg.comment_file)
|
||||
|
||||
twuo_addrs = await self.get_input_addrs_from_cmdline()
|
||||
twuo_addrs = await self.get_input_addrs_from_inputs_opt()
|
||||
|
||||
self.twuo = await TwUnspentOutputs(self.cfg, self.proto, minconf=self.cfg.minconf, addrs=twuo_addrs)
|
||||
await self.twuo.get_data()
|
||||
|
||||
if not do_info:
|
||||
await self.get_outputs_from_cmdline(cmd_args)
|
||||
ad_f, cmd_args = self.get_addrdata_from_files(cmd_args) # pops from end of cmd_args
|
||||
from ..addrdata import TwAddrData
|
||||
ad_w = await TwAddrData(self.cfg, self.proto, twctl=self.twctl)
|
||||
await self.process_cmd_args(cmd_args, ad_f, ad_w)
|
||||
|
||||
from ..ui import do_license_msg
|
||||
do_license_msg(self.cfg)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue