py3port: remaining changes to modules
This commit is contained in:
parent
59007ee697
commit
9c4d7d725f
14 changed files with 87 additions and 79 deletions
|
|
@ -857,8 +857,8 @@ Record this checksum: it will be used to verify the password file in the future
|
|||
return True
|
||||
|
||||
def scramble_seed(self,seed):
|
||||
# Changing either pw_fmt, pw_len or scramble_key will cause a different,
|
||||
# unrelated set of passwords to be generated: this is what we want.
|
||||
# Changing either pw_fmt or pw_len will cause a different, unrelated
|
||||
# set of passwords to be generated: this is what we want.
|
||||
# NB: In original implementation, pw_id_str was 'baseN', not 'bN'
|
||||
scramble_key = '{}:{}:{}'.format(self.pw_fmt,self.pw_len,self.pw_id_str)
|
||||
from mmgen.crypto import scramble_seed
|
||||
|
|
|
|||
|
|
@ -432,8 +432,6 @@ class CoinInfo(object):
|
|||
line[n] = re.sub(r' ',r'',line[n]) + ('',',')[n != len(line)-1]
|
||||
|
||||
from mmgen.util import pmsg,pdie
|
||||
# pmsg(sym)
|
||||
# pdie(tt)
|
||||
if trust != -1:
|
||||
if sym in tt:
|
||||
src = tt[sym]
|
||||
|
|
@ -501,7 +499,7 @@ class CoinInfo(object):
|
|||
'mainnet': {
|
||||
'pycoin': (
|
||||
# broken: DASH - only compressed, LTC segwit old fmt
|
||||
'BTC','LTC','VIA','FTC','DOGE','MEC','MYR','UNO',
|
||||
'BTC','LTC','VIA','FTC','DOGE','MEC',
|
||||
'JBS','MZC','RIC','DFC','FAI','ARG','ZEC','DCR'),
|
||||
'pyethereum': ('ETH','ETC'),
|
||||
'zcash_mini': ('ZEC',),
|
||||
|
|
|
|||
|
|
@ -122,7 +122,8 @@ class g(object):
|
|||
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','coin','bob','alice','key_generator'
|
||||
'brain_params','b16','usr_randchars','coin','bob','alice','key_generator',
|
||||
'hidden_incog_input_params','in_fmt'
|
||||
)
|
||||
incompatible_opts = (
|
||||
('base32','hex'), # mmgen-passgen
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ def launch(what):
|
|||
what = 'wallet'
|
||||
if what == 'keygen': what = 'addrgen'
|
||||
|
||||
import sys
|
||||
|
||||
try: import termios
|
||||
except: # Windows
|
||||
__import__('mmgen.main_' + what)
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ def do_umount():
|
|||
subprocess.call(['umount',mountpoint])
|
||||
|
||||
def sign_tx_file(txfile):
|
||||
from importlib import reload
|
||||
try:
|
||||
g.testnet = False
|
||||
g.coin = 'BTC'
|
||||
|
|
@ -360,7 +361,7 @@ def do_loop():
|
|||
while True:
|
||||
status = get_insert_status()
|
||||
if status and not prev_status:
|
||||
msg('Device insert detected')
|
||||
msg('Device insertion detected')
|
||||
do_sign()
|
||||
prev_status = status
|
||||
if not n % 10:
|
||||
|
|
|
|||
29
mmgen/obj.py
29
mmgen/obj.py
|
|
@ -139,13 +139,14 @@ class Hilite(object):
|
|||
color_always = False
|
||||
width = 0
|
||||
trunc_ok = True
|
||||
dtype = str
|
||||
|
||||
@classmethod
|
||||
# 'width' is screen width (greater than len(s) for CJK strings)
|
||||
# 'append_chars' and 'encl' must consist of single-width chars only
|
||||
def fmtc(cls,s,width=None,color=False,encl='',trunc_ok=None,
|
||||
center=False,nullrepl='',append_chars='',append_color=False):
|
||||
s = str(s)
|
||||
if cls.dtype == bytes: s = s.decode()
|
||||
s_wide_count = len([1 for ch in s if unicodedata.east_asian_width(ch) in ('F','W')])
|
||||
assert type(encl) is str and len(encl) in (0,2),"'encl' must be 2-character str"
|
||||
a,b = list(encl) if encl else ('','')
|
||||
|
|
@ -168,6 +169,12 @@ class Hilite(object):
|
|||
else:
|
||||
return cls.colorize(s.ljust(width-s_wide_count),color=color)
|
||||
|
||||
@classmethod
|
||||
def colorize(cls,s,color=True):
|
||||
if cls.dtype == bytes: s = s.decode()
|
||||
k = color if type(color) is str else cls.color # hack: override color with str value
|
||||
return globals()[k](s) if (color or cls.color_always) else s
|
||||
|
||||
def fmt(self,*args,**kwargs):
|
||||
assert args == () # forbid invocation w/o keywords
|
||||
return self.fmtc(self,*args,**kwargs)
|
||||
|
|
@ -182,11 +189,6 @@ class Hilite(object):
|
|||
def __str__(self):
|
||||
return self.colorize(self,color=False)
|
||||
|
||||
@classmethod
|
||||
def colorize(cls,s,color=True):
|
||||
k = color if type(color) is str else cls.color # hack: override color with str value
|
||||
return globals()[k](s) if (color or cls.color_always) else s
|
||||
|
||||
# For attrs that are always present in the data instance
|
||||
# Reassignment and deletion forbidden
|
||||
class MMGenImmutableAttr(object): # Descriptor
|
||||
|
|
@ -202,7 +204,8 @@ class MMGenImmutableAttr(object): # Descriptor
|
|||
|
||||
# forbid all reassignment
|
||||
def set_attr_ok(self,instance):
|
||||
return not hasattr(instance,self.name)
|
||||
return not self.name in instance.__dict__
|
||||
# return not hasattr(instance,self.name)
|
||||
|
||||
def __set__(self,instance,value):
|
||||
if not self.set_attr_ok(instance):
|
||||
|
|
@ -624,7 +627,7 @@ class WifKey(str,Hilite,InitErrors):
|
|||
if type(s) == cls: return s
|
||||
cls.arg_chk(cls,on_fail)
|
||||
try:
|
||||
assert set(s) <= set(ascii_letters+digits),'not an ascii string'
|
||||
assert set(s) <= set(ascii_letters+digits),'not an ascii alphanumeric string'
|
||||
from mmgen.globalvars import g
|
||||
g.proto.wif2hex(s) # raises exception on error
|
||||
return str.__new__(cls,s)
|
||||
|
|
@ -643,7 +646,7 @@ class PubKey(HexBytes,MMGenObject): # TODO: add some real checks
|
|||
m = '{!r}: invalid value for pubkey ({})'.format(s,e.args[0])
|
||||
return cls.init_fail(m,on_fail)
|
||||
|
||||
class PrivKey(str,Hilite,InitErrors,MMGenObject):
|
||||
class PrivKey(bytes,Hilite,InitErrors,MMGenObject):
|
||||
|
||||
color = 'red'
|
||||
width = 64
|
||||
|
|
@ -662,9 +665,9 @@ class PrivKey(str,Hilite,InitErrors,MMGenObject):
|
|||
if wif:
|
||||
try:
|
||||
assert s == None
|
||||
assert set(wif) <= set(ascii_letters+digits),'not an ascii string'
|
||||
assert set(wif) <= set(ascii_letters+digits),'not an ascii alphanumeric string'
|
||||
w2h = g.proto.wif2hex(wif) # raises exception on error
|
||||
me = str.__new__(cls,w2h['hex'])
|
||||
me = bytes.__new__(cls,w2h['hex'])
|
||||
me.compressed = w2h['compressed']
|
||||
me.pubkey_type = w2h['pubkey_type']
|
||||
me.wif = str.__new__(WifKey,wif) # check has been done
|
||||
|
|
@ -678,9 +681,9 @@ class PrivKey(str,Hilite,InitErrors,MMGenObject):
|
|||
assert s and type(compressed) == bool and pubkey_type,'Incorrect args for PrivKey()'
|
||||
assert len(s) == cls.width // 2,'Key length must be {}'.format(cls.width/2)
|
||||
if pubkey_type == 'password': # skip WIF creation and pre-processing for passwds
|
||||
me = str.__new__(cls,hexlify(s))
|
||||
me = bytes.__new__(cls,hexlify(s))
|
||||
else:
|
||||
me = str.__new__(cls,g.proto.preprocess_key(hexlify(s),pubkey_type))
|
||||
me = bytes.__new__(cls,g.proto.preprocess_key(hexlify(s),pubkey_type))
|
||||
me.wif = WifKey(g.proto.hex2wif(me,pubkey_type,compressed),on_fail='raise')
|
||||
me.compressed = compressed
|
||||
me.pubkey_type = pubkey_type
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
"""
|
||||
opts.py: MMGen-specific options processing after generic processing by share.Opts
|
||||
"""
|
||||
import sys,os
|
||||
import sys,os,stat
|
||||
|
||||
class opt(object): pass
|
||||
|
||||
|
|
@ -161,10 +161,8 @@ def override_from_cfg_file(cfg_data):
|
|||
else:
|
||||
cls,attr = g,name
|
||||
setattr(cls,attr,set_for_type(val,getattr(cls,attr),attr,src=g.cfg_file))
|
||||
# pmsg(cls,attr,getattr(cls,attr))
|
||||
else:
|
||||
die(2,"'{}': unrecognized option in '{}'".format(name,g.cfg_file))
|
||||
# pdie('xxx')
|
||||
|
||||
def override_from_env():
|
||||
from mmgen.util import set_for_type
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ class BitcoinProtocol(MMGenObject):
|
|||
return '{:064x}'.format(pk % cls.secp256k1_ge).encode()
|
||||
|
||||
@classmethod
|
||||
def hex2wif(cls,hexpriv,pubkey_type,compressed):
|
||||
def hex2wif(cls,hexpriv,pubkey_type,compressed): # PrivKey
|
||||
return _b58chk_encode(cls.wif_ver_num[pubkey_type] + hexpriv + (b'',b'01')[bool(compressed)])
|
||||
|
||||
@classmethod
|
||||
|
|
@ -153,7 +153,7 @@ class BitcoinProtocol(MMGenObject):
|
|||
msg('{}: Invalid witness version number'.format(ret[0]))
|
||||
elif ret[1]:
|
||||
return {
|
||||
'hex': hexlify(''.join(map(chr,ret[1]))),
|
||||
'hex': hexlify(bytes(ret[1])),
|
||||
'format': 'bech32'
|
||||
} if return_dict else True
|
||||
return False
|
||||
|
|
@ -168,7 +168,6 @@ class BitcoinProtocol(MMGenObject):
|
|||
if g.debug: Msg('Address cannot be converted to base 58')
|
||||
break
|
||||
addr_hex = '{:0{}x}'.format(num,len(ver_num)+hex_width+8).encode()
|
||||
# pmsg(hex_width,len(addr_hex),addr_hex[:len(ver_num)],ver_num)
|
||||
if addr_hex[:len(ver_num)] != ver_num: continue
|
||||
if hash256(addr_hex[:-8])[:8] == addr_hex[-8:]:
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ class CoinDaemonRPCConnection(object):
|
|||
for k in cf:
|
||||
if k in kwargs and kwargs[k]: cf[k] = kwargs[k]
|
||||
|
||||
hc = http.client.HTTPConnection(self.host, self.port, False, cf['timeout'])
|
||||
hc = http.client.HTTPConnection(self.host,self.port,cf['timeout'])
|
||||
|
||||
if cf['batch']:
|
||||
p = [{'method':cmd,'params':r,'id':n,'jsonrpc':'2.0'} for n,r in enumerate(args[0],1)]
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ class SeedSource(MMGenObject):
|
|||
|
||||
@classmethod
|
||||
def format_fmt_codes(cls):
|
||||
d = [(c.__name__,('.'+c.ext if c.ext else c.ext),','.join(c.fmt_codes))
|
||||
d = [(c.__name__,('.'+c.ext if c.ext else str(c.ext)),','.join(c.fmt_codes))
|
||||
for c in cls.get_subclasses()
|
||||
if hasattr(c,'fmt_codes')]
|
||||
w = max(len(i[0]) for i in d)
|
||||
|
|
@ -414,16 +414,15 @@ class Mnemonic (SeedSourceUnenc):
|
|||
idx = bisect_left(wl,w)
|
||||
return(True,False)[idx == len(wl) or w != wl[idx]]
|
||||
|
||||
words,i,p = [],0,('Enter word #{}: ','Incorrect entry. Repeat word #{}: ')
|
||||
p = ('Enter word #{}: ','Incorrect entry. Repeat word #{}: ')
|
||||
words,err = [],0
|
||||
while len(words) < mn_len:
|
||||
msg_r('{r}{s}{r}'.format(r='\r',s=' '*40))
|
||||
if i == 1: time.sleep(0.1)
|
||||
msg_r(p[i].format(len(words)+1))
|
||||
if err == 1: time.sleep(0.1)
|
||||
msg_r(p[err].format(len(words)+1))
|
||||
s = get_word()
|
||||
if in_list(s):
|
||||
words.append(s); i = 0
|
||||
else:
|
||||
i = 1
|
||||
if in_list(s): words.append(s)
|
||||
err = (1,0)[in_list(s)]
|
||||
msg('')
|
||||
qmsg('Mnemonic successfully entered')
|
||||
return ' '.join(words)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ Opts.py: Generic options handling
|
|||
|
||||
import sys,getopt
|
||||
import collections
|
||||
# from mmgen.util import mdie,die,pdie,pmsg # DEBUG
|
||||
|
||||
def usage(opts_data):
|
||||
print(('USAGE: {} {}'.format(opts_data['prog_name'], opts_data['usage'])))
|
||||
|
|
@ -56,7 +55,8 @@ def process_opts(argv,opts_data,short_opts,long_opts,skip_help=False):
|
|||
so_str = short_opts.replace('-:','').replace('-','')
|
||||
try: cl_opts,args = getopt.getopt(argv[1:], so_str, long_opts)
|
||||
except getopt.GetoptError as err:
|
||||
print((str(err))); sys.exit(2)
|
||||
print(str(err))
|
||||
sys.exit(2)
|
||||
|
||||
sopts_list = ':_'.join(['_'.join(list(i)) for i in short_opts.split(':')]).split('_')
|
||||
opts,skipped_help = {},False
|
||||
|
|
|
|||
|
|
@ -22,17 +22,16 @@ tool.py: Routines and data for the 'mmgen-tool' utility
|
|||
"""
|
||||
|
||||
import binascii
|
||||
from collections import OrderedDict
|
||||
|
||||
from mmgen.protocol import hash160
|
||||
from mmgen.common import *
|
||||
from mmgen.crypto import *
|
||||
from mmgen.tx import *
|
||||
from mmgen.addr import *
|
||||
from decimal import Decimal
|
||||
|
||||
pnm = g.proj_name
|
||||
|
||||
from collections import OrderedDict
|
||||
cmd_data = OrderedDict([
|
||||
('Help', ['<tool command> [str]']),
|
||||
('Usage', ['<tool command> [str]']),
|
||||
|
|
@ -194,7 +193,7 @@ def process_args(command,cmd_args):
|
|||
usage(command)
|
||||
|
||||
def conv_type(arg,arg_name,arg_type):
|
||||
if arg_type == 'str': arg_type = 'unicode'
|
||||
if arg_type == 'bytes': pdie(arg,arg_name,arg_type)
|
||||
if arg_type == 'bool':
|
||||
if arg.lower() in ('true','yes','1','on'): arg = True
|
||||
elif arg.lower() in ('false','no','0','off'): arg = False
|
||||
|
|
@ -246,8 +245,9 @@ def Unhexdump(infile):
|
|||
if g.platform == 'win':
|
||||
import msvcrt
|
||||
msvcrt.setmode(sys.stdout.fileno(),os.O_BINARY)
|
||||
sys.stdout.write(decode_pretty_hexdump(
|
||||
get_data_from_file(infile,dash=True,silent=True)))
|
||||
hexdata = get_data_from_file(infile,dash=True,silent=True)
|
||||
ret = decode_pretty_hexdump(hexdata)
|
||||
os.write(g.stdout_fileno,ret)
|
||||
|
||||
def B58randenc():
|
||||
r = get_random(32)
|
||||
|
|
@ -594,7 +594,8 @@ def monero_wallet_ops(infile,op,blockheight=None,addrs=None):
|
|||
msg(' Wallet in sync')
|
||||
b = [l for l in p.before.decode().splitlines() if len(l) > 7 and l[:8] == 'Balance:'][0].split()
|
||||
msg(' Balance: {} Unlocked balance: {}'.format(b[1],b[4]))
|
||||
bals[fn] = ( Decimal(b[1][:-1]), Decimal(b[4]) )
|
||||
from mmgen.obj import XMRAmt
|
||||
bals[fn] = ( XMRAmt(b[1][:-1]), XMRAmt(b[4]) )
|
||||
my_sendline(p,'Exiting','exit',5)
|
||||
p.read()
|
||||
break
|
||||
|
|
@ -626,8 +627,8 @@ def monero_wallet_ops(infile,op,blockheight=None,addrs=None):
|
|||
col1_w = max(list(map(len,bals))) + 1
|
||||
fs = '{:%s} {} {}' % col1_w
|
||||
msg('\n'+fs.format('Wallet','Balance ','Unlocked Balance '))
|
||||
tbals = [Decimal('0'),Decimal('0')]
|
||||
from mmgen.obj import XMRAmt
|
||||
tbals = [XMRAmt('0'),XMRAmt('0')]
|
||||
for bal in bals:
|
||||
for i in (0,1): tbals[i] += bals[bal][i]
|
||||
msg(fs.format(bal+':',*[XMRAmt(b).fmt(fs='5.12',color=True) for b in bals[bal]]))
|
||||
|
|
@ -655,7 +656,7 @@ def monero_wallet_ops(infile,op,blockheight=None,addrs=None):
|
|||
|
||||
# ================ RPC commands ================== #
|
||||
|
||||
def Gen_addr(addr,wallet='',target='addr'):
|
||||
def Gen_addr(addr,wallet='',target='addr',return_result=False):
|
||||
addr = MMGenID(addr)
|
||||
sf = get_seed_file([wallet] if wallet else [],1)
|
||||
opt.quiet = True
|
||||
|
|
@ -666,7 +667,9 @@ def Gen_addr(addr,wallet='',target='addr'):
|
|||
die(1,m.format(addr.sid,ss.seed.sid))
|
||||
al = AddrList(seed=ss.seed,addr_idxs=AddrIdxList(str(addr.idx)),mmtype=addr.mmtype,do_chksum=False)
|
||||
d = al.data[0]
|
||||
Msg(d.sec.wif if target=='wif' else d.addr)
|
||||
ret = d.sec.wif if target=='wif' else d.addr
|
||||
if return_result: return ret
|
||||
else: Msg(ret)
|
||||
|
||||
def Gen_key(addr,wallet=''):
|
||||
return Gen_addr(addr,wallet,target='wif')
|
||||
|
|
|
|||
55
mmgen/tx.py
55
mmgen/tx.py
|
|
@ -55,12 +55,12 @@ def strfmt_locktime(num,terse=False):
|
|||
# If greater than or equal to 500 million, locktime is parsed using the Unix epoch time
|
||||
# format (the number of seconds elapsed since 1970-01-01T00:00 UTC). The transaction can be
|
||||
# added to any block whose block time is greater than the locktime.
|
||||
if num >= 5 * 10**6:
|
||||
if num == None:
|
||||
return '(None)'
|
||||
elif num >= 5 * 10**6:
|
||||
return ' '.join(time.strftime('%c',time.gmtime(num)).split()[1:])
|
||||
elif num > 0:
|
||||
return '{}{}'.format(('block height ','')[terse],num)
|
||||
elif num == None:
|
||||
return '(None)'
|
||||
else:
|
||||
die(2,"'{}': invalid locktime value!".format(num))
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ def segwit_is_active(exit_on_error=False):
|
|||
|
||||
def bytes2int(hex_bytes):
|
||||
r = hexlify(unhexlify(hex_bytes)[::-1])
|
||||
if r[0] in b'89abcdef':
|
||||
if hexlify(bytes([r[0]])) in b'89abcdef':
|
||||
die(3,"{}: Negative values not permitted in transaction!".format(hex_bytes))
|
||||
return int(r,16)
|
||||
|
||||
|
|
@ -120,35 +120,36 @@ class DeserializedTX(OrderedDict,MMGenObject): # need to add MMGen types
|
|||
def __init__(self,txhex):
|
||||
tx = list(unhexlify(txhex))
|
||||
tx_copy = tx[:]
|
||||
d = { 'raw_tx':'' }
|
||||
d = { 'raw_tx': [] }
|
||||
|
||||
def hshift(l,n,reverse=False,skip=False):
|
||||
ret = l[:n]
|
||||
if not skip: d['raw_tx'] += ''.join(ret)
|
||||
if not skip: d['raw_tx'] += ret
|
||||
del l[:n]
|
||||
return hexlify(''.join(ret[::-1] if reverse else ret))
|
||||
return hexlify(bytes(ret[::-1] if reverse else ret))
|
||||
|
||||
# https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers
|
||||
# For example, the number 515 is encoded as 0xfd0302.
|
||||
def readVInt(l,skip=False,sub_null=False):
|
||||
s = int(hexlify(l[0]),16)
|
||||
s = l[0]
|
||||
bytes_len = 1 if s < 0xfd else 2 if s == 0xfd else 4 if s == 0xfe else 8
|
||||
if bytes_len != 1: del l[0]
|
||||
ret = int(hexlify(''.join(l[:bytes_len][::-1])),16)
|
||||
ret = int(hexlify(bytes(l[:bytes_len][::-1])),16)
|
||||
if sub_null: d['raw_tx'] += b'\0'
|
||||
elif not skip: d['raw_tx'] += ''.join(l[:bytes_len])
|
||||
elif not skip: d['raw_tx'] += l[:bytes_len]
|
||||
del l[:bytes_len]
|
||||
return ret
|
||||
|
||||
d['version'] = bytes2int(hshift(tx,4))
|
||||
has_witness = tx[0] == '\x00'
|
||||
has_witness = tx[0] == 0
|
||||
if has_witness:
|
||||
u = hshift(tx,2,skip=True)[2:]
|
||||
if u != '01':
|
||||
u = hshift(tx,2,skip=True)
|
||||
if u != b'0001':
|
||||
raise IllegalWitnessFlagValue("'{}': Illegal value for flag in transaction!".format(u))
|
||||
del tx_copy[-len(tx)-2:-len(tx)]
|
||||
|
||||
d['num_txins'] = readVInt(tx)
|
||||
|
||||
d['txins'] = MMGenList([OrderedDict((
|
||||
('txid', hshift(tx,32,reverse=True)),
|
||||
('vout', bytes2int(hshift(tx,4))),
|
||||
|
|
@ -174,7 +175,7 @@ class DeserializedTX(OrderedDict,MMGenObject): # need to add MMGen types
|
|||
wd,tx = tx[:-4],tx[-4:]
|
||||
d['witness_size'] = len(wd) + 2 # add marker and flag
|
||||
for i in range(len(d['txins'])):
|
||||
if hexlify(wd[0]) == '00':
|
||||
if wd[0] == 0:
|
||||
hshift(wd,1,skip=True)
|
||||
continue
|
||||
d['txins'][i]['witness'] = [
|
||||
|
|
@ -184,12 +185,12 @@ class DeserializedTX(OrderedDict,MMGenObject): # need to add MMGen types
|
|||
raise WitnessSizeMismatch('More witness data than inputs with witnesses!')
|
||||
|
||||
d['lock_time'] = bytes2int(hshift(tx,4))
|
||||
d['txid'] = hexlify(sha256(sha256(''.join(tx_copy)).digest()).digest()[::-1])
|
||||
d['unsigned_hex'] = hexlify(d['raw_tx'])
|
||||
d['txid'] = hexlify(sha256(sha256(bytes(tx_copy)).digest()).digest()[::-1])
|
||||
d['unsigned_hex'] = hexlify(bytes(d['raw_tx']))
|
||||
del d['raw_tx']
|
||||
|
||||
keys = 'txid','version','lock_time','witness_size','num_txins','txins','num_txouts','txouts','unsigned_hex'
|
||||
return OrderedDict.__init__(self, ((k,d[k]) for k in keys))
|
||||
OrderedDict.__init__(self, ((k,d[k]) for k in keys))
|
||||
|
||||
txio_attrs = {
|
||||
'vout': MMGenListItemAttr('vout',int,typeconv=False),
|
||||
|
|
@ -315,8 +316,11 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
|
|||
self.outputs.append(MMGenTX.MMGenTxOutput(addr=coinaddr,amt=amt,is_chg=is_chg))
|
||||
|
||||
def get_chg_output_idx(self):
|
||||
try: return map(lambda x: x.is_chg,self.outputs).index(True)
|
||||
except ValueError: return None
|
||||
ch_ops = [x.is_chg for x in self.outputs]
|
||||
try:
|
||||
return ch_ops.index(True)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
def update_output_amt(self,idx,amt):
|
||||
o = self.outputs[idx].__dict__
|
||||
|
|
@ -352,13 +356,9 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
|
|||
|
||||
def check_dup_addrs(self,io_str):
|
||||
assert io_str in ('inputs','outputs')
|
||||
io = getattr(self,io_str)
|
||||
for k in ('mmid','addr'):
|
||||
old_attr = None
|
||||
for attr in sorted(getattr(e,k) for e in io):
|
||||
if attr != None and attr == old_attr:
|
||||
die(2,'{}: duplicate address in transaction {}'.format(attr,io_str))
|
||||
old_attr = attr
|
||||
addrs = [e.addr for e in getattr(self,io_str)]
|
||||
if len(addrs) != len(set(addrs)):
|
||||
die(2,'{}: duplicate address in transaction {}'.format(attr,io_str))
|
||||
|
||||
def update_txid(self):
|
||||
self.txid = MMGenTxID(make_chksum_6(unhexlify(self.hex)).upper())
|
||||
|
|
@ -740,6 +740,9 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
|
|||
msg('OK')
|
||||
return True
|
||||
except Exception as e:
|
||||
if os.getenv('MMGEN_TRACEBACK'):
|
||||
import traceback
|
||||
ymsg('\n'+''.join(traceback.format_exception(*sys.exc_info())))
|
||||
try: m = '{}'.format(e.args[0])
|
||||
except: m = repr(e.args[0])
|
||||
msg('\n'+yellow(m))
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ util.py: Low-level routines imported by other modules in the MMGen suite
|
|||
import sys,os,time,stat,re,unicodedata
|
||||
from hashlib import sha256
|
||||
from binascii import hexlify,unhexlify
|
||||
from string import hexdigits
|
||||
from string import hexdigits,digits
|
||||
from mmgen.color import *
|
||||
from mmgen.exception import *
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ def Die(ev=0,s=''):
|
|||
|
||||
def rdie(ev=0,s=''): die(ev,red(s))
|
||||
def ydie(ev=0,s=''): die(ev,yellow(s))
|
||||
def hi(): sys.stdout.write(yellow('hi'))
|
||||
def hi(): ymsg('hi')
|
||||
|
||||
def pformat(d):
|
||||
import pprint
|
||||
|
|
@ -122,7 +122,7 @@ def check_or_create_dir(path):
|
|||
os.listdir(path)
|
||||
except:
|
||||
try:
|
||||
os.makedirs(path,0o700)
|
||||
os.makedirs(path,stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR)
|
||||
except:
|
||||
die(2,"ERROR: unable to read or create path '{}'".format(path))
|
||||
|
||||
|
|
@ -232,6 +232,7 @@ def secs_to_hms(secs):
|
|||
def secs_to_ms(secs):
|
||||
return '{:02d}:{:02d}'.format(secs//60, secs % 60)
|
||||
|
||||
def is_digits(s): return set(list(s)) <= set(list(digits))
|
||||
def is_int(s):
|
||||
try:
|
||||
int(str(s))
|
||||
|
|
@ -431,7 +432,7 @@ def compare_chksums(chk1,desc1,chk2,desc2,hdr='',die_on_fail=False,verbose=False
|
|||
return True
|
||||
|
||||
def compare_or_die(val1, desc1, val2, desc2, e='Error'):
|
||||
if cmp(val1,val2):
|
||||
if val1 != val2:
|
||||
die(3,"{}: {} ({}) doesn't match {} ({})".format(e,desc2,val2,desc1,val1))
|
||||
dmsg('{} OK ({})'.format(capfirst(desc2),val2))
|
||||
return True
|
||||
|
|
@ -740,8 +741,8 @@ def keypress_confirm(prompt,default_yes=False,verbose=False,no_nl=False):
|
|||
return (False,True)[default_yes]
|
||||
|
||||
while True:
|
||||
reply = get_char(p).strip(b'\n\r')
|
||||
if not reply:
|
||||
r = get_char(p).strip(b'\n\r')
|
||||
if not r:
|
||||
if default_yes: msg_r(nl); return True
|
||||
else: msg_r(nl); return False
|
||||
elif r in b'yY': msg_r(nl); return True
|
||||
|
|
@ -812,7 +813,7 @@ def get_daemon_cfg_options(cfg_keys):
|
|||
cfg_file = os.path.join(g.proto.daemon_data_dir,g.proto.name+'.conf')
|
||||
try:
|
||||
lines = get_lines_from_file(cfg_file,'',silent=bool(opt.quiet))
|
||||
kv_pairs = [split2(str(line).translate(None,'\t '),'=') for line in lines]
|
||||
kv_pairs = [l.split('=') for l in lines]
|
||||
cfg = dict([(k,v) for k,v in kv_pairs if k in cfg_keys])
|
||||
except:
|
||||
vmsg("Warning: '{}' does not exist or is unreadable".format(cfg_file))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue