addr.py,rpc.py,tw.py,tx.py,traceback.py: minor cleanups and refactoring
This commit is contained in:
parent
854d6532dc
commit
1b54d425bd
5 changed files with 137 additions and 103 deletions
|
|
@ -545,12 +545,15 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file
|
|||
return [d.addr for d in self.data if not getattr(d,key)]
|
||||
|
||||
def generate_addrs_from_keys(self):
|
||||
kg = KeyGenerator('std')
|
||||
ag = AddrGenerator('p2pkh')
|
||||
# assume that the first listed mmtype is valid for flat key list
|
||||
t = MMGenAddrType(g.proto.mmtypes[0])
|
||||
kg = KeyGenerator(t.pubkey_type)
|
||||
ag = AddrGenerator(t.gen_method)
|
||||
d = self.data
|
||||
for n,e in enumerate(d,1):
|
||||
qmsg_r('\rGenerating addresses from keylist: {}/{}'.format(n,len(d)))
|
||||
e.addr = ag.to_addr(kg.to_pubhex(e.sec))
|
||||
if g.debug_addrlist: Msg('generate_addrs_from_keys():\n{}'.format(e.pformat()))
|
||||
qmsg('\rGenerated addresses from keylist: {}/{} '.format(n,len(d)))
|
||||
|
||||
def format(self,enable_comments=False):
|
||||
|
|
|
|||
|
|
@ -213,7 +213,6 @@ class EthereumRPCConnection(CoinDaemonRPCConnection):
|
|||
'eth_blockNumber',
|
||||
'eth_gasPrice',
|
||||
'eth_getBalance',
|
||||
'eth_getBlock',
|
||||
'eth_getBlockByHash',
|
||||
'eth_getBlockByNumber',
|
||||
'eth_getTransactionByHash',
|
||||
|
|
@ -225,7 +224,11 @@ class EthereumRPCConnection(CoinDaemonRPCConnection):
|
|||
'net_peerCount',
|
||||
'net_version',
|
||||
'parity_chain',
|
||||
# Returns the EIP155 chain ID used for transaction signing at the current best block.
|
||||
# Null is returned if not available.
|
||||
'parity_chainId',
|
||||
'parity_chainStatus',
|
||||
'parity_composeTransaction',
|
||||
'parity_gasCeilTarget',
|
||||
'parity_gasFloorTarget',
|
||||
'parity_localTransactions',
|
||||
|
|
|
|||
76
mmgen/tw.py
76
mmgen/tw.py
|
|
@ -29,8 +29,9 @@ CUR_HOME,ERASE_ALL = '\033[H','\033[0J'
|
|||
class TwUnspentOutputs(MMGenObject):
|
||||
|
||||
txid_w = 64
|
||||
show_tx = True
|
||||
show_txid = True
|
||||
can_group = True
|
||||
hdr_fmt = 'UNSPENT OUTPUTS (sort order: {}) Total {}: {}'
|
||||
prompt = """
|
||||
Sort options: [t]xid, [a]mount, a[d]dress, [A]ge, [r]everse, [M]mgen addr
|
||||
Display options: show [D]ays, [g]roup, show [m]mgen addr, r[e]draw screen
|
||||
|
|
@ -175,21 +176,19 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
|
|||
if self.sort_key == k and getattr(a,k) == getattr(b,k):
|
||||
b.skip = (k,'addr')[k=='twmmid']
|
||||
|
||||
hdr_fmt = 'UNSPENT OUTPUTS (sort order: {}) Total {}: {}'
|
||||
out = [hdr_fmt.format(' '.join(self.sort_info()),g.coin,self.total.hl())]
|
||||
out = [self.hdr_fmt.format(' '.join(self.sort_info()),g.coin,self.total.hl())]
|
||||
if g.chain in ('testnet','regtest'):
|
||||
out += [green('Chain: {}'.format(g.chain.upper()))]
|
||||
if self.show_tx:
|
||||
if self.show_txid:
|
||||
fs = u' {n:%s} {t:%s} {v:2} {a} {A} {c:<}' % (col1_w,tx_w)
|
||||
else:
|
||||
fs = u' {n:%s} {a} {A} {c:<}' % col1_w
|
||||
out += [fs.format(
|
||||
n='Num',
|
||||
t='TXid'.ljust(tx_w - 5) + ' Vout',
|
||||
v='',
|
||||
a='Address'.ljust(addr_w),
|
||||
A='Amt({})'.format(g.coin).ljust(g.proto.coin_amt.max_prec+4),
|
||||
c=('Confs','Age(d)')[self.show_days])]
|
||||
out += [fs.format( n='Num',
|
||||
t='TXid'.ljust(tx_w - 5) + ' Vout',
|
||||
v='',
|
||||
a='Address'.ljust(addr_w),
|
||||
A='Amt({})'.format(g.coin).ljust(g.proto.coin_amt.max_prec+4),
|
||||
c=('Confs','Age(d)')[self.show_days])]
|
||||
|
||||
for n,i in enumerate(unsp):
|
||||
addr_dots = '|' + '.'*(addr_w-1)
|
||||
|
|
@ -209,13 +208,12 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
|
|||
tx = ' ' * (tx_w-4) + '|...' if i.skip == 'txid' \
|
||||
else i.txid[:tx_w-len(txdots)]+txdots
|
||||
|
||||
out.append(fs.format(
|
||||
n=str(n+1)+')',
|
||||
t=tx,
|
||||
v=i.vout,
|
||||
a=addr_out,
|
||||
A=i.amt.fmt(color=True),
|
||||
c=i.days if self.show_days else i.confs))
|
||||
out.append(fs.format( n=str(n+1)+')',
|
||||
t=tx,
|
||||
v=i.vout,
|
||||
a=addr_out,
|
||||
A=i.amt.fmt(color=True),
|
||||
c=i.days if self.show_days else i.confs))
|
||||
|
||||
self.fmt_display = '\n'.join(out) + '\n'
|
||||
# unsp.pdie()
|
||||
|
|
@ -225,36 +223,34 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
|
|||
|
||||
addr_w = max(len(i.addr) for i in self.unspent)
|
||||
mmid_w = max(len(('',i.twmmid)[i.twmmid.type=='mmgen']) for i in self.unspent) or 12 # DEADBEEF:S:1
|
||||
if self.show_tx:
|
||||
if self.show_txid:
|
||||
fs = ' {n:4} {t:%s} {a} {m} {A:%s} {c:<8} {g:<6} {l}' % (self.txid_w+3,g.proto.coin_amt.max_prec+4)
|
||||
else:
|
||||
fs = ' {n:4} {a} {m} {A:%s} {c:<8} {g:<6} {l}' % (g.proto.coin_amt.max_prec+4)
|
||||
out = [fs.format(
|
||||
n='Num',
|
||||
t='Tx ID,Vout',
|
||||
a='Address'.ljust(addr_w),
|
||||
m='MMGen ID'.ljust(mmid_w+1),
|
||||
A='Amount({})'.format(g.coin),
|
||||
c='Confs',
|
||||
g='Age(d)',
|
||||
l='Label')]
|
||||
out = [fs.format( n='Num',
|
||||
t='Tx ID,Vout',
|
||||
a='Address'.ljust(addr_w),
|
||||
m='MMGen ID'.ljust(mmid_w+1),
|
||||
A='Amount({})'.format(g.coin),
|
||||
c='Confs',
|
||||
g='Age(d)',
|
||||
l='Label')]
|
||||
|
||||
max_lbl_len = max([len(i.label) for i in self.unspent if i.label] or [1])
|
||||
for n,i in enumerate(self.unspent):
|
||||
addr = '|'+'.' * addr_w if i.skip == 'addr' and self.group else i.addr.fmt(color=color,width=addr_w)
|
||||
tx = '|'+'.' * 63 if i.skip == 'txid' and self.group else str(i.txid)
|
||||
out.append(
|
||||
fs.format(
|
||||
n=str(n+1)+')',
|
||||
t=tx+','+str(i.vout),
|
||||
a=addr,
|
||||
m=MMGenID.fmtc(i.twmmid if i.twmmid.type=='mmgen'
|
||||
else 'Non-{}'.format(g.proj_name),width=mmid_w,color=color),
|
||||
A=i.amt.fmt(color=color),
|
||||
c=i.confs,
|
||||
g=i.days,
|
||||
l=i.label.hl(color=color) if i.label else
|
||||
TwComment.fmtc('',color=color,nullrepl='-',width=max_lbl_len)).rstrip())
|
||||
out.append(fs.format(
|
||||
n=str(n+1)+')',
|
||||
t=tx+','+str(i.vout),
|
||||
a=addr,
|
||||
m=MMGenID.fmtc(i.twmmid if i.twmmid.type=='mmgen'
|
||||
else 'Non-{}'.format(g.proj_name),width=mmid_w,color=color),
|
||||
A=i.amt.fmt(color=color),
|
||||
c=i.confs,
|
||||
g=i.days,
|
||||
l=i.label.hl(color=color) if i.label else
|
||||
TwComment.fmtc('',color=color,nullrepl='-',width=max_lbl_len)).rstrip())
|
||||
|
||||
fs = 'Unspent outputs ({} UTC)\nSort order: {}\n{}\n\nTotal {}: {}\n'
|
||||
self.fmt_print = fs.format(
|
||||
|
|
|
|||
129
mmgen/tx.py
129
mmgen/tx.py
|
|
@ -80,16 +80,6 @@ def strfmt_locktime(num,terse=False):
|
|||
else:
|
||||
die(2,"'{}': invalid locktime value!".format(num))
|
||||
|
||||
def select_unspent(unspent,prompt):
|
||||
while True:
|
||||
reply = my_raw_input(prompt).strip()
|
||||
if reply:
|
||||
selected = AddrIdxList(fmt_str=','.join(reply.split()),on_fail='return')
|
||||
if selected:
|
||||
if selected[-1] <= len(unspent):
|
||||
return selected
|
||||
msg('Unspent output number must be <= {}'.format(len(unspent)))
|
||||
|
||||
def mmaddr2coinaddr(mmaddr,ad_w,ad_f):
|
||||
|
||||
# assume mmaddr has already been checked
|
||||
|
|
@ -234,6 +224,8 @@ class MMGenTX(MMGenObject):
|
|||
sig_ext = 'sigtx'
|
||||
txid_ext = 'txid'
|
||||
desc = 'transaction'
|
||||
chg_fs = 'Transaction produces {} {} in change'
|
||||
no_chg_msg = 'Warning: Change address will be deleted as transaction produces no change'
|
||||
|
||||
class MMGenTxInput(MMGenListItem):
|
||||
for k in txio_attrs: locals()[k] = txio_attrs[k] # in lieu of inheritance
|
||||
|
|
@ -275,6 +267,7 @@ class MMGenTX(MMGenObject):
|
|||
self.inputs = self.MMGenTxInputList()
|
||||
self.outputs = self.MMGenTxOutputList()
|
||||
self.send_amt = g.proto.coin_amt('0') # total amt minus change
|
||||
self.fee = g.proto.coin_amt('0')
|
||||
self.hex = '' # raw serialized hex transaction
|
||||
self.label = MMGenTXLabel('')
|
||||
self.txid = ''
|
||||
|
|
@ -295,11 +288,15 @@ class MMGenTX(MMGenObject):
|
|||
self.check_sigs() # marks the tx as signed
|
||||
|
||||
# repeat with sign and send, because coin daemon could be restarted
|
||||
self.die_if_incorrect_chain()
|
||||
self.check_correct_chain(on_fail='die')
|
||||
|
||||
def die_if_incorrect_chain(self):
|
||||
if self.chain and g.chain and self.chain != g.chain:
|
||||
die(2,'Transaction is for {}, but current chain is {}!'.format(self.chain,g.chain))
|
||||
def check_correct_chain(self,on_fail='return'):
|
||||
assert on_fail in ('return','die'),"'{}': invalid value for 'on_fail'".format(on_fail)
|
||||
m = 'Transaction is for {}, but current chain is {}!'.format(self.chain,g.chain)
|
||||
bad = self.chain and g.chain and self.chain != g.chain
|
||||
if bad:
|
||||
msg(m) if on_fail == 'return' else die(2,m)
|
||||
return not bad
|
||||
|
||||
def add_output(self,coinaddr,amt,is_chg=None):
|
||||
self.outputs.append(MMGenTX.MMGenTxOutput(addr=coinaddr,amt=amt,is_chg=is_chg))
|
||||
|
|
@ -564,8 +561,11 @@ class MMGenTX(MMGenObject):
|
|||
assert type(val) == int,'locktime value not an integer'
|
||||
self.hex = self.hex[:-8] + hexlify(unhexlify('{:08x}'.format(val))[::-1])
|
||||
|
||||
def get_blockcount(self):
|
||||
return int(g.rpch.getblockcount())
|
||||
|
||||
def add_blockcount(self):
|
||||
self.blockcount = int(g.rpch.getblockcount())
|
||||
self.blockcount = self.get_blockcount()
|
||||
|
||||
def format(self):
|
||||
self.inputs.check_coin_mismatch()
|
||||
|
|
@ -604,12 +604,15 @@ class MMGenTX(MMGenObject):
|
|||
def sign(self,tx_num_str,keys):
|
||||
|
||||
if self.marked_signed():
|
||||
die(1,'Transaction is already signed!')
|
||||
msg('Transaction is already signed!')
|
||||
return False
|
||||
|
||||
self.die_if_incorrect_chain()
|
||||
if not self.check_correct_chain(on_fail='return'):
|
||||
return False
|
||||
|
||||
if (self.has_segwit_inputs() or self.has_segwit_outputs()) and not g.proto.cap('segwit'):
|
||||
die(2,yellow("TX has Segwit inputs or outputs, but {} doesn't support Segwit!".format(g.coin)))
|
||||
ymsg("TX has Segwit inputs or outputs, but {} doesn't support Segwit!".format(g.coin))
|
||||
return False
|
||||
|
||||
qmsg('Passing {} key{} to {}'.format(len(keys),suf(keys,'s'),g.proto.daemon_name))
|
||||
|
||||
|
|
@ -793,7 +796,7 @@ class MMGenTX(MMGenObject):
|
|||
if not self.marked_signed():
|
||||
die(1,'Transaction is not signed!')
|
||||
|
||||
self.die_if_incorrect_chain()
|
||||
self.check_correct_chain(on_fail='die')
|
||||
|
||||
self.check_hex_tx_matches_mmgen_tx(DeserializedTX(self.hex))
|
||||
|
||||
|
|
@ -908,7 +911,7 @@ class MMGenTX(MMGenObject):
|
|||
def format_view(self,terse=False):
|
||||
try:
|
||||
rpc_init()
|
||||
blockcount = g.rpch.getblockcount()
|
||||
blockcount = self.get_blockcount()
|
||||
except:
|
||||
blockcount = None
|
||||
|
||||
|
|
@ -928,7 +931,7 @@ class MMGenTX(MMGenObject):
|
|||
addr_w = max(len(e.addr) for e in io)
|
||||
confs_per_day = 60*60*24 / g.proto.secs_per_block
|
||||
for n,e in enumerate(sorted(io,key=lambda o: o.mmid.sort_key if o.mmid else o.addr)):
|
||||
if ip and blockcount != None:
|
||||
if ip and blockcount:
|
||||
confs = e.confs + blockcount - self.blockcount
|
||||
days = int(confs / confs_per_day)
|
||||
if e.mmid:
|
||||
|
|
@ -950,7 +953,7 @@ class MMGenTX(MMGenObject):
|
|||
('','comment:',e.label.hl() if e.label else ''),
|
||||
('','amount:','{} {}'.format(e.amt.hl(),g.coin))]
|
||||
items = [(n+1, 'tx,vout:','{},{}'.format(e.txid,e.vout))] + icommon + [
|
||||
('','confirmations:','{} (around {} days)'.format(confs,days) if blockcount!=None else '')
|
||||
('','confirmations:','{} (around {} days)'.format(confs,days) if blockcount else '')
|
||||
] if ip else icommon + [
|
||||
('','change:',green('True') if e.is_chg else '')]
|
||||
io_out += '\n'.join([(u'{:>3} {:<8} {}'.format(*d)) for d in items if d[2]]) + '\n\n'
|
||||
|
|
@ -964,8 +967,7 @@ class MMGenTX(MMGenObject):
|
|||
self.send_amt.hl(),
|
||||
g.coin,
|
||||
self.timestamp,
|
||||
(red('False'),
|
||||
green('True'))[self.is_rbf()],
|
||||
(red('False'),green('True'))[self.is_rbf()],
|
||||
self.marked_signed(color=True),
|
||||
(green('None'),orange(strfmt_locktime(self.locktime,terse=True)))[bool(self.locktime)])
|
||||
if self.chain in ('testnet','regtest'):
|
||||
|
|
@ -998,6 +1000,9 @@ class MMGenTX(MMGenObject):
|
|||
|
||||
return out # TX label might contain non-ascii chars
|
||||
|
||||
def check_tx_hex_data(self):
|
||||
self.hex = HexStr(self.hex,on_fail='raise')
|
||||
|
||||
def parse_tx_file(self,infile,md_only=False,silent_open=False):
|
||||
|
||||
def eval_io_data(raw_data,desc):
|
||||
|
|
@ -1069,7 +1074,7 @@ class MMGenTX(MMGenObject):
|
|||
desc = 'block count in metadata'
|
||||
self.blockcount = int(blockcount)
|
||||
desc = 'transaction hex data'
|
||||
self.hex = HexStr(self.hex,on_fail='raise')
|
||||
self.check_tx_hex_data()
|
||||
if md_only: return # the following ops will all fail if g.coin doesn't match self.coin
|
||||
desc = 'coin type in metadata'
|
||||
assert self.coin == g.coin,'invalid coin type'
|
||||
|
|
@ -1093,38 +1098,27 @@ class MMGenTX(MMGenObject):
|
|||
try:
|
||||
ret = g.rpch.estimatesmartfee(opt.tx_confs,on_fail='raise')
|
||||
except:
|
||||
fetype = 'estimatefee'
|
||||
fe_type = 'estimatefee'
|
||||
fee_per_kb = g.rpch.estimatefee(opt.tx_confs)
|
||||
else:
|
||||
fetype = 'estimatesmartfee'
|
||||
fe_type = 'estimatesmartfee'
|
||||
fee_per_kb = ret['feerate'] if 'feerate' in ret else -2
|
||||
|
||||
if fee_per_kb < 0:
|
||||
if not have_estimate_fail:
|
||||
msg('Network fee estimation for {} confirmations failed ({})'.format(opt.tx_confs,fetype))
|
||||
msg('Network fee estimation for {} confirmations failed ({})'.format(opt.tx_confs,fe_type))
|
||||
have_estimate_fail.append(True)
|
||||
start_fee = None
|
||||
else:
|
||||
start_fee = g.proto.coin_amt(fee_per_kb) * opt.tx_fee_adj * self.estimate_size() / 1024
|
||||
if opt.verbose:
|
||||
msg('{} fee for {} confirmations: {} {}/kB'.format(
|
||||
fetype.upper(),opt.tx_confs,fee_per_kb,g.coin))
|
||||
fe_type.upper(),opt.tx_confs,fee_per_kb,g.coin))
|
||||
msg('TX size (estimated): {}'.format(self.estimate_size()))
|
||||
|
||||
return self.get_usr_fee_interactive(start_fee,desc=desc)
|
||||
|
||||
def get_outputs_from_cmdline(self,cmd_args):
|
||||
from mmgen.addr import AddrList,AddrData
|
||||
addrfiles = [a for a in cmd_args if get_extension(a) == AddrList.ext]
|
||||
cmd_args = set(cmd_args) - set(addrfiles)
|
||||
|
||||
ad_f = AddrData()
|
||||
for a in addrfiles:
|
||||
check_infile(a)
|
||||
ad_f.add(AddrList(a))
|
||||
|
||||
ad_w = AddrData(source='tw')
|
||||
|
||||
def process_cmd_args(self,cmd_args,ad_f,ad_w):
|
||||
for a in cmd_args:
|
||||
if ',' in a:
|
||||
a1,a2 = a.split(',',1)
|
||||
|
|
@ -1141,24 +1135,48 @@ class MMGenTX(MMGenObject):
|
|||
else:
|
||||
die(2,'{}: invalid command-line argument'.format(a))
|
||||
|
||||
if not self.outputs:
|
||||
die(2,'At least one output must be specified on the command line')
|
||||
|
||||
if self.get_chg_output_idx() == None:
|
||||
die(2,('ERROR: No change output specified',wmsg['no_change_output'])[len(self.outputs) == 1])
|
||||
|
||||
self.add_mmaddrs_to_outputs(ad_w,ad_f)
|
||||
self.check_dup_addrs('outputs')
|
||||
|
||||
if not segwit_is_active() and self.has_segwit_outputs():
|
||||
fs = '{} Segwit address requested on the command line, but Segwit is not active on this chain'
|
||||
rdie(2,fs.format(g.proj_name))
|
||||
|
||||
def get_outputs_from_cmdline(self,cmd_args):
|
||||
from mmgen.addr import AddrList,AddrData
|
||||
addrfiles = [a for a in cmd_args if get_extension(a) == AddrList.ext]
|
||||
cmd_args = set(cmd_args) - set(addrfiles)
|
||||
|
||||
ad_f = AddrData()
|
||||
for a in addrfiles:
|
||||
check_infile(a)
|
||||
ad_f.add(AddrList(a))
|
||||
|
||||
ad_w = AddrData(source='tw')
|
||||
|
||||
self.process_cmd_args(cmd_args,ad_f,ad_w)
|
||||
|
||||
if not self.outputs:
|
||||
die(2,'At least one output must be specified on the command line')
|
||||
|
||||
self.add_mmaddrs_to_outputs(ad_w,ad_f)
|
||||
self.check_dup_addrs('outputs')
|
||||
|
||||
def select_unspent(self,unspent):
|
||||
prompt = 'Enter a range or space-separated list of outputs to spend: '
|
||||
while True:
|
||||
reply = my_raw_input(prompt).strip()
|
||||
if reply:
|
||||
selected = AddrIdxList(fmt_str=','.join(reply.split()),on_fail='return')
|
||||
if selected:
|
||||
if selected[-1] <= len(unspent):
|
||||
return selected
|
||||
msg('Unspent output number must be <= {}'.format(len(unspent)))
|
||||
|
||||
def get_inputs_from_user(self,tw):
|
||||
|
||||
while True:
|
||||
m = 'Enter a range or space-separated list of outputs to spend: '
|
||||
sel_nums = select_unspent(tw.unspent,m)
|
||||
sel_nums = self.select_unspent(tw.unspent)
|
||||
msg('Selected output{}: {}'.format(suf(sel_nums,'s'),' '.join(map(str,sel_nums))))
|
||||
|
||||
sel_unspent = tw.MMGenTwOutputList([tw.unspent[i-1] for i in sel_nums])
|
||||
|
|
@ -1176,16 +1194,21 @@ class MMGenTX(MMGenObject):
|
|||
|
||||
self.copy_inputs_from_tw(sel_unspent) # makes self.inputs
|
||||
|
||||
change_amt = self.sum_inputs() - self.send_amt - self.get_fee_from_user()
|
||||
self.fee = self.get_fee_from_user()
|
||||
|
||||
change_amt = self.sum_inputs() - self.send_amt - self.fee
|
||||
|
||||
if change_amt >= 0:
|
||||
p = 'Transaction produces {} {} in change'.format(change_amt.hl(),g.coin)
|
||||
p = self.chg_fs.format(change_amt.hl(),g.coin)
|
||||
if opt.yes or keypress_confirm(p+'. OK?',default_yes=True):
|
||||
if opt.yes: msg(p)
|
||||
return change_amt
|
||||
else:
|
||||
msg(wmsg['not_enough_coin'].format(abs(change_amt)))
|
||||
|
||||
def check_fee(self):
|
||||
assert self.sum_inputs() - self.sum_outputs() <= g.proto.max_tx_fee
|
||||
|
||||
def create(self,cmd_args,locktime,do_info=False):
|
||||
assert type(locktime) == int
|
||||
|
||||
|
|
@ -1217,7 +1240,7 @@ class MMGenTX(MMGenObject):
|
|||
chg_idx = self.get_chg_output_idx()
|
||||
|
||||
if change_amt == 0:
|
||||
msg('Warning: Change address will be deleted as transaction produces no change')
|
||||
msg(self.no_chg_msg)
|
||||
self.del_output(chg_idx)
|
||||
else:
|
||||
self.update_output_amt(chg_idx,g.proto.coin_amt(change_amt))
|
||||
|
|
@ -1239,7 +1262,7 @@ class MMGenTX(MMGenObject):
|
|||
self.add_blockcount()
|
||||
self.chain = g.chain
|
||||
|
||||
assert self.sum_inputs() - self.sum_outputs() <= g.proto.max_tx_fee
|
||||
self.check_fee()
|
||||
|
||||
qmsg('Transaction successfully created')
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,18 @@ if 'TMUX' in os.environ: del os.environ['TMUX']
|
|||
os.environ['MMGEN_TRACEBACK'] = '1'
|
||||
|
||||
tb_source = open(sys.argv[1])
|
||||
tb_file = open('my.err','w')
|
||||
tb_file = os.path.join(os.environ['PWD'],'my.err')
|
||||
|
||||
def process_exception(es):
|
||||
l = traceback.format_exception(*es)
|
||||
l_save = l[:]
|
||||
exc = l.pop()
|
||||
if exc[:11] == 'SystemExit:': l.pop()
|
||||
def red(s): return '{e}[31;1m{}{e}[0m'.format(s,e='\033')
|
||||
def yellow(s): return '{e}[33;1m{}{e}[0m'.format(s,e='\033')
|
||||
sys.stdout.write('{}{}'.format(yellow(''.join(l)),red(exc)))
|
||||
with open(tb_file,'w') as f:
|
||||
f.write(''.join(l_save))
|
||||
|
||||
try:
|
||||
sys.argv.pop(0)
|
||||
|
|
@ -14,12 +25,10 @@ try:
|
|||
except SystemExit:
|
||||
# pass
|
||||
e = sys.exc_info()
|
||||
if int(str(e[1])) != 0:
|
||||
process_exception(e)
|
||||
sys.exit(int(str(e[1])))
|
||||
except:
|
||||
l = traceback.format_exception(*sys.exc_info())
|
||||
exc = l.pop()
|
||||
def red(s): return '{e}[31;1m{}{e}[0m'.format(s,e='\033')
|
||||
def yellow(s): return '{e}[33;1m{}{e}[0m'.format(s,e='\033')
|
||||
sys.stdout.write('{}{}'.format(yellow(''.join(l)),red(exc)))
|
||||
traceback.print_exc(file=tb_file)
|
||||
e = sys.exc_info()
|
||||
process_exception(e)
|
||||
sys.exit(1)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue