|
@@ -24,6 +24,8 @@ import os, json, time, re
|
|
|
from decimal import Decimal
|
|
|
|
|
|
from mmgen.proto.btc.regtest import MMGenRegtest
|
|
|
+from mmgen.proto.bch.cashaddr import b32a
|
|
|
+from mmgen.proto.btc.common import b58a
|
|
|
from mmgen.color import yellow
|
|
|
from mmgen.util import msg_r,die,gmsg,capfirst,fmt_list
|
|
|
from mmgen.protocol import init_proto
|
|
@@ -164,7 +166,7 @@ def make_burn_addr(proto):
|
|
|
cfg = cfg,
|
|
|
cmdname = 'pubhash2addr',
|
|
|
proto = proto,
|
|
|
- mmtype = 'compressed' ).pubhash2addr('00'*20)
|
|
|
+ mmtype = 'compressed').pubhash2addr('00'*20)
|
|
|
|
|
|
class CmdTestRegtest(CmdTestBase,CmdTestShared):
|
|
|
'transacting and tracking wallet operations via regtest mode'
|
|
@@ -394,6 +396,7 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared):
|
|
|
'view': (
|
|
|
'viewing addresses and unspent outputs',
|
|
|
('alice_listaddresses_scroll', 'listaddresses (--scroll, interactive=1)'),
|
|
|
+ ('alice_listaddresses_cashaddr', 'listaddresses (BCH cashaddr)'),
|
|
|
('alice_listaddresses_empty', 'listaddresses (no data)'),
|
|
|
('alice_listaddresses_menu', 'listaddresses (menu items)'),
|
|
|
('alice_listaddresses1', 'listaddresses'),
|
|
@@ -404,6 +407,7 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared):
|
|
|
('alice_twview_days', 'twview (age_fmt=days)'),
|
|
|
('alice_twview_date', 'twview (age_fmt=date)'),
|
|
|
('alice_twview_date_time', 'twview (age_fmt=date_time)'),
|
|
|
+ ('alice_twview_interactive_cashaddr', 'twview (interactive=1, BCH cashaddr)'),
|
|
|
('alice_txcreate_info', 'txcreate -i'),
|
|
|
('alice_txcreate_info_term', 'txcreate -i (pexpect_spawn)'),
|
|
|
('bob_send_to_alice_2addr', 'sending a TX to 2 addresses in Alice’s wallet'),
|
|
@@ -471,18 +475,19 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared):
|
|
|
if self.proto.testnet:
|
|
|
die(2,'--testnet and --regtest options incompatible with regtest test suite')
|
|
|
|
|
|
- self.proto = init_proto( cfg, self.proto.coin, network='regtest', need_amt=True )
|
|
|
- coin = self.proto.coin.lower()
|
|
|
+ coin = self.coin
|
|
|
+
|
|
|
+ self.proto = init_proto(cfg, coin, network='regtest', need_amt=True)
|
|
|
|
|
|
gldict = globals()
|
|
|
for k in rt_data:
|
|
|
gldict[k] = rt_data[k][coin] if coin in rt_data[k] else None
|
|
|
|
|
|
- self.use_bdb_wallet = self.bdb_wallet or self.proto.coin != 'BTC'
|
|
|
+ self.use_bdb_wallet = self.bdb_wallet or coin != 'btc'
|
|
|
|
|
|
- self.rt = MMGenRegtest(cfg, self.proto.coin, bdb_wallet=self.use_bdb_wallet)
|
|
|
+ self.rt = MMGenRegtest(cfg, coin, bdb_wallet=self.use_bdb_wallet)
|
|
|
|
|
|
- if self.proto.coin == 'BTC':
|
|
|
+ if coin == 'btc':
|
|
|
self.test_rbf = True # tests are non-coin-dependent, so run just once for BTC
|
|
|
if cfg.test_suite_deterministic:
|
|
|
self.deterministic = True
|
|
@@ -490,7 +495,7 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared):
|
|
|
self.spawn_env['MMGEN_BOGUS_SEND'] = ''
|
|
|
self.write_to_tmpfile('wallet_password',rt_pw)
|
|
|
|
|
|
- self.dfl_mmtype = 'C' if self.proto.coin == 'BCH' else 'B'
|
|
|
+ self.dfl_mmtype = 'C' if coin == 'bch' else 'B'
|
|
|
self.burn_addr = make_burn_addr(self.proto)
|
|
|
self.user_sids = {}
|
|
|
|
|
@@ -553,8 +558,8 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared):
|
|
|
def walletgen_alice(self):
|
|
|
return self.walletgen('alice')
|
|
|
|
|
|
- def _user_dir(self,user,coin=None):
|
|
|
- return joinpath(self.tr.data_dir,'regtest',coin or self.proto.coin.lower(),user)
|
|
|
+ def _user_dir(self, user, coin=None):
|
|
|
+ return joinpath(self.tr.data_dir, 'regtest', coin or self.coin, user)
|
|
|
|
|
|
def _user_sid(self,user):
|
|
|
if user in self.user_sids:
|
|
@@ -718,31 +723,39 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared):
|
|
|
def fund_alice(self):
|
|
|
return self.fund_wallet('alice',('L','S')[self.proto.cap('segwit')],rtFundAmt)
|
|
|
|
|
|
- def user_twview(self, user, chk=None, expect=None, cmdline=['twview'], sort='age', exit_val=None):
|
|
|
- t = self.spawn('mmgen-tool',[f'--{user}'] + cmdline + ['sort='+sort], exit_val=exit_val)
|
|
|
+ def user_twview(
|
|
|
+ self,
|
|
|
+ user,
|
|
|
+ chk = None,
|
|
|
+ expect = None,
|
|
|
+ cmd = 'twview',
|
|
|
+ opts = [],
|
|
|
+ sort = 'age',
|
|
|
+ exit_val = None):
|
|
|
+ t = self.spawn('mmgen-tool', [f'--{user}'] + opts + [cmd] + [f'sort={sort}'], exit_val=exit_val)
|
|
|
if chk:
|
|
|
t.expect(r'{}\b.*\D{}\b'.format(*chk),regex=True)
|
|
|
if expect:
|
|
|
- t.expect(expect)
|
|
|
+ t.expect(expect, regex=True)
|
|
|
return t
|
|
|
|
|
|
def bob_twview_noaddrs(self):
|
|
|
return self.user_twview('bob', expect='No spendable', exit_val=1)
|
|
|
|
|
|
def bob_listaddrs_noaddrs(self):
|
|
|
- return self.user_twview('bob', cmdline=['listaddresses'], expect='No addresses', exit_val=1)
|
|
|
+ return self.user_twview('bob', cmd='listaddresses', expect='No addresses', exit_val=1)
|
|
|
|
|
|
def bob_twview_nobal(self):
|
|
|
return self.user_twview('bob', expect='No spendable', exit_val=1)
|
|
|
|
|
|
def bob_listaddrs_nobal(self):
|
|
|
- return self.user_twview('bob', cmdline=['listaddresses'], expect='TOTAL:')
|
|
|
+ return self.user_twview('bob', cmd='listaddresses', expect='TOTAL:')
|
|
|
|
|
|
def bob_twview1(self):
|
|
|
- return self.user_twview('bob', chk = ('1',rtAmts[0]) )
|
|
|
+ return self.user_twview('bob', chk=('1', rtAmts[0]))
|
|
|
|
|
|
- def user_bal(self,user,bal,args=['showempty=1'],skip_check=False):
|
|
|
- t = self.spawn('mmgen-tool',['--'+user,'listaddresses'] + args)
|
|
|
+ def user_bal(self, user, bal, opts=[], args=['showempty=1'], skip_check=False):
|
|
|
+ t = self.spawn('mmgen-tool', opts + [f'--{user}', 'listaddresses'] + args)
|
|
|
if not skip_check:
|
|
|
cmp_or_die(f'{bal} {self.proto.coin}',strip_ansi_escapes(t.expect_getend('TOTAL: ')))
|
|
|
return t
|
|
@@ -754,10 +767,10 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared):
|
|
|
return self.user_bal('alice',rtBals[8])
|
|
|
|
|
|
def bob_bal1(self):
|
|
|
- return self.user_bal('bob',rtFundAmt)
|
|
|
+ return self.user_bal('bob', rtFundAmt, self._cashaddr_opt(0))
|
|
|
|
|
|
def bob_bal2(self):
|
|
|
- return self.user_bal('bob',rtBals[0])
|
|
|
+ return self.user_bal('bob', rtBals[0], self._cashaddr_opt(1))
|
|
|
|
|
|
def bob_bal2a(self):
|
|
|
return self.user_bal('bob',rtBals[0],args=['showempty=1','age_fmt=confs'])
|
|
@@ -818,11 +831,21 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared):
|
|
|
|
|
|
def bob_twview2(self):
|
|
|
sid1 = self._get_user_subsid('bob','29L')
|
|
|
- return self.user_twview('bob',chk=(sid1+':C:2','0.29'),sort='twmmid')
|
|
|
+ return self.user_twview(
|
|
|
+ 'bob',
|
|
|
+ opts = self._cashaddr_opt(0),
|
|
|
+ chk = (f'{sid1}:C:2', '0.29'),
|
|
|
+ sort = 'twmmid',
|
|
|
+ expect = rf'[{b58a}]{{8}}' if self.proto.coin == 'BCH' else None)
|
|
|
|
|
|
def bob_twview3(self):
|
|
|
sid2 = self._get_user_subsid('bob','127S')
|
|
|
- return self.user_twview('bob',chk=(sid2+':C:3','0.127'),sort='amt')
|
|
|
+ return self.user_twview(
|
|
|
+ 'bob',
|
|
|
+ opts = self._cashaddr_opt(1),
|
|
|
+ chk = (f'{sid2}:C:3', '0.127'),
|
|
|
+ sort = 'amt',
|
|
|
+ expect = rf'[{b32a}]{{8}}' if self.proto.coin == 'BCH' else None)
|
|
|
|
|
|
def bob_subwallet_txcreate(self):
|
|
|
sid1 = self._get_user_subsid('bob','29L')
|
|
@@ -853,21 +876,28 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared):
|
|
|
sid = self._user_sid('bob')
|
|
|
return self.user_twview('bob',chk=(sid+':L:5',rtBals[9]),sort='twmmid')
|
|
|
|
|
|
- def user_txhist(self,user,args,expect):
|
|
|
- t = self.spawn('mmgen-tool',['--'+user,'txhist'] + args)
|
|
|
- m = re.search( expect, t.read(strip_color=True), re.DOTALL )
|
|
|
- assert m, f'Expected: {expect}'
|
|
|
+ def user_txhist(self, user, args, expect, opts=[], expect2=None):
|
|
|
+ t = self.spawn('mmgen-tool', opts + [f'--{user}', 'txhist'] + args)
|
|
|
+ text = t.read(strip_color=True)
|
|
|
+ for s in (expect, expect2):
|
|
|
+ if s:
|
|
|
+ m = re.search(s, text, re.DOTALL)
|
|
|
+ assert m, f'Expected: {s}'
|
|
|
return t
|
|
|
|
|
|
def bob_txhist1(self):
|
|
|
return self.user_txhist('bob',
|
|
|
+ opts = self._cashaddr_opt(1),
|
|
|
args = ['sort=age'],
|
|
|
- expect = fr'\s1\).*\s{rtFundAmt}\s' )
|
|
|
+ expect = fr'\s1\).*\s{rtFundAmt}\s',
|
|
|
+ expect2 = rf'[{b32a}]{{8}}' if self.proto.coin == 'BCH' else None)
|
|
|
|
|
|
def bob_txhist2(self):
|
|
|
return self.user_txhist('bob',
|
|
|
+ opts = self._cashaddr_opt(0),
|
|
|
args = ['sort=blockheight','reverse=1','age_fmt=block'],
|
|
|
- expect = fr'\s1\).*:{self.dfl_mmtype}:1\s' )
|
|
|
+ expect = fr'\s1\).*:{self.dfl_mmtype}:1\s',
|
|
|
+ expect2 = rf'[{b58a}]{{8}}' if self.proto.coin == 'BCH' else None)
|
|
|
|
|
|
def bob_txhist3(self):
|
|
|
return self.user_txhist('bob',
|
|
@@ -891,6 +921,13 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared):
|
|
|
self.get_file_with_ext('out',delete_all=True)
|
|
|
t = self.spawn('mmgen-tool',
|
|
|
['--bob',f'--outdir={self.tmpdir}','txhist','age_fmt=date_time','interactive=true'] )
|
|
|
+ if self.proto.coin == 'BCH':
|
|
|
+ for expect, resp in (
|
|
|
+ (rf'[{b32a}]{{8}}', 'h'),
|
|
|
+ (rf'[{b58a}]{{8}}', 'h')
|
|
|
+ ):
|
|
|
+ t.expect(expect, regex=True)
|
|
|
+ t.expect('draw:\b', resp, regex=True)
|
|
|
for resp in ('u','i','t','a','m','T','A','r','r','D','D','D','D','p','P','n','V'):
|
|
|
t.expect('draw:\b',resp,regex=True)
|
|
|
if t.pexpect_spawn:
|
|
@@ -1476,6 +1513,8 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared):
|
|
|
|
|
|
async def carol_delete_wallet(self):
|
|
|
imsg('Unloading Carol’s tracking wallet')
|
|
|
+ if self.proto.coin == 'BCH':
|
|
|
+ time.sleep(0.2)
|
|
|
t = self.spawn('mmgen-regtest',['cli','unloadwallet','carol'])
|
|
|
t.ok()
|
|
|
wdir = joinpath((await self.rt.rpc).daemon.network_datadir, 'wallets', 'carol')
|
|
@@ -1577,7 +1616,7 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared):
|
|
|
|
|
|
def alice_add_comment_badaddr2(self):
|
|
|
# mainnet zero address:
|
|
|
- addr = init_proto( cfg, self.proto.coin, network='mainnet' ).pubhash2addr(bytes(20),False)
|
|
|
+ addr = init_proto(cfg, self.proto.coin, network='mainnet').pubhash2addr(bytes(20), 'p2pkh')
|
|
|
return self.alice_add_comment_badaddr( addr, 'invalid address', 2 )
|
|
|
|
|
|
def alice_add_comment_badaddr3(self):
|
|
@@ -1585,7 +1624,7 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared):
|
|
|
return self.alice_add_comment_badaddr( addr, f'MMGen address {addr!r} not found in tracking wallet', 2 )
|
|
|
|
|
|
def alice_add_comment_badaddr4(self):
|
|
|
- addr = self.proto.pubhash2addr(bytes(20),False) # regtest (testnet) zero address
|
|
|
+ addr = self.proto.pubhash2addr(bytes(20), 'p2pkh') # regtest (testnet) zero address
|
|
|
return self.alice_add_comment_badaddr( addr, f'Coin address {addr!r} not found in tracking wallet', 2 )
|
|
|
|
|
|
def alice_remove_comment1(self):
|
|
@@ -1635,28 +1674,42 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared):
|
|
|
'interactive=1',
|
|
|
]
|
|
|
)
|
|
|
- t.expect('abel:\b','p')
|
|
|
- ret = t.expect([ 'abel:\b', 'to confirm: ' ])
|
|
|
+ prompt = 'abel:\b'
|
|
|
+ t.expect(prompt, 'p')
|
|
|
+ ret = t.expect([prompt, 'to confirm: '])
|
|
|
if ret == 1:
|
|
|
t.send('YES\n')
|
|
|
- t.expect('abel:\b')
|
|
|
+ t.expect(prompt)
|
|
|
t.send('l')
|
|
|
t.expect(
|
|
|
'main menu): ',
|
|
|
'{}\n'.format(2 if self.proto.coin == 'BCH' else 1) )
|
|
|
t.expect('for address.*: ','\n',regex=True)
|
|
|
t.expect('unchanged')
|
|
|
- t.expect('abel:\b','q')
|
|
|
+ t.expect(prompt, 'q')
|
|
|
return t
|
|
|
|
|
|
def _alice_listaddresses_interactive(self,expect=(),expect_menu=()):
|
|
|
t = self.spawn('mmgen-tool',['--alice','listaddresses','interactive=1'])
|
|
|
+ prompt = 'abel:\b'
|
|
|
+ for e in expect:
|
|
|
+ t.expect(*e, regex=True)
|
|
|
for s in expect_menu:
|
|
|
- t.expect('abel:\b',s)
|
|
|
- for p,s in expect:
|
|
|
- t.expect(p,s)
|
|
|
+ t.expect(prompt, s)
|
|
|
return t
|
|
|
|
|
|
+ def alice_listaddresses_cashaddr(self):
|
|
|
+ if self.proto.coin != 'BCH':
|
|
|
+ return 'skip'
|
|
|
+ prompt = 'abel:\b'
|
|
|
+ expect = (
|
|
|
+ [rf'[{b32a}]{{8}}'],
|
|
|
+ [prompt, 'h'],
|
|
|
+ [rf'[{b58a}]{{8}}'],
|
|
|
+ [prompt, 'q']
|
|
|
+ )
|
|
|
+ return self._alice_listaddresses_interactive(expect=expect)
|
|
|
+
|
|
|
def alice_listaddresses_empty(self):
|
|
|
return self._alice_listaddresses_interactive(expect_menu='uuEq')
|
|
|
|
|
@@ -1715,6 +1768,17 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared):
|
|
|
args = ['age_fmt=date_time'],
|
|
|
expect = (rtAmts[0],pat_date_time) )
|
|
|
|
|
|
+ def alice_twview_interactive_cashaddr(self):
|
|
|
+ if self.proto.coin != 'BCH':
|
|
|
+ return 'skip'
|
|
|
+ t = self.spawn('mmgen-tool', ['--alice', 'twview', 'interactive=true'])
|
|
|
+ prompt = 'abel:\b'
|
|
|
+ t.expect(rf'[{b32a}]{{8}}', regex=True)
|
|
|
+ t.expect(prompt, 'h')
|
|
|
+ t.expect(rf'[{b58a}]{{8}}', regex=True)
|
|
|
+ t.expect(prompt, 'q')
|
|
|
+ return t
|
|
|
+
|
|
|
def alice_txcreate_info(self,pexpect_spawn=False):
|
|
|
t = self.spawn('mmgen-txcreate',['--alice','-Bi'],pexpect_spawn=pexpect_spawn)
|
|
|
pats = (
|