regtest: load all wallets, use rpcwallet mechanism to select user
This commit is contained in:
parent
6b73197679
commit
2fcb336d57
4 changed files with 51 additions and 136 deletions
133
mmgen/regtest.py
133
mmgen/regtest.py
|
|
@ -46,10 +46,7 @@ class MMGenRegtest(MMGenObject):
|
|||
rpc_password = 'hodltothemoon'
|
||||
users = ('bob','alice','miner')
|
||||
coins = ('btc','bch','ltc')
|
||||
usr_cmds = (
|
||||
'bob','alice','miner','user','state',
|
||||
'setup','generate','send','stop',
|
||||
'balances','mempool','cli' )
|
||||
usr_cmds = ('setup','generate','send','stop', 'state', 'balances','mempool','cli')
|
||||
|
||||
def __init__(self,coin):
|
||||
self.coin = coin.lower()
|
||||
|
|
@ -61,14 +58,13 @@ class MMGenRegtest(MMGenObject):
|
|||
async def generate(self,blocks=1,silent=False):
|
||||
|
||||
blocks = int(blocks)
|
||||
await self.switch_user('miner',quiet=True)
|
||||
|
||||
async def have_generatetoaddress():
|
||||
ret = await self.rpc_call('help','generatetoaddress')
|
||||
ret = await self.rpc_call('help','generatetoaddress',wallet='miner')
|
||||
return not 'unknown command:' in ret
|
||||
|
||||
async def get_miner_address():
|
||||
return await self.rpc_call('getnewaddress')
|
||||
return await self.rpc_call('getnewaddress',wallet='miner')
|
||||
|
||||
if self.d.state == 'stopped':
|
||||
die(1,'Regtest daemon is not running')
|
||||
|
|
@ -80,27 +76,13 @@ class MMGenRegtest(MMGenObject):
|
|||
else:
|
||||
cmd_args = ( 'generate', blocks )
|
||||
|
||||
out = await self.rpc_call(*cmd_args)
|
||||
out = await self.rpc_call(*cmd_args,wallet='miner')
|
||||
|
||||
if len(out) != blocks:
|
||||
rdie(1,'Error generating blocks')
|
||||
|
||||
gmsg('Mined {} block{}'.format(blocks,suf(blocks)))
|
||||
|
||||
async def create_tracking_wallet(self,user):
|
||||
try:
|
||||
await self.rpc_call('getbalance')
|
||||
except:
|
||||
await self.rpc_call('createwallet',
|
||||
user, # wallet_name
|
||||
user != 'miner', # disable_private_keys
|
||||
user != 'miner', # blank (no keys or seed)
|
||||
'', # passphrase (empty string for non-encrypted)
|
||||
False, # avoid_reuse (track address reuse)
|
||||
False, # descriptors (native descriptor wallet)
|
||||
False # load_on_startup
|
||||
)
|
||||
|
||||
async def setup(self):
|
||||
|
||||
try: os.makedirs(self.d.datadir)
|
||||
|
|
@ -113,47 +95,46 @@ class MMGenRegtest(MMGenObject):
|
|||
|
||||
gmsg('Starting {} regtest setup'.format(self.coin.upper()))
|
||||
|
||||
gmsg('Creating miner wallet')
|
||||
self.start_daemon('miner')
|
||||
await self.create_tracking_wallet('miner')
|
||||
self.d.start(silent=True)
|
||||
|
||||
rpc = await rpc_init(self.proto,backend=None,daemon=self.d)
|
||||
for user in ('miner','bob','alice'):
|
||||
gmsg(f'Creating {capfirst(user)}’s wallet')
|
||||
await rpc.icall(
|
||||
'createwallet',
|
||||
wallet_name = user,
|
||||
no_keys = user != 'miner',
|
||||
load_on_startup = False )
|
||||
|
||||
await self.generate(432,silent=True)
|
||||
await self.rpc_call('stop')
|
||||
time.sleep(1.2) # race condition?
|
||||
|
||||
for user in ('alice','bob'):
|
||||
gmsg("Creating {}'s tracking wallet".format(user.capitalize()))
|
||||
self.start_daemon(user)
|
||||
await self.create_tracking_wallet(user)
|
||||
if user == 'bob' and opt.setup_no_stop_daemon:
|
||||
msg('Leaving daemon running with Bob as current user')
|
||||
else:
|
||||
await self.rpc_call('stop')
|
||||
time.sleep(0.2) # race condition?
|
||||
|
||||
gmsg('Setup complete')
|
||||
|
||||
def init_daemon(self,user,reindex=False):
|
||||
assert user is None or user in self.users,'{!r}: invalid user for regtest'.format(user)
|
||||
if opt.setup_no_stop_daemon:
|
||||
msg('Leaving regtest daemon running')
|
||||
else:
|
||||
msg('Stopping regtest daemon')
|
||||
await self.rpc_call('stop')
|
||||
|
||||
def init_daemon(self,reindex=False):
|
||||
self.d.net_desc = self.coin.upper()
|
||||
self.d.usr_coind_args = [f'--wallet={user}']
|
||||
if reindex:
|
||||
self.d.usr_coind_args.append('--reindex')
|
||||
|
||||
def start_daemon(self,user,reindex=False,silent=True):
|
||||
self.init_daemon(user=user,reindex=reindex)
|
||||
async def start_daemon(self,reindex=False,silent=True):
|
||||
self.init_daemon(reindex=reindex)
|
||||
self.d.start(silent=silent)
|
||||
for user in ('miner','bob','alice'):
|
||||
msg(f'Loading {capfirst(user)}’s wallet')
|
||||
await self.rpc_call('loadwallet',user,start_daemon=False)
|
||||
|
||||
async def rpc_call(self,*args):
|
||||
rpc = await rpc_init(self.proto,backend=None,daemon=self.d,caller='regtest')
|
||||
return await rpc.call(*args)
|
||||
|
||||
async def current_user(self):
|
||||
try:
|
||||
return (await self.rpc_call('getwalletinfo'))['walletname']
|
||||
except SocketError as e:
|
||||
msg(str(e))
|
||||
return None
|
||||
async def rpc_call(self,*args,wallet=None,start_daemon=True):
|
||||
# g.prog_name == 'mmgen-regtest' test is used by .rpc to identify caller, so require this:
|
||||
assert g.prog_name == 'mmgen-regtest', 'only mmgen-regtest util is allowed to use this method'
|
||||
if start_daemon and self.d.state == 'stopped':
|
||||
await self.start_daemon()
|
||||
rpc = await rpc_init(self.proto,backend=None,daemon=self.d)
|
||||
return await rpc.call(*args,wallet=wallet)
|
||||
|
||||
async def stop(self):
|
||||
await self.rpc_call('stop')
|
||||
|
|
@ -161,27 +142,21 @@ class MMGenRegtest(MMGenObject):
|
|||
def state(self):
|
||||
msg(self.d.state)
|
||||
|
||||
async def balances(self,*users):
|
||||
users = list(set(users or ['bob','alice']))
|
||||
cur_user = await self.current_user()
|
||||
if cur_user in users:
|
||||
users.remove(cur_user)
|
||||
users = [cur_user] + users
|
||||
async def balances(self):
|
||||
bal = {}
|
||||
users = ('bob','alice')
|
||||
for user in users:
|
||||
await self.switch_user(user,quiet=True)
|
||||
out = await self.rpc_call('listunspent',0)
|
||||
out = await self.rpc_call('listunspent',0,wallet=user)
|
||||
bal[user] = sum(e['amount'] for e in out)
|
||||
|
||||
fs = '{:<16} {:18.8f}'
|
||||
for user in sorted(users):
|
||||
for user in users:
|
||||
msg(fs.format(user.capitalize()+"'s balance:",bal[user]))
|
||||
msg(fs.format('Total balance:',sum(v for k,v in bal.items())))
|
||||
|
||||
async def send(self,addr,amt):
|
||||
await self.switch_user('miner',quiet=True)
|
||||
gmsg('Sending {} miner {} to address {}'.format(amt,self.d.daemon_id.upper(),addr))
|
||||
cp = await self.rpc_call('sendtoaddress',addr,str(amt))
|
||||
cp = await self.rpc_call('sendtoaddress',addr,str(amt),wallet='miner')
|
||||
await self.generate(1)
|
||||
|
||||
async def mempool(self):
|
||||
|
|
@ -197,36 +172,6 @@ class MMGenRegtest(MMGenObject):
|
|||
ret = getattr(self,args[0])(*args[1:])
|
||||
return (await ret) if type(ret).__name__ == 'coroutine' else ret
|
||||
|
||||
async def user(self):
|
||||
ret = await self.current_user()
|
||||
msg(ret.capitalize() if ret else 'None')
|
||||
|
||||
async def bob(self): await self.switch_user('bob')
|
||||
async def alice(self): await self.switch_user('alice')
|
||||
async def miner(self): await self.switch_user('miner')
|
||||
|
||||
async def switch_user(self,user,quiet=False):
|
||||
|
||||
if self.d.state == 'busy':
|
||||
self.d.wait_for_state('ready')
|
||||
|
||||
if self.d.state == 'ready':
|
||||
cur_user = await self.current_user()
|
||||
if user == cur_user:
|
||||
if not quiet:
|
||||
msg('{} is already the current user for {}'.format(user.capitalize(),self.d.net_desc))
|
||||
return
|
||||
gmsg_r('Switching to user {} for {}'.format(user.capitalize(),self.d.net_desc))
|
||||
if cur_user:
|
||||
await self.rpc_call('unloadwallet',cur_user)
|
||||
await self.rpc_call('loadwallet',user)
|
||||
else:
|
||||
m = 'Starting {} {} with current user {}'
|
||||
gmsg_r(m.format(self.d.net_desc,self.d.desc,user.capitalize()))
|
||||
self.start_daemon(user,silent=True)
|
||||
|
||||
gmsg('...done')
|
||||
|
||||
async def fork(self,coin): # currently disabled
|
||||
|
||||
proto = init_proto(coin,False)
|
||||
|
|
@ -254,7 +199,7 @@ class MMGenRegtest(MMGenObject):
|
|||
create_data_dir(self.d.datadir)
|
||||
os.rmdir(self.d.datadir)
|
||||
shutil.copytree(source_data_dir,self.d.datadir,symlinks=True)
|
||||
self.start_daemon('miner',reindex=True)
|
||||
await self.start_daemon(reindex=True)
|
||||
await self.rpc_call('stop')
|
||||
|
||||
gmsg('Fork {} successfully created'.format(proto.coin))
|
||||
|
|
|
|||
16
mmgen/rpc.py
16
mmgen/rpc.py
|
|
@ -391,7 +391,7 @@ class BitcoinRPCClient(RPCClient,metaclass=aInitMeta):
|
|||
def __init__(self,*args,**kwargs):
|
||||
pass
|
||||
|
||||
async def __ainit__(self,proto,daemon,backend,caller):
|
||||
async def __ainit__(self,proto,daemon,backend):
|
||||
|
||||
self.proto = proto
|
||||
self.daemon = daemon
|
||||
|
|
@ -404,10 +404,6 @@ class BitcoinRPCClient(RPCClient,metaclass=aInitMeta):
|
|||
self.set_auth() # set_auth() requires cookie, so must be called after __init__() tests daemon is listening
|
||||
self.set_backend(backend) # backend requires self.auth
|
||||
|
||||
if caller != 'regtest' and (g.bob or g.alice):
|
||||
from .regtest import MMGenRegtest
|
||||
await MMGenRegtest(self.proto.coin).switch_user(('alice','bob')[g.bob],quiet=True)
|
||||
|
||||
self.cached = {}
|
||||
(
|
||||
self.cached['networkinfo'],
|
||||
|
|
@ -452,7 +448,7 @@ class BitcoinRPCClient(RPCClient,metaclass=aInitMeta):
|
|||
if len((await self.call('help',func)).split('\n')) > 3:
|
||||
self.caps += (cap,)
|
||||
|
||||
if caller != 'regtest':
|
||||
if not (g.prog_name == 'mmgen-regtest' or g.bob or g.alice):
|
||||
await self.check_tracking_wallet()
|
||||
|
||||
async def check_tracking_wallet(self,wallet_checked=[]):
|
||||
|
|
@ -503,6 +499,7 @@ class BitcoinRPCClient(RPCClient,metaclass=aInitMeta):
|
|||
@staticmethod
|
||||
def make_host_path(wallet):
|
||||
return (
|
||||
'/wallet/{}'.format('bob' if g.bob else 'alice') if (g.bob or g.alice) else
|
||||
'/wallet/{}'.format(wallet) if wallet else '/'
|
||||
)
|
||||
|
||||
|
|
@ -573,7 +570,7 @@ class EthereumRPCClient(RPCClient,metaclass=aInitMeta):
|
|||
def __init__(self,*args,**kwargs):
|
||||
pass
|
||||
|
||||
async def __ainit__(self,proto,daemon,backend,caller):
|
||||
async def __ainit__(self,proto,daemon,backend):
|
||||
self.proto = proto
|
||||
self.daemon = daemon
|
||||
self.call_sigs = getattr(getattr(CallSigs,proto.base_proto),daemon.id)
|
||||
|
|
@ -706,7 +703,7 @@ def handle_unsupported_daemon_version(rpc,proto,ignore_daemon_version,warning_sh
|
|||
rpc.daemon.coind_version_str,
|
||||
),indent=' ').rstrip())
|
||||
|
||||
async def rpc_init(proto,backend=None,daemon=None,ignore_daemon_version=False,caller=None):
|
||||
async def rpc_init(proto,backend=None,daemon=None,ignore_daemon_version=False):
|
||||
|
||||
if not 'rpc' in proto.mmcaps:
|
||||
die(1,f'Coin daemon operations not supported for {proto.name} protocol!')
|
||||
|
|
@ -718,8 +715,7 @@ async def rpc_init(proto,backend=None,daemon=None,ignore_daemon_version=False,ca
|
|||
}[proto.base_proto](
|
||||
proto = proto,
|
||||
daemon = daemon or CoinDaemon(proto=proto,test_suite=g.test_suite),
|
||||
backend = backend or opt.rpc_backend,
|
||||
caller = caller )
|
||||
backend = backend or opt.rpc_backend )
|
||||
|
||||
if rpc.daemon_version > rpc.daemon.coind_version:
|
||||
handle_unsupported_daemon_version(rpc,proto,ignore_daemon_version)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import sys
|
|||
from include.tests_header import repo_root
|
||||
from mmgen.common import *
|
||||
from mmgen.daemon import CoinDaemon
|
||||
from mmgen.regtest import MMGenRegtest
|
||||
|
||||
action = g.prog_name.split('-')[0]
|
||||
|
||||
|
|
@ -18,7 +17,6 @@ opts_data = {
|
|||
--, --longhelp Print help message for long options (common options)
|
||||
-d, --debug Produce debugging output (implies --verbose)
|
||||
-D, --no-daemonize Don't fork daemon to background
|
||||
-r, --regtest-user=U {a} a regtest daemon for user 'U'
|
||||
-s, --get-state Get the state of the daemon(s) and exit
|
||||
-t, --testing Testing mode. Print commands but don't execute them
|
||||
-v, --verbose Produce more verbose output
|
||||
|
|
@ -26,17 +24,11 @@ opts_data = {
|
|||
""",
|
||||
'notes': """
|
||||
Valid network IDs: {nid}, all, or no_xmr
|
||||
Valid Regtest network IDs: {rid}, or all
|
||||
Valid Regtest users: {ru}
|
||||
"""
|
||||
},
|
||||
'code': {
|
||||
'options': lambda s: s.format(a=action.capitalize(),pn=g.prog_name),
|
||||
'notes': lambda s: s.format(
|
||||
nid=', '.join(CoinDaemon.network_ids),
|
||||
rid=', '.join(MMGenRegtest.coins),
|
||||
ru=', '.join(MMGenRegtest.users),
|
||||
)
|
||||
'notes': lambda s: s.format(nid=', '.join(CoinDaemon.network_ids))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -45,8 +37,6 @@ cmd_args = opts.init(opts_data)
|
|||
if 'all' in cmd_args or 'no_xmr' in cmd_args:
|
||||
if len(cmd_args) != 1:
|
||||
die(1,"'all' or 'no_xmr' must be the sole argument")
|
||||
if opt.regtest_user:
|
||||
ids = MMGenRegtest.coins
|
||||
else:
|
||||
ids = list(CoinDaemon.network_ids)
|
||||
if cmd_args[0] == 'no_xmr':
|
||||
|
|
@ -58,10 +48,6 @@ else:
|
|||
for i in ids:
|
||||
if i not in CoinDaemon.network_ids:
|
||||
die(1,f'{i!r}: invalid network ID')
|
||||
if i.endswith('_rt'):
|
||||
die(1,'For regtest, use the plain coin symbol and the --regtest-user option')
|
||||
if opt.regtest_user and i not in MMGenRegtest.coins:
|
||||
die(1,f'For regtest, coin symbol must be one of {MMGenRegtest.coins}')
|
||||
|
||||
if 'eth' in ids and 'etc' in ids:
|
||||
msg('Cannot run ETH and ETC simultaneously, so skipping ETC')
|
||||
|
|
@ -69,12 +55,7 @@ if 'eth' in ids and 'etc' in ids:
|
|||
|
||||
for network_id in ids:
|
||||
network_id = network_id.lower()
|
||||
if opt.regtest_user:
|
||||
rt = MMGenRegtest(network_id)
|
||||
rt.init_daemon(opt.regtest_user)
|
||||
d = rt.d
|
||||
else:
|
||||
d = CoinDaemon(network_id,test_suite=True,flags=['no_daemonize'] if opt.no_daemonize else None)
|
||||
d = CoinDaemon(network_id,test_suite=True,flags=['no_daemonize'] if opt.no_daemonize else None)
|
||||
d.debug = opt.debug
|
||||
d.wait = not opt.no_wait
|
||||
if opt.get_state:
|
||||
|
|
|
|||
|
|
@ -144,7 +144,6 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
|
|||
cmd_group = (
|
||||
('setup', 'regtest (Bob and Alice) mode setup'),
|
||||
('daemon_version', 'mmgen-tool daemon_version'),
|
||||
('current_user', 'current user'),
|
||||
('halving_calculator_bob', 'halving calculator (Bob)'),
|
||||
('walletgen_bob', 'wallet generation (Bob)'),
|
||||
('walletgen_alice', 'wallet generation (Alice)'),
|
||||
|
|
@ -276,7 +275,7 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
|
|||
os.environ['MMGEN_TEST_SUITE'] = '' # mnemonic is piped to stdin, so stop being a terminal
|
||||
t = self.spawn('mmgen-regtest',['-n','setup'])
|
||||
os.environ['MMGEN_TEST_SUITE'] = '1'
|
||||
for s in ('Starting','Creating','Mined','Creating','Creating','Setup complete'):
|
||||
for s in ('Starting','Creating','Creating','Creating','Mined','Setup complete'):
|
||||
t.expect(s)
|
||||
return t
|
||||
|
||||
|
|
@ -285,11 +284,6 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
|
|||
t.expect('version')
|
||||
return t
|
||||
|
||||
def current_user(self):
|
||||
t = self.spawn('mmgen-regtest', ['user'])
|
||||
t.expect('Bob')
|
||||
return t
|
||||
|
||||
def halving_calculator_bob(self):
|
||||
t = self.spawn('halving-calculator.py',['--bob'],cmd_dir='examples')
|
||||
t.expect('time until halving')
|
||||
|
|
@ -526,11 +520,10 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
|
|||
|
||||
def bob_alice_bal(self):
|
||||
t = self.spawn('mmgen-regtest',['balances'])
|
||||
t.expect('Switching')
|
||||
ret = t.expect_getend("Alice's balance:").strip()
|
||||
cmp_or_die(rtBals[5],ret)
|
||||
ret = t.expect_getend("Bob's balance:").strip()
|
||||
cmp_or_die(rtBals[4],ret)
|
||||
ret = t.expect_getend("Alice's balance:").strip()
|
||||
cmp_or_die(rtBals[5],ret)
|
||||
ret = t.expect_getend("Total balance:").strip()
|
||||
cmp_or_die(rtBals[6],ret)
|
||||
return t
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue