Replace --aug1hf with --coin=bch, display 'BCH' for BCH amounts
* Deprecate the --aug1hf option
* Use --coin=bch option to select BCH chain; works with all MMGen commands
* All BCH amounts now correctly display with 'BCH' instead of 'BTC'
* use non-standard RPC ports (8442,18442) for BCH mainnet/testnet to allow
dual-node operation. Use 'mmlive-node-start' and '-stop' scripts
(home.mmgen/bin/mmlive-node-{start,stop} in the MMGenLive repo)
to start daemons with correct RPC ports; the --coin option automatically
configures the correct ports for all MMGen scripts.
* mmgen-txsend: new --status option checks confirmation/mempool status of TXs
This commit is contained in:
parent
057fe22f0c
commit
2873897f68
15 changed files with 186 additions and 128 deletions
|
|
@ -49,6 +49,10 @@ class g(object):
|
|||
Cdates = '2013-2017'
|
||||
keywords = 'Bitcoin, cryptocurrency, wallet, cold storage, offline, online, spending, open-source, command-line, Python, Bitcoin Core, bitcoind, hd, deterministic, hierarchical, secure, anonymous, Electrum, seed, mnemonic, brainwallet, Scrypt, utility, script, scriptable, blockchain, raw, transaction, permissionless, console, terminal, curses, ansi, color, tmux, remote, client, daemon, RPC, json, entropy, xterm, rxvt, PowerShell, MSYS, MinGW, mswin'
|
||||
|
||||
coin = 'BTC'
|
||||
coins = 'BTC','BCH'
|
||||
ports = { 'BTC': (8332,18332), 'BCH': (8442,18442) }
|
||||
|
||||
user_entropy = ''
|
||||
hash_preset = '3'
|
||||
usr_randchars = 30
|
||||
|
|
@ -106,19 +110,19 @@ class g(object):
|
|||
# User opt sets global var:
|
||||
common_opts = (
|
||||
'color','no_license','rpc_host','rpc_port','testnet','rpc_user','rpc_password',
|
||||
'bitcoin_data_dir','force_256_color','regtest'
|
||||
'bitcoin_data_dir','force_256_color','regtest','coin'
|
||||
)
|
||||
required_opts = (
|
||||
'quiet','verbose','debug','outdir','echo_passphrase','passwd_file','stdout',
|
||||
'show_hash_presets','label','keep_passphrase','keep_hash_preset','yes',
|
||||
'brain_params','b16','usr_randchars'
|
||||
'brain_params','b16','usr_randchars','coin'
|
||||
)
|
||||
incompatible_opts = (
|
||||
('quiet','verbose'),
|
||||
('label','keep_label'),
|
||||
('tx_id','info'),
|
||||
('tx_id','terse_info'),
|
||||
('aug1hf','rbf'),
|
||||
('aug1hf','rbf'), # TODO: remove in 0.9.4
|
||||
('batch','rescan')
|
||||
)
|
||||
cfg_file_opts = (
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ opts_data = {
|
|||
-c, --comment-file= f Source the transaction's comment from file 'f'
|
||||
-d, --outdir= d Specify an alternate directory 'd' for output
|
||||
-e, --echo-passphrase Print passphrase to screen when typing it
|
||||
-f, --tx-fee= f Transaction fee, as a decimal BTC amount or in
|
||||
-f, --tx-fee= f Transaction fee, as a decimal {cu} amount or in
|
||||
satoshis per byte (an integer followed by 's')
|
||||
-H, --hidden-incog-input-params=f,o Read hidden incognito data from file
|
||||
'f' at offset 'o' (comma-separated)
|
||||
|
|
@ -51,7 +51,7 @@ opts_data = {
|
|||
-M, --mmgen-keys-from-file=f Provide keys for {pnm} addresses in a key-
|
||||
address file (output of '{pnl}-keygen'). Permits
|
||||
online signing without an {pnm} seed source. The
|
||||
key-address file is also used to verify {pnm}-to-BTC
|
||||
key-address file is also used to verify {pnm}-to-{cu}
|
||||
mappings, so the user should record its checksum.
|
||||
-o, --output-to-reduce=o Deduct the fee from output 'o' (an integer, or 'c'
|
||||
for the transaction's change output, if present)
|
||||
|
|
@ -67,11 +67,13 @@ opts_data = {
|
|||
-z, --show-hash-presets Show information on available hash presets
|
||||
""".format(g=g,pnm=pnm,pnl=pnm.lower(),
|
||||
kgs=' '.join(['{}:{}'.format(n,k) for n,k in enumerate(g.key_generators,1)]),
|
||||
kg=g.key_generator),
|
||||
kg=g.key_generator,
|
||||
cu=g.coin
|
||||
),
|
||||
'notes': '\n' + fee_notes + txsign_notes
|
||||
}
|
||||
|
||||
cmd_args = opts.init(opts_data,add_opts=['aug1hf'])
|
||||
cmd_args = opts.init(opts_data)
|
||||
|
||||
c = bitcoin_connection()
|
||||
|
||||
|
|
@ -96,14 +98,14 @@ tx.set_min_fee()
|
|||
|
||||
if not [o.amt for o in tx.outputs if o.amt >= tx.min_fee]:
|
||||
die(1,'Transaction cannot be bumped.' +
|
||||
'\nAll outputs have less than the minimum fee ({} BTC)'.format(tx.min_fee))
|
||||
'\nAll outputs have less than the minimum fee ({} {})'.format(tx.min_fee,g.coin))
|
||||
|
||||
msg('Creating new transaction')
|
||||
|
||||
op_idx = tx.choose_output()
|
||||
|
||||
if not silent:
|
||||
msg('Minimum fee for new transaction: {} BTC'.format(tx.min_fee))
|
||||
msg('Minimum fee for new transaction: {} {}'.format(tx.min_fee,g.coin))
|
||||
|
||||
fee = tx.get_usr_fee_interactive(tx_fee=opt.tx_fee,desc='User-selected')
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ opts_data = {
|
|||
-c, --comment-file=f Source the transaction's comment from file 'f'
|
||||
-C, --tx-confs= c Desired number of confirmations (default: {g.tx_confs})
|
||||
-d, --outdir= d Specify an alternate directory 'd' for output
|
||||
-f, --tx-fee= f Transaction fee, as a decimal BTC amount or in satoshis
|
||||
-f, --tx-fee= f Transaction fee, as a decimal {cu} amount or in satoshis
|
||||
per byte (an integer followed by 's'). If omitted, fee
|
||||
will be calculated using bitcoind's 'estimatefee' call
|
||||
-i, --info Display unspent outputs and exit
|
||||
|
|
@ -45,7 +45,7 @@ opts_data = {
|
|||
-r, --rbf Make transaction BIP 125 replaceable (replace-by-fee)
|
||||
-v, --verbose Produce more verbose output
|
||||
-y, --yes Answer 'yes' to prompts, suppress non-essential output
|
||||
""".format(g=g),
|
||||
""".format(g=g,cu=g.coin),
|
||||
'notes': '\n' + txcreate_notes + fee_notes
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ opts_data = {
|
|||
-C, --tx-confs= c Desired number of confirmations (default: {g.tx_confs})
|
||||
-d, --outdir= d Specify an alternate directory 'd' for output
|
||||
-e, --echo-passphrase Print passphrase to screen when typing it
|
||||
-f, --tx-fee= f Transaction fee, as a decimal BTC amount or in
|
||||
-f, --tx-fee= f Transaction fee, as a decimal {cu} amount or in
|
||||
satoshis per byte (an integer followed by 's').
|
||||
If omitted, bitcoind's 'estimatefee' will be used
|
||||
to calculate the fee.
|
||||
|
|
@ -58,7 +58,7 @@ opts_data = {
|
|||
-M, --mmgen-keys-from-file=f Provide keys for {pnm} addresses in a key-
|
||||
address file (output of '{pnl}-keygen'). Permits
|
||||
online signing without an {pnm} seed source. The
|
||||
key-address file is also used to verify {pnm}-to-BTC
|
||||
key-address file is also used to verify {pnm}-to-{cu}
|
||||
mappings, so the user should record its checksum.
|
||||
-O, --old-incog-fmt Specify old-format incognito input
|
||||
-p, --hash-preset= p Use the scrypt hash parameters defined by preset 'p'
|
||||
|
|
@ -71,11 +71,18 @@ opts_data = {
|
|||
-z, --show-hash-presets Show information on available hash presets
|
||||
""".format(g=g,pnm=pnm,pnl=pnm.lower(),
|
||||
kgs=' '.join(['{}:{}'.format(n,k) for n,k in enumerate(g.key_generators,1)]),
|
||||
kg=g.key_generator),
|
||||
kg=g.key_generator,
|
||||
cu=g.coin
|
||||
),
|
||||
'notes': '\n' + txcreate_notes + fee_notes + txsign_notes
|
||||
}
|
||||
|
||||
cmd_args = opts.init(opts_data)
|
||||
|
||||
if opt.aug1hf: # TODO: remove in 0.9.4
|
||||
msg(yellow('The --aug1hf option is deprecated. Please use --coin=bch instead'))
|
||||
g.coin = 'BCH'
|
||||
|
||||
seed_files = get_seed_files(opt,cmd_args)
|
||||
c = bitcoin_connection()
|
||||
do_license_msg()
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ opts_data = {
|
|||
--, --longhelp Print help message for long options (common options)
|
||||
-d, --outdir= d Specify an alternate directory 'd' for output
|
||||
-q, --quiet Suppress warnings; overwrite files without prompting
|
||||
-s, --status Get status of a sent transaction
|
||||
-y, --yes Answer 'yes' to prompts, suppress non-essential output
|
||||
"""
|
||||
}
|
||||
|
|
@ -43,7 +44,8 @@ if len(cmd_args) == 1:
|
|||
infile = cmd_args[0]; check_infile(infile)
|
||||
else: opts.usage()
|
||||
|
||||
do_license_msg()
|
||||
if not opt.status: do_license_msg()
|
||||
|
||||
c = bitcoin_connection()
|
||||
tx = MMGenTX(infile) # sig check performed here
|
||||
qmsg("Signed transaction file '%s' is valid" % infile)
|
||||
|
|
@ -51,6 +53,11 @@ qmsg("Signed transaction file '%s' is valid" % infile)
|
|||
if not tx.marked_signed(c):
|
||||
die(1,'Transaction is not signed!')
|
||||
|
||||
if opt.status:
|
||||
if tx.btc_txid: qmsg('{} txid: {}'.format(g.coin,tx.btc_txid.hl()))
|
||||
tx.get_status(c,status=True)
|
||||
sys.exit(0)
|
||||
|
||||
if not opt.yes:
|
||||
tx.view_with_prompt('View transaction data?')
|
||||
if tx.add_comment(): # edits an existing comment, returns true if changed
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ opts_data = {
|
|||
-M, --mmgen-keys-from-file=f Provide keys for {pnm} addresses in a key-
|
||||
address file (output of '{pnl}-keygen'). Permits
|
||||
online signing without an {pnm} seed source. The
|
||||
key-address file is also used to verify {pnm}-to-BTC
|
||||
key-address file is also used to verify {pnm}-to-{cu}
|
||||
mappings, so the user should record its checksum.
|
||||
-P, --passwd-file= f Get {pnm} wallet or bitcoind passphrase from file 'f'
|
||||
-q, --quiet Suppress warnings; overwrite files without prompting
|
||||
|
|
@ -63,12 +63,18 @@ opts_data = {
|
|||
""".format(
|
||||
g=g,pnm=pnm,pnl=pnm.lower(),
|
||||
kgs=' '.join(['{}:{}'.format(n,k) for n,k in enumerate(g.key_generators,1)]),
|
||||
kg=g.key_generator),
|
||||
kg=g.key_generator,
|
||||
cu=g.coin
|
||||
),
|
||||
'notes': '\n' + txsign_notes
|
||||
}
|
||||
|
||||
infiles = opts.init(opts_data,add_opts=['b16'])
|
||||
|
||||
if opt.aug1hf: # TODO: remove in 0.9.4
|
||||
msg(yellow('The --aug1hf option is deprecated. Please use --coin=bch instead'))
|
||||
g.coin = 'BCH'
|
||||
|
||||
if not infiles: opts.usage()
|
||||
for i in infiles: check_infile(i)
|
||||
|
||||
|
|
|
|||
|
|
@ -296,9 +296,11 @@ class BTCAmt(Decimal,Hilite,InitErrors):
|
|||
m = "'%s': value cannot be converted to decimal" % num
|
||||
else:
|
||||
if me.normalize().as_tuple()[-1] < -cls.max_prec:
|
||||
m = "'%s': too many decimal places in BTC amount" % num
|
||||
from mmgen.globalvars import g
|
||||
m = "'{}': too many decimal places in {} amount".format(num,g.coin)
|
||||
elif me > cls.max_amt:
|
||||
m = "'%s': BTC amount too large (>%s)" % (num,cls.max_amt)
|
||||
from mmgen.globalvars import g
|
||||
m = "'{}': {} amount too large (>{})".format(num,g.coin,cls.max_amt)
|
||||
# elif me.as_tuple()[0]:
|
||||
# m = "'%s': BTC amount cannot be negative" % num
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ def _show_hash_presets():
|
|||
|
||||
# most, but not all, of these set the corresponding global var
|
||||
common_opts_data = """
|
||||
--, --coin=c Choose coin unit. Default: {cu_dfl}. Options: {cu_all}
|
||||
--, --color=0|1 Disable or enable color output
|
||||
--, --force-256-color Force 256-color output when color is enabled
|
||||
--, --bitcoin-data-dir=d Specify Bitcoin data directory location 'd'
|
||||
|
|
@ -60,7 +61,11 @@ common_opts_data = """
|
|||
--, --testnet=0|1 Disable or enable testnet
|
||||
--, --skip-cfg-file Skip reading the configuration file
|
||||
--, --version Print version information and exit
|
||||
""".format(pnm=g.proj_name)
|
||||
""".format(
|
||||
pnm=g.proj_name,
|
||||
cu_dfl=g.coin,
|
||||
cu_all=' '.join(g.coins),
|
||||
)
|
||||
|
||||
def opt_preproc_debug(short_opts,long_opts,skipped_opts,uopts,args):
|
||||
d = (
|
||||
|
|
@ -102,6 +107,8 @@ def opt_postproc_initializations():
|
|||
|
||||
if g.platform == 'win': start_mscolor()
|
||||
|
||||
g.coin = g.coin.upper() # allow user to use lowercase
|
||||
|
||||
def set_data_dir_root():
|
||||
g.data_dir_root = os.path.normpath(os.path.expanduser(opt.data_dir)) if opt.data_dir else \
|
||||
os.path.join(g.home_dir,'.'+g.proj_name.lower())
|
||||
|
|
@ -273,10 +280,10 @@ def check_opts(usr_opts): # Returns false if any check fails
|
|||
from mmgen.tx import MMGenTX
|
||||
ret = MMGenTX().convert_fee_spec(val,224,on_fail='return')
|
||||
if ret == False:
|
||||
msg("'{}': invalid {} (not a BTC amount or satoshis-per-byte specification)".format(
|
||||
val,desc))
|
||||
msg("'{}': invalid {} (not a {} amount or satoshis-per-byte specification)".format(
|
||||
val,desc,g.coin.upper()))
|
||||
elif ret != None and ret > g.max_tx_fee:
|
||||
msg("'{}': invalid {} (greater than max_tx_fee ({} BTC))".format(val,desc,g.max_tx_fee))
|
||||
msg("'{}': invalid {} (> max_tx_fee ({} {}))".format(val,desc,g.max_tx_fee,g.coin.upper()))
|
||||
else:
|
||||
return True
|
||||
return False
|
||||
|
|
@ -386,6 +393,8 @@ def check_opts(usr_opts): # Returns false if any check fails
|
|||
elif key == 'key_generator':
|
||||
if not opt_compares(val,'<=',len(g.key_generators),desc): return False
|
||||
if not opt_compares(val,'>',0,desc): return False
|
||||
elif key == 'coin':
|
||||
if not opt_is_in_list(val.upper(),g.coins,'coin'): return False
|
||||
else:
|
||||
if g.debug: Msg("check_opts(): No test for opt '%s'" % key)
|
||||
|
||||
|
|
|
|||
|
|
@ -28,11 +28,7 @@ from mmgen.obj import BTCAmt
|
|||
|
||||
class BitcoinRPCConnection(object):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
host=g.rpc_host,port=(8332,18332)[g.testnet],
|
||||
user=None,passwd=None,auth_cookie=None,
|
||||
):
|
||||
def __init__(self,host=None,port=None,user=None,passwd=None,auth_cookie=None):
|
||||
|
||||
dmsg('=== BitcoinRPCConnection.__init__() debug ===')
|
||||
dmsg(' host [{}] port [{}] user [{}] passwd [{}] auth_cookie [{}]\n'.format(
|
||||
|
|
@ -154,6 +150,7 @@ class BitcoinRPCConnection(object):
|
|||
'getblockcount',
|
||||
'getblockhash',
|
||||
'getmempoolentry',
|
||||
'getnettotals',
|
||||
'getnetworkinfo',
|
||||
'getpeerinfo',
|
||||
'getrawmempool',
|
||||
|
|
|
|||
|
|
@ -485,8 +485,8 @@ def Listaddresses(addrs='',minconf=1,showempty=False,pager=False,showbtcaddrs=Fa
|
|||
if usr_addr_list and (label.mmid not in usr_addr_list): continue
|
||||
if label.mmid in addrs:
|
||||
if addrs[label.mmid]['addr'] != d['address']:
|
||||
die(2,'duplicate BTC address ({}) for this MMGen address! ({})'.format(
|
||||
(d['address'], addrs[label.mmid]['addr'])))
|
||||
die(2,'duplicate {} address ({}) for this MMGen address! ({})'.format(
|
||||
g.coin,d['address'],addrs[label.mmid]['addr']))
|
||||
else:
|
||||
addrs[label.mmid] = { 'amt':BTCAmt('0'), 'lbl':label, 'addr':BTCAddr(d['address']) }
|
||||
addrs[label.mmid]['amt'] += d['amount']
|
||||
|
|
@ -501,7 +501,7 @@ def Listaddresses(addrs='',minconf=1,showempty=False,pager=False,showbtcaddrs=Fa
|
|||
assert len(accts) == len(acct_addrs), 'listaccounts() and getaddressesbyaccount() not of same length'
|
||||
for a in acct_addrs:
|
||||
if len(a) != 1:
|
||||
die(2,"'{}': more than one BTC address in account!".format(a))
|
||||
die(2,"'{}': more than one {} address in account!".format(a,g.coin))
|
||||
for label,addr in zip(accts,[b[0] for b in acct_addrs]):
|
||||
if usr_addr_list and (label.mmid not in usr_addr_list): continue
|
||||
if label.mmid not in addrs:
|
||||
|
|
@ -543,7 +543,7 @@ def Listaddresses(addrs='',minconf=1,showempty=False,pager=False,showbtcaddrs=Fa
|
|||
cmt=addrs[mmid]['lbl'].comment.fmt(width=max_cmt_len,color=True,nullrepl='-'),
|
||||
amt=addrs[mmid]['amt'].fmt('3.0',color=True)))
|
||||
|
||||
out.append('\nTOTAL: %s BTC' % total.hl(color=True))
|
||||
out.append('\nTOTAL: {} {}'.format(total.hl(color=True),g.coin))
|
||||
o = '\n'.join(out)
|
||||
return do_pager(o) if pager else Msg(o)
|
||||
|
||||
|
|
@ -567,7 +567,7 @@ def Getbalance(minconf=1):
|
|||
Msg(fs.format('Wallet',
|
||||
*[s.ljust(16) for s in ' Unconfirmed',' <%s %s'%(mc,lbl),' >=%s %s'%(mc,lbl)]))
|
||||
for key in sorted(accts.keys()):
|
||||
Msg(fs.format(key+':', *[a.fmt(color=True,suf=' BTC') for a in accts[key]]))
|
||||
Msg(fs.format(key+':', *[a.fmt(color=True,suf=' '+g.coin) for a in accts[key]]))
|
||||
if 'SPENDABLE' in accts:
|
||||
Msg(red('Warning: this wallet contains PRIVATE KEYS for the SPENDABLE balance!'))
|
||||
|
||||
|
|
|
|||
18
mmgen/tw.py
18
mmgen/tw.py
|
|
@ -157,13 +157,13 @@ 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: %s) Total BTC: %s'
|
||||
out = [hdr_fmt % (' '.join(self.sort_info()), self.total.hl())]
|
||||
hdr_fmt = 'UNSPENT OUTPUTS (sort order: {}) Total {}: {}'
|
||||
out = [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()))]
|
||||
af = BTCAddr.fmtc('Address',width=addr_w+1)
|
||||
cf = ('Conf.','Age(d)')[self.show_days]
|
||||
out += [fs % ('Num','TX id'.ljust(tx_w - 5) + ' Vout','',af,'Amt(BTC) ',cf)]
|
||||
out += [fs % ('Num','TX id'.ljust(tx_w - 5) + ' Vout','',af,'Amt({}) '.format(g.coin),cf)]
|
||||
|
||||
for n,i in enumerate(unsp):
|
||||
addr_dots = '|' + '.'*33
|
||||
|
|
@ -195,7 +195,7 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
|
|||
|
||||
fs = ' %-4s %-67s %s %s %s %-8s %-6s %s'
|
||||
out = [fs % ('Num','Tx ID,Vout','Address'.ljust(34),'MMGen ID'.ljust(15),
|
||||
'Amount(BTC)','Conf.','Age(d)', 'Label')]
|
||||
'Amount({})'.format(g.coin),'Conf.','Age(d)', '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):
|
||||
|
|
@ -209,17 +209,18 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
|
|||
TwComment.fmtc('',color=color,nullrepl='-',width=max_lbl_len))
|
||||
out.append(s.rstrip())
|
||||
|
||||
fs = 'Unspent outputs ({} UTC)\nSort order: {}\n\n{}\n\nTotal BTC: {}\n'
|
||||
fs = 'Unspent outputs ({} UTC)\nSort order: {}\n\n{}\n\nTotal {}: {}\n'
|
||||
self.fmt_print = fs.format(
|
||||
make_timestr(),
|
||||
' '.join(self.sort_info(include_group=False)),
|
||||
'\n'.join(out),
|
||||
g.coin,
|
||||
self.total.hl(color=color))
|
||||
return self.fmt_print
|
||||
|
||||
def display_total(self):
|
||||
fs = '\nTotal unspent: %s BTC (%s outputs)'
|
||||
msg(fs % (self.total.hl(),len(self.unspent)))
|
||||
fs = '\nTotal unspent: {} {} ({} outputs)'
|
||||
msg(fs.format(self.total.hl(),g.coin,len(self.unspent)))
|
||||
|
||||
def get_idx_and_label_from_user(self):
|
||||
msg('')
|
||||
|
|
@ -246,7 +247,8 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
|
|||
return n,s
|
||||
|
||||
def view_and_sort(self,tx):
|
||||
txos = 'Total to spend, excluding fees: {} BTC\n\n'.format(tx.sum_outputs().hl()) if tx.outputs else ''
|
||||
fs = 'Total to spend, excluding fees: {} {}\n\n'
|
||||
txos = fs.format(tx.sum_outputs().hl(),g.coin) if tx.outputs else ''
|
||||
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
|
||||
|
|
|
|||
101
mmgen/tx.py
101
mmgen/tx.py
|
|
@ -319,7 +319,7 @@ class MMGenTX(MMGenObject):
|
|||
def get_relay_fee(self):
|
||||
assert self.estimate_size()
|
||||
kb_fee = BTCAmt(bitcoin_connection().getnetworkinfo()['relayfee'])
|
||||
vmsg('Relay fee: {} BTC/kB'.format(kb_fee))
|
||||
vmsg('Relay fee: {} {}/kB'.format(kb_fee,g.coin))
|
||||
return kb_fee * self.estimate_size() / 1024
|
||||
|
||||
def convert_fee_spec(self,tx_fee,tx_size,on_fail='throw'):
|
||||
|
|
@ -339,16 +339,20 @@ class MMGenTX(MMGenObject):
|
|||
def get_usr_fee(self,tx_fee,desc='Missing description'):
|
||||
btc_fee = self.convert_fee_spec(tx_fee,self.estimate_size(),on_fail='return')
|
||||
if btc_fee == None:
|
||||
msg("'{}': cannot convert satoshis-per-byte to BTC because transaction size is unknown".format(tx_fee))
|
||||
assert False # because we shouldn't be calling this if tx size is unknown
|
||||
# we shouldn't be calling this if tx size is unknown
|
||||
m = "'{}': cannot convert satoshis-per-byte to {} because transaction size is unknown"
|
||||
assert False, m.format(tx_fee,g.coin)
|
||||
elif btc_fee == False:
|
||||
msg("'{}': invalid TX fee (not a BTC amount or satoshis-per-byte specification)".format(tx_fee))
|
||||
m = "'{}': invalid TX fee (not a {} amount or satoshis-per-byte specification)"
|
||||
msg(m.format(tx_fee,g.coin))
|
||||
return False
|
||||
elif btc_fee > g.max_tx_fee:
|
||||
msg('{} BTC: {} fee too large (maximum fee: {} BTC)'.format(btc_fee,desc,g.max_tx_fee))
|
||||
m = '{} {c}: {} fee too large (maximum fee: {} {c})'
|
||||
msg(m.format(btc_fee,desc,g.max_tx_fee,c=g.coin))
|
||||
return False
|
||||
elif btc_fee < self.get_relay_fee():
|
||||
msg('{} BTC: {} fee too small (below relay fee of {} BTC)'.format(str(btc_fee),desc,str(self.get_relay_fee())))
|
||||
m = '{} {c}: {} fee too small (below relay fee of {} {c})'
|
||||
msg(m.format(str(btc_fee),desc,str(self.get_relay_fee()),c=g.coin))
|
||||
return False
|
||||
else:
|
||||
return btc_fee
|
||||
|
|
@ -360,8 +364,8 @@ class MMGenTX(MMGenObject):
|
|||
btc_fee = self.get_usr_fee(tx_fee,desc)
|
||||
if btc_fee:
|
||||
m = ('',' (after {}x adjustment)'.format(opt.tx_fee_adj))[opt.tx_fee_adj != 1]
|
||||
p = '{} TX fee{}: {} BTC ({} satoshis per byte)'.format(desc,m,
|
||||
btc_fee.hl(),pink(str(self.btc2spb(btc_fee))))
|
||||
p = '{} TX fee{}: {} {} ({} satoshis per byte)'.format(desc,m,
|
||||
btc_fee.hl(),g.coin,pink(str(self.btc2spb(btc_fee))))
|
||||
if opt.yes or keypress_confirm(p+'. OK?',default_yes=True):
|
||||
if opt.yes: msg(p)
|
||||
return btc_fee
|
||||
|
|
@ -444,8 +448,8 @@ class MMGenTX(MMGenObject):
|
|||
|
||||
self.die_if_incorrect_chain()
|
||||
|
||||
if opt.aug1hf and self.has_segwit_inputs():
|
||||
die(2,yellow("'--aug1hf' option is incompatible with Segwit transaction inputs!"))
|
||||
if g.coin == 'BCH' and self.has_segwit_inputs():
|
||||
die(2,yellow("Segwit inputs cannot be spent on BCH chain!"))
|
||||
|
||||
if not keys:
|
||||
msg('No keys. Cannot sign!')
|
||||
|
|
@ -468,15 +472,15 @@ class MMGenTX(MMGenObject):
|
|||
|
||||
from mmgen.bitcoin import hash256
|
||||
msg_r('Signing transaction{}...'.format(tx_num_str))
|
||||
ht = ('ALL','ALL|FORKID')[bool(opt.aug1hf)] # sighashtype defaults to 'ALL'
|
||||
ht = ('ALL','ALL|FORKID')[g.coin=='BCH'] # sighashtype defaults to 'ALL'
|
||||
ret = c.signrawtransaction(self.hex,sig_data,keys.values(),ht,on_fail='return')
|
||||
|
||||
from mmgen.rpc import rpc_error,rpc_errmsg
|
||||
if rpc_error(ret):
|
||||
errmsg = rpc_errmsg(ret)
|
||||
if 'Invalid sighash param' in errmsg:
|
||||
m = 'This chain does not support the Aug. 1 2017 UAHF.'
|
||||
m += "\nRe-run 'mmgen-txsign' or 'mmgen-txdo' without the --aug1hf option."
|
||||
m = 'This is not the BCH chain.'
|
||||
m += "\nRe-run the script without the --aug1hf or --coin=bch option."
|
||||
else:
|
||||
m = errmsg
|
||||
msg(yellow(m))
|
||||
|
|
@ -549,6 +553,17 @@ class MMGenTX(MMGenObject):
|
|||
def is_in_utxos(self,c):
|
||||
return 'txid' in c.getrawtransaction(self.btc_txid,True,on_fail='silent')
|
||||
|
||||
def get_status(self,c,status=False):
|
||||
if self.is_in_mempool(c):
|
||||
msg(('Warning: transaction is in mempool!','Transaction is in mempool')[status])
|
||||
elif self.is_in_wallet(c):
|
||||
die(1,'Transaction has been confirmed{}'.format('' if status else '!'))
|
||||
elif self.is_in_utxos(c):
|
||||
die(2,red('ERROR: transaction is in the blockchain (but not in the tracking wallet)!'))
|
||||
ret = self.is_replaced(c) # 1: replacement in mempool, 2: replacement confirmed
|
||||
if ret:
|
||||
die(1,'Transaction has been replaced'+('',', and the replacement TX is confirmed')[ret==2]+'!')
|
||||
|
||||
def send(self,c,prompt_user=True):
|
||||
|
||||
self.die_if_incorrect_chain()
|
||||
|
|
@ -562,16 +577,7 @@ class MMGenTX(MMGenObject):
|
|||
if self.get_fee() > g.max_tx_fee:
|
||||
die(2,'Transaction fee ({}) greater than max_tx_fee ({})!'.format(self.get_fee(),g.max_tx_fee))
|
||||
|
||||
if self.is_in_mempool(c):
|
||||
msg('Warning: transaction is in mempool!')
|
||||
elif self.is_in_wallet(c):
|
||||
die(1,'Transaction has been confirmed!')
|
||||
elif self.is_in_utxos(c):
|
||||
die(2,red('ERROR: transaction is in the blockchain (but not in the tracking wallet)!'))
|
||||
|
||||
ret = self.is_replaced(c) # 1: replacement in mempool, 2: replacement confirmed
|
||||
if ret:
|
||||
die(1,'Transaction has been replaced'+('',', and the replacement TX is confirmed')[ret==2]+'!')
|
||||
self.get_status(c)
|
||||
|
||||
if prompt_user:
|
||||
m1 = ("Once this transaction is sent, there's no taking it back!",'')[bool(opt.quiet)]
|
||||
|
|
@ -592,10 +598,10 @@ class MMGenTX(MMGenObject):
|
|||
errmsg = rpc_errmsg(ret)
|
||||
if 'Signature must use SIGHASH_FORKID' in errmsg:
|
||||
m = 'The Aug. 1 2017 UAHF has activated on this chain.'
|
||||
m += "\nRe-run 'mmgen-txsign' or 'mmgen-txdo' with the --aug1hf option."
|
||||
m += "\nRe-run the script with the --coin=bch option."
|
||||
elif 'Illegal use of SIGHASH_FORKID' in errmsg:
|
||||
m = 'The Aug. 1 2017 UAHF is not yet active on this chain.'
|
||||
m += "\nRe-run 'mmgen-txsign' or 'mmgen-txdo' without the --aug1hf option."
|
||||
m += "\nRe-run the script without the --aug1hf or --coin=bch option."
|
||||
else:
|
||||
m = errmsg
|
||||
msg(yellow(m))
|
||||
|
|
@ -667,74 +673,77 @@ class MMGenTX(MMGenObject):
|
|||
blockcount = None
|
||||
|
||||
hdr_fs = (
|
||||
'TRANSACTION DATA\n\nHeader: [ID:{}] [{} BTC] [{} UTC] [RBF:{}] [Signed:{}]\n',
|
||||
'Transaction {} {} BTC ({} UTC) RBF={} Signed={}\n'
|
||||
'TRANSACTION DATA\n\n[ID:{}] [{} {}] [{} UTC] [RBF:{}] [Signed:{}]\n',
|
||||
'Transaction {} {} {} ({} UTC) RBF={} Signed={}\n'
|
||||
)[bool(terse)]
|
||||
|
||||
out = hdr_fs.format(self.txid.hl(),self.send_amt.hl(),self.timestamp,
|
||||
out = hdr_fs.format(self.txid.hl(),self.send_amt.hl(),g.coin,self.timestamp,
|
||||
self.is_rbf(color=True),self.marked_signed(color=True))
|
||||
|
||||
enl = ('\n','')[bool(terse)]
|
||||
if self.chain in ('testnet','regtest'): out += green('Chain: {}\n'.format(self.chain.upper()))
|
||||
if self.btc_txid: out += 'Bitcoin TxID: {}\n'.format(self.btc_txid.hl())
|
||||
if self.btc_txid: out += '{} TxID: {}\n'.format(g.coin,self.btc_txid.hl())
|
||||
out += enl
|
||||
|
||||
if self.label:
|
||||
out += 'Comment: %s\n%s' % (self.label.hl(),enl)
|
||||
out += 'Inputs:\n' + enl
|
||||
|
||||
nonmm_str = '(non-{pnm} address){s} '.format(pnm=g.proj_name,s=('',' ')[terse])
|
||||
nonmm_str = '(non-{pnm} address)'.format(pnm=g.proj_name)
|
||||
max_mmwid = max(max(len(i.mmid) for i in self.inputs if i.mmid)+len('()'),len(nonmm_str))
|
||||
for n,e in enumerate(sorted(self.inputs,key=lambda o: o.mmid.sort_key if o.mmid else o.addr)):
|
||||
if blockcount:
|
||||
confs = e.confs + blockcount - self.blockcount
|
||||
days = int(confs * g.mins_per_block / (60*24))
|
||||
mmid_fmt = e.mmid.fmt(width=len(nonmm_str),encl='()',color=True) if e.mmid \
|
||||
else MMGenID.hlc(nonmm_str)
|
||||
mmid_fmt = e.mmid.fmt(width=max_mmwid,encl='()',color=True) if e.mmid else MMGenID.hlc(nonmm_str)
|
||||
if terse:
|
||||
out += '%3s: %s %s %s BTC' % (n+1, e.addr.fmt(color=True),mmid_fmt, e.amt.hl())
|
||||
out += '{:3} {} {} {} {}'.format(n+1,e.addr.fmt(color=True),mmid_fmt,e.amt.hl(),g.coin)
|
||||
else:
|
||||
for d in (
|
||||
(n+1, 'tx,vout:', '%s,%s' % (e.txid, e.vout)),
|
||||
('', 'address:', e.addr.fmt(color=True) + ' ' + mmid_fmt),
|
||||
('', 'comment:', e.label.hl() if e.label else ''),
|
||||
('', 'amount:', '%s BTC' % e.amt.hl()),
|
||||
('', 'amount:', '{} {}'.format(e.amt.hl(),g.coin)),
|
||||
('', 'confirmations:', '%s (around %s days)' % (confs,days) if blockcount else '')
|
||||
):
|
||||
if d[2]: out += ('%3s %-8s %s\n' % d)
|
||||
out += '\n'
|
||||
|
||||
out += 'Outputs:\n' + enl
|
||||
max_mmwid = max((len(o.mmid),len(o.mmid)+len(' (chg)'))[bool(o.is_chg)] for o in self.outputs if o.mmid)
|
||||
max_mmwid = max(max_mmwid+len('()'),len(nonmm_str))
|
||||
for n,e in enumerate(sorted(self.outputs,key=lambda o: o.mmid.sort_key if o.mmid else o.addr)):
|
||||
if e.mmid:
|
||||
app=('',' (chg)')[bool(e.is_chg and terse)]
|
||||
mmid_fmt = e.mmid.fmt(width=len(nonmm_str),encl='()',color=True,
|
||||
mmid_fmt = e.mmid.fmt(width=max_mmwid,encl='()',color=True,
|
||||
app=app,appcolor='green')
|
||||
else:
|
||||
mmid_fmt = MMGenID.hlc(nonmm_str)
|
||||
if terse:
|
||||
out += '%3s: %s %s %s BTC' % (n+1, e.addr.fmt(color=True),mmid_fmt, e.amt.hl())
|
||||
out += '{:3} {} {} {} {}'.format(n+1,e.addr.fmt(color=True),mmid_fmt,e.amt.hl(),g.coin)
|
||||
else:
|
||||
for d in (
|
||||
(n+1, 'address:', e.addr.fmt(color=True) + ' ' + mmid_fmt),
|
||||
('', 'comment:', e.label.hl() if e.label else ''),
|
||||
('', 'amount:', '%s BTC' % e.amt.hl()),
|
||||
('', 'amount:', '{} {}'.format(e.amt.hl(),g.coin)),
|
||||
('', 'change:', green('True') if e.is_chg else '')
|
||||
):
|
||||
if d[2]: out += ('%3s %-8s %s\n' % d)
|
||||
out += '\n'
|
||||
|
||||
fs = (
|
||||
'Total input: %s BTC\nTotal output: %s BTC\nTX fee: %s BTC (%s satoshis per byte)\n',
|
||||
'In %s BTC - Out %s BTC - Fee %s BTC (%s satoshis/byte)\n'
|
||||
'Total input: {} {c}\nTotal output: {} {c}\nTX fee: {} {c} ({} satoshis per byte)\n',
|
||||
'In {} {c} - Out {} {c} - Fee {} {c} ({} satoshis/byte)\n'
|
||||
)[bool(terse)]
|
||||
|
||||
total_in = self.sum_inputs()
|
||||
total_out = self.sum_outputs()
|
||||
out += fs % (
|
||||
out += fs.format(
|
||||
total_in.hl(),
|
||||
total_out.hl(),
|
||||
(total_in-total_out).hl(),
|
||||
pink(str(self.btc2spb(total_in-total_out))),
|
||||
c=g.coin
|
||||
)
|
||||
if opt.verbose:
|
||||
ts = len(self.hex)/2 if self.hex else 'unknown'
|
||||
|
|
@ -851,10 +860,10 @@ class MMGenBumpTX(MMGenTX):
|
|||
else:
|
||||
o_amt = self.outputs[idx].amt
|
||||
cs = ('',' (change output)')[chg_idx == idx]
|
||||
p = 'Fee will be deducted from output {}{} ({} BTC)'.format(idx+1,cs,o_amt)
|
||||
p = 'Fee will be deducted from output {}{} ({} {})'.format(idx+1,cs,o_amt,g.coin)
|
||||
if o_amt < self.min_fee:
|
||||
msg('Minimum fee ({} BTC) is greater than output amount ({} BTC)'.format(
|
||||
self.min_fee,o_amt))
|
||||
msg('Minimum fee ({} {c}) is greater than output amount ({} {c})'.format(
|
||||
self.min_fee,o_amt,c=g.coin))
|
||||
elif opt.yes or keypress_confirm(p+'. OK?',default_yes=True):
|
||||
if opt.yes: msg(p)
|
||||
self.bump_output_idx = idx
|
||||
|
|
@ -866,11 +875,11 @@ class MMGenBumpTX(MMGenTX):
|
|||
def get_usr_fee(self,tx_fee,desc):
|
||||
ret = super(type(self),self).get_usr_fee(tx_fee,desc)
|
||||
if ret < self.min_fee:
|
||||
msg('{} BTC: {} fee too small. Minimum fee: {} BTC ({} satoshis per byte)'.format(
|
||||
ret,desc,self.min_fee,self.btc2spb(self.min_fee)))
|
||||
msg('{} {c}: {} fee too small. Minimum fee: {} {c} ({} satoshis per byte)'.format(
|
||||
ret,desc,self.min_fee,self.btc2spb(self.min_fee,c=g.coin)))
|
||||
return False
|
||||
output_amt = self.outputs[self.bump_output_idx].amt
|
||||
if ret >= output_amt:
|
||||
msg('{} BTC: {} fee too large. Maximum fee: <{} BTC'.format(ret,desc,output_amt))
|
||||
msg('{} {c}: {} fee too large. Maximum fee: <{} {c}'.format(ret,desc,output_amt,c=g.coin))
|
||||
return False
|
||||
return ret
|
||||
|
|
|
|||
|
|
@ -51,10 +51,10 @@ one address with no amount on the command line.
|
|||
|
||||
fee_notes = """
|
||||
FEE SPECIFICATION: Transaction fees, both on the command line and at the
|
||||
interactive prompt, may be specified as either absolute BTC amounts, using a
|
||||
plain decimal number, or as satoshis per byte, using an integer followed by
|
||||
interactive prompt, may be specified as either absolute {} amounts, using
|
||||
a plain decimal number, or as satoshis per byte, using an integer followed by
|
||||
the letter 's'.
|
||||
"""
|
||||
""".format(g.coin)
|
||||
|
||||
wmsg = {
|
||||
'addr_in_addrfile_only': """
|
||||
|
|
@ -77,19 +77,15 @@ NOTE: This transaction includes non-{pnm} inputs, which makes the signing
|
|||
process more complicated. When signing the transaction, keys for non-{pnm}
|
||||
inputs must be supplied to '{pnl}-txsign' in a file with the '--keys-from-file'
|
||||
option.
|
||||
Selected non-{pnm} inputs: %s
|
||||
Selected non-{pnm} inputs: {{}}
|
||||
""".strip().format(pnm=pnm,pnl=pnm.lower()),
|
||||
'not_enough_btc': """
|
||||
Selected outputs insufficient to fund this transaction (%s BTC needed)
|
||||
""".strip(),
|
||||
'throwaway_change': """
|
||||
ERROR: This transaction produces change (%s BTC); however, no change address
|
||||
was specified.
|
||||
""".strip(),
|
||||
Selected outputs insufficient to fund this transaction ({{}} {} needed)
|
||||
""".strip().format(g.coin),
|
||||
'no_change_output': """
|
||||
ERROR: No change address specified. If you wish to create a transaction with
|
||||
only one output, specify a single output address with no BTC amount
|
||||
""".strip(),
|
||||
only one output, specify a single output address with no {} amount
|
||||
""".strip().format(g.coin),
|
||||
}
|
||||
|
||||
def select_unspent(unspent,prompt):
|
||||
|
|
@ -139,7 +135,7 @@ def get_fee_from_estimate_or_user(tx,estimate_fail_msg_shown=[]):
|
|||
else:
|
||||
start_fee = BTCAmt(ret) * opt.tx_fee_adj * tx.estimate_size() / 1024
|
||||
if opt.verbose:
|
||||
msg('{} fee ({} confs): {} BTC/kB'.format(desc,opt.tx_confs,ret))
|
||||
msg('{} fee ({} confs): {} {}/kB'.format(desc,opt.tx_confs,ret,g.coin))
|
||||
msg('TX size (estimated): {}'.format(tx.estimate_size()))
|
||||
|
||||
return tx.get_usr_fee_interactive(start_fee,desc=desc)
|
||||
|
|
@ -195,12 +191,12 @@ def get_inputs_from_user(tw,tx,caller):
|
|||
|
||||
t_inputs = sum(s.amt for s in sel_unspent)
|
||||
if t_inputs < tx.send_amt:
|
||||
msg(wmsg['not_enough_btc'] % (tx.send_amt - t_inputs))
|
||||
msg(wmsg['not_enough_btc'].format(tx.send_amt-t_inputs))
|
||||
continue
|
||||
|
||||
non_mmaddrs = [i for i in sel_unspent if i.twmmid.type == 'non-mmgen']
|
||||
if non_mmaddrs and caller != 'txdo':
|
||||
msg(wmsg['non_mmgen_inputs'] % ', '.join(set(sorted([a.addr.hl() for a in non_mmaddrs]))))
|
||||
msg(wmsg['non_mmgen_inputs'].format(', '.join(set(sorted([a.addr.hl() for a in non_mmaddrs])))))
|
||||
if not keypress_confirm('Accept?'):
|
||||
continue
|
||||
|
||||
|
|
@ -209,12 +205,12 @@ def get_inputs_from_user(tw,tx,caller):
|
|||
change_amt = tx.sum_inputs() - tx.send_amt - get_fee_from_estimate_or_user(tx)
|
||||
|
||||
if change_amt >= 0:
|
||||
p = 'Transaction produces %s BTC in change' % change_amt.hl()
|
||||
p = 'Transaction produces {} {} in change'.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_btc'] % abs(change_amt))
|
||||
msg(wmsg['not_enough_btc'].format(abs(change_amt)))
|
||||
|
||||
def txcreate(cmd_args,do_info=False,caller='txcreate'):
|
||||
|
||||
|
|
@ -234,7 +230,9 @@ def txcreate(cmd_args,do_info=False,caller='txcreate'):
|
|||
|
||||
tx.send_amt = tx.sum_outputs()
|
||||
|
||||
msg('Total amount to spend: %s' % ('Unknown','%s BTC'%tx.send_amt.hl())[bool(tx.send_amt)])
|
||||
msg('Total amount to spend: {}'.format(
|
||||
('Unknown','{} {}'.format(tx.send_amt.hl(),g.coin))[bool(tx.send_amt)]
|
||||
))
|
||||
|
||||
change_amt = get_inputs_from_user(tw,tx,caller)
|
||||
|
||||
|
|
|
|||
|
|
@ -57,12 +57,12 @@ column below:
|
|||
|
||||
wmsg = {
|
||||
'mapping_error': """
|
||||
{pnm} -> BTC address mappings differ!
|
||||
%-23s %s -> %s
|
||||
%-23s %s -> %s
|
||||
""".strip().format(pnm=pnm),
|
||||
{pnm} -> {c} address mappings differ!
|
||||
{{:<23}} {{}} -> {{}}
|
||||
{{:<23}} {{}} -> {{}}
|
||||
""".strip().format(pnm=pnm,c=g.coin),
|
||||
'missing_keys_error': """
|
||||
ERROR: a key file must be supplied for the following non-{pnm} address%s:\n %s
|
||||
ERROR: a key file must be supplied for the following non-{pnm} address{{}}:\n {{}}
|
||||
""".format(pnm=pnm).strip()
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +106,7 @@ def add_keys(tx,src,infiles=None,saved_seeds=None,keyaddr_list=None):
|
|||
if not need_keys: return []
|
||||
desc,m1 = ('key-address file','From key-address file:') if keyaddr_list else \
|
||||
('seed(s)','Generated from seed:')
|
||||
qmsg('Checking {} -> BTC address mappings for {} (from {})'.format(pnm,src,desc))
|
||||
qmsg('Checking {} -> {} address mappings for {} (from {})'.format(pnm,g.coin,src,desc))
|
||||
d = keyaddr_list.flat_list() if keyaddr_list else \
|
||||
generate_keys_for_mmgen_addrs([e.mmid for e in need_keys],infiles,saved_seeds)
|
||||
new_keys = []
|
||||
|
|
@ -118,7 +118,7 @@ def add_keys(tx,src,infiles=None,saved_seeds=None,keyaddr_list=None):
|
|||
if src == 'inputs':
|
||||
new_keys.append((f.addr,f.wif))
|
||||
else:
|
||||
die(3,wmsg['mapping_error'] % (m1,f.mmid,f.addr,'tx file:',e.mmid,e.addr))
|
||||
die(3,wmsg['mapping_error'].format(m1,f.mmid,f.addr,'tx file:',e.mmid,e.addr))
|
||||
if new_keys:
|
||||
vmsg('Added %s wif key%s from %s' % (len(new_keys),suf(new_keys,'s'),desc))
|
||||
return new_keys
|
||||
|
|
@ -165,7 +165,7 @@ def txsign(opt,c,tx,seed_files,kl,kal,tx_num_str=''):
|
|||
tmp = KeyAddrList(addrlist=non_mm_addrs,do_chksum=False)
|
||||
tmp.add_wifs(kl)
|
||||
m = tmp.list_missing('wif')
|
||||
if m: die(2,wmsg['missing_keys_error'] % (suf(m,'es'),'\n '.join(m)))
|
||||
if m: die(2,wmsg['missing_keys_error'].format(suf(m,'es'),'\n '.join(m)))
|
||||
keys += tmp.get_addr_wif_pairs()
|
||||
|
||||
if opt.mmgen_keys_from_file:
|
||||
|
|
|
|||
|
|
@ -58,7 +58,8 @@ def Die(ev=0,s=''):
|
|||
sys.exit(ev)
|
||||
|
||||
def rdie(ev=0,s=''): die(ev,red(s))
|
||||
def ydie(ev=0,s=''): die(ev,yellow(s))
|
||||
def wdie(ev=0,s=''): die(ev,yellow(s))
|
||||
def hi(): sys.stdout.write(yellow('hi'))
|
||||
|
||||
def pformat(d):
|
||||
import pprint
|
||||
|
|
@ -773,20 +774,16 @@ def get_bitcoind_auth_cookie():
|
|||
return ''
|
||||
|
||||
def bitcoin_connection():
|
||||
cfg = get_bitcoind_cfg_options(('rpcuser','rpcpassword'))
|
||||
import mmgen.rpc
|
||||
c = mmgen.rpc.BitcoinRPCConnection(
|
||||
g.rpc_host or 'localhost',
|
||||
g.rpc_port or (8332,18332)[g.testnet],
|
||||
g.rpc_user or cfg['rpcuser'], # MMGen's rpcuser,rpcpassword override bitcoind's
|
||||
g.rpc_password or cfg['rpcpassword'],
|
||||
auth_cookie=get_bitcoind_auth_cookie())
|
||||
# do an RPC call so we exit immediately if we can't connect
|
||||
if not g.bitcoind_version:
|
||||
g.bitcoind_version = int(c.getnetworkinfo()['version'])
|
||||
g.chain = c.getblockchaininfo()['chain']
|
||||
if g.chain != 'regtest': g.chain += 'net'
|
||||
assert g.chain in g.chains
|
||||
|
||||
def check_coin_mismatch(c):
|
||||
fb = '00000000000000000019f112ec0a9982926f1258cdcc558dd7c3b7e5dc7fa148'
|
||||
err = []
|
||||
if int(c.getblockchaininfo()['blocks']) <= 478558 or c.getblockhash(478559) == fb:
|
||||
if g.coin == 'BCH': err = 'BCH','BTC'
|
||||
elif g.coin == 'BTC': err = 'BTC','BCH'
|
||||
if err: wdie(2,"'{}' requested, but this is the {} chain!".format(*err))
|
||||
|
||||
def check_chain_mismatch():
|
||||
err = None
|
||||
if g.regtest and g.chain != 'regtest':
|
||||
err = '--regtest option'
|
||||
|
|
@ -797,4 +794,22 @@ def bitcoin_connection():
|
|||
err = 'mainnet'
|
||||
if err:
|
||||
die(1,'{} selected but chain is {}'.format(err,g.chain))
|
||||
|
||||
cfg = get_bitcoind_cfg_options(('rpcuser','rpcpassword'))
|
||||
import mmgen.rpc
|
||||
c = mmgen.rpc.BitcoinRPCConnection(
|
||||
g.rpc_host or 'localhost',
|
||||
g.rpc_port or g.ports[g.coin][g.testnet],
|
||||
g.rpc_user or cfg['rpcuser'], # MMGen's rpcuser,rpcpassword override bitcoind's
|
||||
g.rpc_password or cfg['rpcpassword'],
|
||||
auth_cookie=get_bitcoind_auth_cookie())
|
||||
|
||||
if not g.bitcoind_version: # First call
|
||||
g.bitcoind_version = int(c.getnetworkinfo()['version'])
|
||||
g.chain = c.getblockchaininfo()['chain']
|
||||
if g.chain != 'regtest':
|
||||
g.chain += 'net'
|
||||
assert g.chain in g.chains
|
||||
if g.chain == 'mainnet':
|
||||
check_coin_mismatch(c)
|
||||
return c
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue