From e9385725cff80f6b06e899943a49f6b783eb329c Mon Sep 17 00:00:00 2001 From: MMGen Date: Mon, 5 Mar 2018 06:29:20 +0000 Subject: [PATCH] Add g.proto.witness_ver_num, minor fixes and changes --- mmgen/addr.py | 26 ++++++------ mmgen/crypto.py | 4 +- mmgen/globalvars.py | 6 +++ mmgen/main_tool.py | 6 +-- mmgen/obj.py | 6 ++- mmgen/opts.py | 5 ++- mmgen/protocol.py | 16 +++++--- mmgen/rpc.py | 17 ++++---- mmgen/tx.py | 18 ++++----- mmgen/util.py | 4 +- test/mmgen_pexpect.py | 7 +++- test/test.py | 93 ++++++++++++++++++++++++++----------------- 12 files changed, 121 insertions(+), 87 deletions(-) diff --git a/mmgen/addr.py b/mmgen/addr.py index 87f00b33..41caf305 100755 --- a/mmgen/addr.py +++ b/mmgen/addr.py @@ -27,9 +27,8 @@ from mmgen.obj import * pnm = g.proj_name -def sc_dmsg(desc,data): - if os.getenv('MMGEN_DEBUG_ADDRLIST'): - Msg('sc_debug_{}: {}'.format(desc,data)) +def dmsg_sc(desc,data): + if g.debug_addrlist: Msg('sc_debug_{}: {}'.format(desc,data)) class AddrGenerator(MMGenObject): def __new__(cls,addr_type): @@ -45,8 +44,7 @@ class AddrGenerator(MMGenObject): 'segwit': AddrGeneratorSegwit, 'ethereum': AddrGeneratorEthereum, 'zcash_z': AddrGeneratorZcashZ, - 'monero': AddrGeneratorMonero - } + 'monero': AddrGeneratorMonero} assert gen_method in gen_methods me = super(cls,cls).__new__(gen_methods[gen_method]) me.desc = gen_methods @@ -59,7 +57,7 @@ class AddrGeneratorP2PKH(AddrGenerator): return CoinAddr(g.proto.pubhash2addr(hash160(pubhex),p2sh=False)) def to_segwit_redeem_script(self,pubhex): - raise NotImplementedError,'Coin/type pair incompatible with Segwit' + raise NotImplementedError,'Segwit redeem script not supported by this address type' class AddrGeneratorSegwit(AddrGenerator): def to_addr(self,pubhex): @@ -77,7 +75,7 @@ class AddrGeneratorEthereum(AddrGenerator): return CoinAddr(sha3.keccak_256(pubhex[2:].decode('hex')).digest()[12:].encode('hex')) def to_segwit_redeem_script(self,pubhex): - raise NotImplementedError,'Coin/type pair incompatible with Segwit' + raise NotImplementedError,'Segwit redeem script not supported by this address type' # github.com/FiloSottile/zcash-mini/zcash/address.go class AddrGeneratorZcashZ(AddrGenerator): @@ -197,7 +195,7 @@ class KeyGenerator(MMGenObject): def test_for_secp256k1(self,silent=False): try: from mmgen.secp256k1 import priv2pub - assert priv2pub(os.urandom(32),1) + assert priv2pub(('deadbeef'*8).decode('hex'),1) return True except: return False @@ -303,7 +301,7 @@ class AddrListIDStr(unicode,Hilite): bc = (g.proto.base_coin,g.coin)[g.proto.base_coin=='ETH'] mt = addrlist.al_id.mmtype ret = '{}{}{}[{}]'.format(addrlist.al_id.sid,('-'+bc,'')[bc=='BTC'],('-'+mt,'')[mt in ('L','E')],s) - sc_dmsg('id_str',ret[8:].split('[')[0]) + dmsg_sc('id_str',ret[8:].split('[')[0]) return unicode.__new__(cls,ret) @@ -397,7 +395,7 @@ Removed %s duplicate WIF key%s from keylist (also in {pnm} key-address file seed = seed.get_data() seed = self.scramble_seed(seed) - sc_dmsg('seed',seed[:8].encode('hex')) + dmsg_sc('seed',seed[:8].encode('hex')) compressed = self.al_id.mmtype.compressed pubkey_type = self.al_id.mmtype.pubkey_type @@ -441,7 +439,7 @@ Removed %s duplicate WIF key%s from keylist (also in {pnm} key-address file dmsg('Key {:>03}: {}'.format(pos,e.passwd)) out.append(e) - if g.debug: Msg('generate():\n', e.pformat()) + if g.debug: Msg('generate():\n{}'.format(e.pformat())) qmsg('\r%s: %s %s%s generated%s' % ( self.al_id.hl(),t_addrs,self.gen_desc,suf(t_addrs,self.gen_desc_pl),' '*15)) @@ -452,13 +450,13 @@ Removed %s duplicate WIF key%s from keylist (also in {pnm} key-address file def scramble_seed(self,seed): is_btcfork = g.proto.base_coin == 'BTC' if is_btcfork and self.al_id.mmtype == 'L': - sc_dmsg('str','(none)') + dmsg_sc('str','(none)') return seed if g.proto.base_coin == 'ETH': scramble_key = g.coin.lower() else: scramble_key = (g.coin.lower()+':','')[is_btcfork] + self.al_id.mmtype.name - sc_dmsg('str',scramble_key) + dmsg_sc('str',scramble_key) from mmgen.crypto import scramble_seed return scramble_seed(seed,scramble_key,self.scramble_hash_rounds) @@ -559,7 +557,7 @@ Removed %s duplicate WIF key%s from keylist (also in {pnm} key-address file lbl_p2 = ':'.join(l_coin+l_type) lbl = self.al_id.sid + ('',' ')[bool(lbl_p2)] + lbl_p2 - sc_dmsg('lbl',lbl[9:]) + dmsg_sc('lbl',lbl[9:]) out.append(u'{} {{'.format(lbl)) fs = ' {:<%s} {:<34}{}' % len(str(self.data[-1].idx)) diff --git a/mmgen/crypto.py b/mmgen/crypto.py index 4ec44564..2bcd9749 100755 --- a/mmgen/crypto.py +++ b/mmgen/crypto.py @@ -45,8 +45,8 @@ def sha256_rounds(s,n): def scramble_seed(seed,scramble_key,hash_rounds): import hmac scr_seed = hmac.new(seed,scramble_key,sha256).digest() - fs = 'Seed: {}\nScramble key: {}\nScrambled seed: {}\nScrambled seed len: {}' - dmsg(fs.format(hexlify(seed),scramble_key,hexlify(scr_seed),len(scr_seed))) + fs = 'Seed: {}\nScramble key: {}\nScrambled seed: {}' + dmsg(fs.format(hexlify(seed),scramble_key,hexlify(scr_seed))) return sha256_rounds(scr_seed,hash_rounds) def encrypt_seed(seed,key): diff --git a/mmgen/globalvars.py b/mmgen/globalvars.py index 01402493..9fd85d35 100755 --- a/mmgen/globalvars.py +++ b/mmgen/globalvars.py @@ -66,6 +66,9 @@ class g(object): coin = 'BTC' debug = False + debug_opts = False + debug_rpc = False + debug_addrlist = False quiet = False no_license = False hold_protect = True @@ -136,6 +139,9 @@ class g(object): env_opts = ( 'MMGEN_BOGUS_WALLET_DATA', 'MMGEN_DEBUG', + 'MMGEN_DEBUG_OPTS', + 'MMGEN_DEBUG_RPC', + 'MMGEN_DEBUG_ADDRLIST', 'MMGEN_QUIET', 'MMGEN_DISABLE_COLOR', 'MMGEN_FORCE_256_COLOR', diff --git a/mmgen/main_tool.py b/mmgen/main_tool.py index 105baf67..0ebdf80a 100755 --- a/mmgen/main_tool.py +++ b/mmgen/main_tool.py @@ -36,9 +36,9 @@ Cryptocoin address/key operations (compressed public keys supported): privhex2addr - generate coin address from private key in hex format privhex2pubhex - generate a hex public key from a hex private key pubhex2addr - convert a hex pubkey to an address - pubhex2redeem_script - convert a hex pubkey to a witness redeem script - wif2redeem_script - convert a WIF private key to a witness redeem script - wif2segwit_pair - generate both a Segwit redeem script and address from WIF + pubhex2redeem_script - convert a hex pubkey to a Segwit P2SH-P2WPKH redeem script + wif2redeem_script - convert a WIF private key to a Segwit P2SH-P2WPKH redeem script + wif2segwit_pair - generate both a Segwit P2SH-P2WPKH redeem script and address from WIF pubkey2addr - convert coin public key to address randpair - generate a random private key/address pair randwif - generate a random private key in WIF format diff --git a/mmgen/obj.py b/mmgen/obj.py index 1b175f21..ada0152b 100755 --- a/mmgen/obj.py +++ b/mmgen/obj.py @@ -383,8 +383,6 @@ class CoinAddr(str,Hilite,InitErrors,MMGenObject): return Hilite.fmtc(s,**kwargs) def is_for_chain(self,chain): - from mmgen.globalvars import g - vn = g.proto.get_protocol_by_chain(chain).addr_ver_num def pfx_ok(pfx): if type(pfx) == tuple: @@ -392,6 +390,10 @@ class CoinAddr(str,Hilite,InitErrors,MMGenObject): elif self[:len(pfx)] == pfx: return True return False + from mmgen.globalvars import g + proto = g.proto.get_protocol_by_chain(chain) + vn = proto.addr_ver_num + if self.addr_fmt == 'p2sh' and 'p2sh2' in vn: return pfx_ok(vn['p2sh'][1]) or pfx_ok(vn['p2sh2'][1]) else: diff --git a/mmgen/opts.py b/mmgen/opts.py index f47dafb0..21da78cb 100755 --- a/mmgen/opts.py +++ b/mmgen/opts.py @@ -224,7 +224,7 @@ def init(opts_f,add_opts=[],opt_filter=None): uopts,args,short_opts,long_opts,skipped_opts,do_help = \ mmgen.share.Opts.parse_opts(sys.argv,opts_data,opt_filter=opt_filter,defer_help=True) - if g.debug: opt_preproc_debug(short_opts,long_opts,skipped_opts,uopts,args) + if g.debug_opts: opt_preproc_debug(short_opts,long_opts,skipped_opts,uopts,args) # Save this for usage() global usage_txt @@ -292,6 +292,7 @@ def init(opts_f,add_opts=[],opt_filter=None): if g.bob or g.alice: g.testnet = True + g.regtest = True g.proto = CoinProtocol(g.coin,g.testnet) g.data_dir = os.path.join(g.data_dir_root,'regtest',g.coin.lower(),('alice','bob')[g.bob]) check_or_create_dir(g.data_dir) @@ -309,7 +310,7 @@ def init(opts_f,add_opts=[],opt_filter=None): ymsg("Warning: config file options have changed! See '{}' for details".format(g.cfg_file+'.sample')) my_raw_input('Hit ENTER to continue: ') - if g.debug: opt_postproc_debug() + if g.debug_opts: opt_postproc_debug() # We don't need this data anymore del mmgen.share.Opts diff --git a/mmgen/protocol.py b/mmgen/protocol.py index 1604759a..a2332d51 100755 --- a/mmgen/protocol.py +++ b/mmgen/protocol.py @@ -83,10 +83,14 @@ class BitcoinProtocol(MMGenObject): (478559,'00000000000000000019f112ec0a9982926f1258cdcc558dd7c3b7e5dc7fa148','bch',False), (None,'','b2x',True) ] - caps = ('rbf','segwit') - mmcaps = ('key','addr','rpc','tx') - base_coin = 'BTC' - addr_width = 34 + caps = ('rbf','segwit') + mmcaps = ('key','addr','rpc','tx') + base_coin = 'BTC' + addr_width = 34 + # From BIP173: witness version 'n' is stored as 'OP_n'. OP_0 is encoded as 0x00, + # but OP_1 through OP_16 are encoded as 0x51 though 0x60 (81 to 96 in decimal). + witness_vernum_hex = '00' + witness_vernum = int(witness_vernum_hex,16) @staticmethod def get_protocol_by_chain(chain): @@ -147,7 +151,7 @@ class BitcoinProtocol(MMGenObject): else: if g.debug: Msg('Invalid checksum in address') break - if g.debug: Msg("Invalid address '{}'".format(addr)) + return False @classmethod @@ -163,7 +167,7 @@ class BitcoinProtocol(MMGenObject): # https://bitcoincore.org/en/segwit_wallet_dev/ # The P2SH redeemScript is always 22 bytes. It starts with a OP_0, followed # by a canonical push of the keyhash (i.e. 0x0014{20-byte keyhash}) - return '0014' + hash160(pubhex) + return cls.witness_vernum_hex + '14' + hash160(pubhex) @classmethod def pubhex2segwitaddr(cls,pubhex): diff --git a/mmgen/rpc.py b/mmgen/rpc.py index 5db1381b..cb60b5de 100755 --- a/mmgen/rpc.py +++ b/mmgen/rpc.py @@ -25,14 +25,17 @@ import httplib,base64,json from mmgen.common import * from decimal import Decimal +def dmsg_rpc(s): + if g.debug_rpc: msg(s) + class RPCFailure(Exception): pass class CoinDaemonRPCConnection(object): def __init__(self,host=None,port=None,user=None,passwd=None,auth_cookie=None): - dmsg('=== CoinDaemonRPCConnection.__init__() debug ===') - dmsg(' host [{}] port [{}] user [{}] passwd [{}] auth_cookie [{}]\n'.format( + dmsg_rpc('=== CoinDaemonRPCConnection.__init__() debug ===') + dmsg_rpc(' host [{}] port [{}] user [{}] passwd [{}] auth_cookie [{}]\n'.format( host,port,user,passwd,auth_cookie)) import socket @@ -98,8 +101,8 @@ class CoinDaemonRPCConnection(object): elif cf['on_fail'] == 'die': die(args[1],yellow(s)) - dmsg('=== request() debug ===') - dmsg(' RPC POST data ==> %s\n' % p) + dmsg_rpc('=== request() debug ===') + dmsg_rpc(' RPC POST data ==> %s\n' % p) caller = self class MyJSONEncoder(json.JSONEncoder): def default(self, obj): @@ -112,7 +115,7 @@ class CoinDaemonRPCConnection(object): # dump = json.dumps(p,cls=MyJSONEncoder,ensure_ascii=False) # print(dump) - dmsg(' RPC AUTHORIZATION data ==> raw: [{}]\n{}enc: [Basic {}]\n'.format( + dmsg_rpc(' RPC AUTHORIZATION data ==> raw: [{}]\n{}enc: [Basic {}]\n'.format( self.auth_str,' '*31,base64.b64encode(self.auth_str))) try: hc.request('POST', '/', json.dumps(p,cls=MyJSONEncoder), { @@ -129,7 +132,7 @@ class CoinDaemonRPCConnection(object): m = 'Unable to connect to {} at {}:{} (but port is bound?)' return do_fail(None,2,m.format(g.proto.daemon_name,self.host,self.port)) - dmsg(' RPC GETRESPONSE data ==> %s\n' % r.__dict__) + dmsg_rpc(' RPC GETRESPONSE data ==> %s\n' % r.__dict__) if r.status != 200: if cf['on_fail'] not in ('silent','raise'): @@ -145,7 +148,7 @@ class CoinDaemonRPCConnection(object): r2 = r.read() - dmsg(' RPC REPLY data ==> %s\n' % r2) + dmsg_rpc(' RPC REPLY data ==> %s\n' % r2) if not r2: return do_fail(r,2,'Error: empty reply') diff --git a/mmgen/tx.py b/mmgen/tx.py index 9481a4fe..e4461cf8 100755 --- a/mmgen/tx.py +++ b/mmgen/tx.py @@ -131,10 +131,12 @@ def bytes2coin_amt(hex_bytes): return g.proto.coin_amt(bytes2int(hex_bytes) * g.proto.coin_amt.min_coin_unit) def scriptPubKey2addr(s): - if len(s) == 50 and s[:6] == '76a914' and s[-4:] == '88ac': addr_hex,p2sh = s[6:-4],False - elif len(s) == 46 and s[:4] == 'a914' and s[-2:] == '87': addr_hex,p2sh = s[4:-2],True - else: raise NotImplementedError,'Unknown scriptPubKey' - return g.proto.pubhash2addr(addr_hex,p2sh) + if len(s) == 50 and s[:6] == '76a914' and s[-4:] == '88ac': + return g.proto.pubhash2addr(s[6:-4],p2sh=False) + elif len(s) == 46 and s[:4] == 'a914' and s[-2:] == '87': + return g.proto.pubhash2addr(s[4:-2],p2sh=True) + else: + raise NotImplementedError,'Unknown scriptPubKey ({})'.format(s) from collections import OrderedDict class DeserializedTX(OrderedDict,MMGenObject): # need to add MMGen types @@ -162,7 +164,7 @@ class DeserializedTX(OrderedDict,MMGenObject): # need to add MMGen types return ret d['version'] = bytes2int(hshift(tx,4)) - has_witness = (False,True)[hexlify(tx[0])=='00'] + has_witness = tx[0] == '\x00' if has_witness: u = hshift(tx,2,skip=True)[2:] if u != '01': @@ -383,7 +385,7 @@ class MMGenTX(MMGenObject): # serialization, divide the result by 4 and round up to the next integer. # TODO: results differ slightly from actual transaction size - def estimate_vsize(self): + def estimate_size(self): if not self.inputs or not self.outputs: return None sig_size = 72 # sig in DER format @@ -439,8 +441,6 @@ class MMGenTX(MMGenObject): # pmsg('estimate_size_old',self.estimate_size_old()) return ret - estimate_size = estimate_vsize - def get_fee(self): return self.sum_inputs() - self.sum_outputs() @@ -609,8 +609,6 @@ class MMGenTX(MMGenObject): msg_r('Signing transaction{}...'.format(tx_num_str)) wifs = [d.sec.wif for d in keys] -# keys.pmsg() -# pmsg(wifs) ret = g.rpch.signrawtransaction(self.hex,sig_data,wifs,g.proto.sighash_type,on_fail='return') from mmgen.rpc import rpc_error,rpc_errmsg diff --git a/mmgen/util.py b/mmgen/util.py index e382f967..4f673d78 100755 --- a/mmgen/util.py +++ b/mmgen/util.py @@ -70,10 +70,10 @@ def pformat(d): return pprint.PrettyPrinter(indent=4).pformat(d) def pmsg(*args): if not args: return - Msg(pformat(args if len(args) > 1 else args[0])) + msg(pformat(args if len(args) > 1 else args[0])) def pdie(*args): if not args: sys.exit(1) - Die(1,(pformat(args if len(args) > 1 else args[0]))) + die(1,(pformat(args if len(args) > 1 else args[0]))) def set_for_type(val,refval,desc,invert_bool=False,src=None): src_str = (''," in '{}'".format(src))[bool(src)] diff --git a/test/mmgen_pexpect.py b/test/mmgen_pexpect.py index d067874b..20e73fe4 100755 --- a/test/mmgen_pexpect.py +++ b/test/mmgen_pexpect.py @@ -235,8 +235,11 @@ class MMGenPexpect(object): self.expect("Overwrite? Type uppercase 'YES' to confirm: ",'\n') self.expect('Exiting at user request') - def tx_view(self): - my_expect(self.p,r'View .*?transaction.*? \(y\)es, \(N\)o, pager \(v\)iew.*?: ','\n',regex=True) + def tx_view(self,view=None): + repl = { 'terse':'t', 'full':'v' }[view] if view else 'n' + my_expect(self.p,r'View .*?transaction.*? \(y\)es, \(N\)o, pager \(v\)iew.*?: ',repl,regex=True) + if repl in ('t','v'): + my_expect(self.p,r'any key to continue: ','\n') def expect_getend(self,s,regex=False): ret = self.expect(s,regex=regex,nonl=True) diff --git a/test/test.py b/test/test.py index b29cc85c..de21004d 100755 --- a/test/test.py +++ b/test/test.py @@ -177,8 +177,14 @@ if opt.segwit and 'S' not in g.proto.mmtypes: def randbool(): return hexlify(os.urandom(1))[1] in '12345678' -def get_segwit_val(): +def get_segwit_bool(): return randbool() if opt.segwit_random else True if opt.segwit else False +def disable_debug(): + ds = os.getenv('MMGEN_DEBUG') + if ds is not None: os.environ['MMGEN_DEBUG'] = '' + return ds +def restore_debug(ds): + if ds is not None: os.environ['MMGEN_DEBUG'] = ds cfgs = { '15': { @@ -194,7 +200,7 @@ cfgs = { 'mmseed': 'export_seed_dfl_wallet', 'del_dw_run': 'delete_dfl_wallet', }, - 'segwit': get_segwit_val() + 'segwit': get_segwit_bool() }, '16': { 'tmpdir': os.path.join('test','tmp16'), @@ -203,7 +209,7 @@ cfgs = { 'dep_generators': { pwfile: 'passchg_dfl_wallet', }, - 'segwit': get_segwit_val() + 'segwit': get_segwit_bool() }, '17': { 'tmpdir': os.path.join('test','tmp17') }, '18': { 'tmpdir': os.path.join('test','tmp18') }, @@ -229,7 +235,7 @@ cfgs = { incog_id_fn: 'export_incog_hidden', 'akeys.mmenc': 'keyaddrgen' }, - 'segwit': get_segwit_val() + 'segwit': get_segwit_bool() }, '2': { 'tmpdir': os.path.join('test','tmp2'), @@ -243,7 +249,7 @@ cfgs = { 'sigtx': 'txsign2', 'mmwords': 'export_mnemonic2', }, - 'segwit': get_segwit_val() + 'segwit': get_segwit_bool() }, '3': { 'tmpdir': os.path.join('test','tmp3'), @@ -255,7 +261,7 @@ cfgs = { 'rawtx': 'txcreate3', 'sigtx': 'txsign3' }, - 'segwit': get_segwit_val() + 'segwit': get_segwit_bool() }, '4': { 'tmpdir': os.path.join('test','tmp4'), @@ -272,7 +278,7 @@ cfgs = { }, 'bw_filename': 'brainwallet.mmbrain', 'bw_params': '192,1', - 'segwit': get_segwit_val() + 'segwit': get_segwit_bool() }, '14': { 'kapasswd': 'Maxwell', @@ -285,7 +291,7 @@ cfgs = { 'addrs': 'addrgen14', 'akeys.mmenc': 'keyaddrgen14', }, - 'segwit': get_segwit_val() + 'segwit': get_segwit_bool() }, '5': { 'tmpdir': os.path.join('test','tmp5'), @@ -295,7 +301,7 @@ cfgs = { 'mmdat': 'passchg', pwfile: 'passchg', }, - 'segwit': get_segwit_val() + 'segwit': get_segwit_bool() }, '6': { 'name': 'reference wallet check (128-bit)', @@ -347,7 +353,7 @@ cfgs = { 'addrs': 'refaddrgen1', 'akeys.mmenc': 'refkeyaddrgen1' }, - 'segwit': get_segwit_val() + 'segwit': get_segwit_bool() }, '7': { 'name': 'reference wallet check (192-bit)', @@ -399,7 +405,7 @@ cfgs = { 'addrs': 'refaddrgen2', 'akeys.mmenc': 'refkeyaddrgen2' }, - 'segwit': get_segwit_val() + 'segwit': get_segwit_bool() }, '8': { 'name': 'reference wallet check (256-bit)', @@ -488,7 +494,7 @@ cfgs = { 'addrs': 'refaddrgen3', 'akeys.mmenc': 'refkeyaddrgen3' }, - 'segwit': get_segwit_val() + 'segwit': get_segwit_bool() }, '9': { 'tmpdir': os.path.join('test','tmp9'), @@ -1013,7 +1019,10 @@ class MMGenExpect(MMGenPexpect): def create_fake_unspent_entry(coinaddr,al_id=None,idx=None,lbl=None,non_mmgen=False,segwit=False): if 'S' not in g.proto.mmtypes: segwit = False if lbl: lbl = ' ' + lbl - spk1,spk2 = (('76a914','88ac'),('a914','87'))[segwit and coinaddr.addr_fmt=='p2sh'] + spk_beg,spk_end = ( + ('76a914','88ac'), + ('a914','87'), + )[segwit and coinaddr.addr_fmt=='p2sh'] amt1,amt2 = {'btc':(10,40),'bch':(10,40),'ltc':(1000,4000)}[coin_sel] return { 'account': '{}:{}'.format(g.proto.base_coin.lower(),coinaddr) if non_mmgen \ @@ -1023,7 +1032,7 @@ def create_fake_unspent_entry(coinaddr,al_id=None,idx=None,lbl=None,non_mmgen=Fa 'amount': g.proto.coin_amt('%s.%s' % (amt1+(getrandnum(4) % amt2), getrandnum(4) % 100000000)), 'address': coinaddr, 'spendable': False, - 'scriptPubKey': '{}{}{}'.format(spk1,coinaddr.hex,spk2), + 'scriptPubKey': '{}{}{}'.format(spk_beg,coinaddr.hex,spk_end), 'confirmations': getrandnum(4) % 50000 } @@ -1067,10 +1076,10 @@ def create_fake_unspent_data(adata,tx_data,non_mmgen_input=''): if non_mmgen_input: privkey = PrivKey(os.urandom(32),compressed=True,pubkey_type='std') - coinaddr = AddrGenerator('p2pkh').to_addr(KeyGenerator('std').to_pubhex(privkey)) + rand_coinaddr = AddrGenerator('p2pkh').to_addr(KeyGenerator('std').to_pubhex(privkey)) of = os.path.join(cfgs[non_mmgen_input]['tmpdir'],non_mmgen_fn) write_data_to_file(of,privkey.wif+'\n','compressed {} key'.format(g.proto.name),silent=True) - out.append(create_fake_unspent_entry(coinaddr,non_mmgen=True,segwit=False)) + out.append(create_fake_unspent_entry(rand_coinaddr,non_mmgen=True,segwit=False)) # msg('\n'.join([repr(o) for o in out])); sys.exit(0) return out @@ -1108,7 +1117,7 @@ def create_tx_data(sources): def make_txcreate_cmdline(tx_data): privkey = PrivKey(os.urandom(32),compressed=True,pubkey_type='std') t = ('p2pkh','segwit')['S' in g.proto.mmtypes] - coinaddr = AddrGenerator(t).to_addr(KeyGenerator('std').to_pubhex(privkey)) + rand_coinaddr = AddrGenerator(t).to_addr(KeyGenerator('std').to_pubhex(privkey)) # total of two outputs must be < 10 BTC (<1000 LTC) mods = {'btc':(6,4),'bch':(6,4),'ltc':(600,400)}[coin_sel] @@ -1127,7 +1136,7 @@ def make_txcreate_cmdline(tx_data): # + one change address and one BTC address if num is tx_data.keys()[-1]: cmd_args += ['{}:{}'.format(s['al_id'],s['addr_idxs'][1])] - cmd_args += ['{},{}'.format(coinaddr,cfgs[num]['amts'][1])] + cmd_args += ['{},{}'.format(rand_coinaddr,cfgs[num]['amts'][1])] return cmd_args + [tx_data[num]['addrfile'] for num in tx_data] @@ -1441,7 +1450,8 @@ class MMGenTestSuite(object): ok() def addrgen(self,name,wf,pf=None,check_ref=False,ftype='addr',id_str=None,extra_args=[],mmtype=None): - if cfg['segwit'] and ftype[:4] != 'pass' and not mmtype: mmtype = 'segwit' + if ftype[:4] != 'pass' and not mmtype: + if cfg['segwit']: mmtype = 'segwit' cmd_pfx = (ftype,'pass')[ftype[:4]=='pass'] t = MMGenExpect(name,'mmgen-{}gen'.format(cmd_pfx), ['-d',cfg['tmpdir']] + @@ -1455,16 +1465,20 @@ class MMGenTestSuite(object): t.expect('Passphrase is OK') desc = ('address','password')[ftype[:4]=='pass'] chk = t.expect_getend(r'Checksum for {} data .*?: '.format(desc),regex=True) + if ftype[:4] == 'pass': + t.expect('Encrypt password list? (y/N): ','\n') + t.written_to_file('Password list',oo=True) + else: + t.written_to_file('Addresses',oo=True) if check_ref: k = 'passfile32_chk' if ftype == 'pass32' \ else 'passfilehex_chk' if ftype == 'passhex' \ else 'passfile_chk' if ftype == 'pass' \ else '{}file{}_chk'.format(ftype,'_'+mmtype if mmtype else '') chk_ref = cfg[k] if ftype[:4] == 'pass' else cfg[k][fork][g.testnet] - refcheck('address data checksum',chk,chk_ref) - return - t.written_to_file('Addresses',oo=True) - t.ok() + refcheck('{}list data checksum'.format(ftype),chk,chk_ref) + else: + t.ok() def addrgen_dfl_wallet(self,name,pf=None,check_ref=False): return self.addrgen(name,wf=None,pf=pf,check_ref=check_ref) @@ -1486,7 +1500,7 @@ class MMGenTestSuite(object): vmsg('This is a simulation, so no addresses were actually imported into the tracking\nwallet') t.ok(exit_val=1) - def txcreate_common(self,name,sources=['1'],non_mmgen_input='',do_label=False,txdo_args=[],add_args=[]): + def txcreate_common(self,name,sources=['1'],non_mmgen_input='',do_label=False,txdo_args=[],add_args=[],view=None): if opt.verbose or opt.exact_output: sys.stderr.write(green('Generating fake tracking wallet info\n')) @@ -1538,7 +1552,7 @@ class MMGenTestSuite(object): t.expect('Comment: ',ref_tx_label.encode('utf8')+'\n') else: t.expect('Add a comment to transaction? (y/N): ','\n') - t.tx_view() + t.tx_view(view=view) if txdo_args: return t t.expect('Save transaction? (y/N): ','y') t.written_to_file('Transaction') @@ -1619,7 +1633,7 @@ class MMGenTestSuite(object): t = MMGenExpect(name,'mmgen-txsend', extra_opts + ['-d',cfg['tmpdir'],sigfile]) if really_send: os.environ['MMGEN_BOGUS_SEND'] = '1' t.license() - t.tx_view() + t.tx_view(view='terse') t.expect('Add a comment to transaction? (y/N): ','\n') t.expect('Are you sure you want to broadcast this') m = 'YES, I REALLY WANT TO DO THIS' @@ -1735,7 +1749,8 @@ class MMGenTestSuite(object): args=['-H','%s,%s'%(rf,hincog_offset),'-l',str(hincog_seedlen)]) def keyaddrgen(self,name,wf,pf=None,check_ref=False,mmtype=None): - if cfg['segwit'] and not mmtype: mmtype = 'segwit' + if cfg['segwit'] and not mmtype: + mmtype = 'segwit' args = ['-d',cfg['tmpdir'],usr_rand_arg,wf,cfg['addr_idx_list']] t = MMGenExpect(name,'mmgen-keygen', ([],['--type='+str(mmtype)])[bool(mmtype)] + args,extra_desc=('','(segwit)')[mmtype=='segwit']) @@ -1866,7 +1881,7 @@ class MMGenTestSuite(object): t.hash_preset('key-address data','1') t.passphrase('key-address data',cfgs['14']['kapasswd']) t.expect('Check key-to-address validity? (y/N): ','y') - t.tx_view() + t.tx_view(view='terse') for cnum,desc in (('1','incognito data'),('3','MMGen wallet')): t.passphrase(('%s' % desc),cfgs[cnum]['wpasswd']) @@ -2134,8 +2149,7 @@ class MMGenTestSuite(object): def ref_segwitaddrfile_chk(self,name): if not 'S' in g.proto.mmtypes: - msg_r('Skipping {} (not supported)'.format(name)) - ok() + msg_r('Skipping {} (not supported)'.format(name)); ok() else: self.ref_addrfile_chk(name,ftype='segwitaddr') @@ -2294,7 +2308,7 @@ class MMGenTestSuite(object): def regtest_user_bal(self,name,user,bal): t = MMGenExpect(name,'mmgen-tool',['--'+user,'listaddresses','showempty=1']) total = t.expect_getend('TOTAL: ') - cmp_or_die(total,'{} {}'.format(bal,g.coin)) + cmp_or_die('{} {}'.format(bal,g.coin),total) def regtest_alice_bal1(self,name): return self.regtest_user_bal(name,'alice',rtFundAmt) @@ -2318,11 +2332,11 @@ class MMGenTestSuite(object): t = MMGenExpect(name,'mmgen-regtest',['get_balances']) t.expect('Switching') ret = t.expect_getend("Bob's balance:").strip() - cmp_or_die(ret,rtBals[4],skip_ok=True) + cmp_or_die(rtBals[4],ret,skip_ok=True) ret = t.expect_getend("Alice's balance:").strip() - cmp_or_die(ret,rtBals[5],skip_ok=True) + cmp_or_die(rtBals[5],ret,skip_ok=True) ret = t.expect_getend("Total balance:").strip() - cmp_or_die(ret,rtBals[6],skip_ok=True) + cmp_or_die(rtBals[6],ret,skip_ok=True) t.ok() def regtest_user_txdo( self,name,user,fee, @@ -2437,9 +2451,11 @@ class MMGenTestSuite(object): t.ok() def regtest_get_mempool(self,name): - t = MMGenExpect(name,'mmgen-regtest',['show_mempool']) + ds = disable_debug() + ret = MMGenExpect(name,'mmgen-regtest',['show_mempool']).read() + restore_debug(ds) from ast import literal_eval - return literal_eval(t.read()) + return literal_eval(ret) def regtest_get_mempool1(self,name): mp = self.regtest_get_mempool(name) @@ -2461,11 +2477,14 @@ class MMGenTestSuite(object): @staticmethod def gen_pairs(n): - return [subprocess.check_output( + ds = disable_debug() + ret = [subprocess.check_output( ['python',os.path.join('cmds','mmgen-tool'),'--testnet=1'] + ([],['--type=compressed'])[bool((i+1)%2)] + ['-r0','randpair'] ).split() for i in range(n)] + restore_debug(ds) + return ret def regtest_bob_pre_import(self,name): pairs = self.gen_pairs(5)