cmdtest.py regtest: enable deterministic testing with descriptor wallet
This commit is contained in:
parent
ba0bdb381c
commit
a3f9676677
5 changed files with 67 additions and 9 deletions
|
|
@ -37,12 +37,15 @@ opts_data = {
|
|||
-n, --setup-no-stop-daemon Don't stop daemon after setup is finished
|
||||
-q, --quiet Produce quieter output
|
||||
-v, --verbose Produce more verbose output
|
||||
-w, --wallet-src=DIR Initialize miner and tracking wallets from wallets in
|
||||
DIR instead of creating new ones
|
||||
""",
|
||||
'notes': """
|
||||
|
||||
AVAILABLE COMMANDS
|
||||
|
||||
setup - set up Bob and Alice regtest mode
|
||||
create_wallets - create Miner wallet and Bob and Alice’s tracking wallets
|
||||
start - start the regtest coin daemon
|
||||
stop - stop the regtest coin daemon
|
||||
generate N - mine N blocks (defaults to 1)
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ class MMGenRegtest(MMGenObject):
|
|||
coins = ('btc', 'bch', 'ltc')
|
||||
usr_cmds = (
|
||||
'setup',
|
||||
'create_wallets',
|
||||
'generate',
|
||||
'send',
|
||||
'start',
|
||||
|
|
@ -95,12 +96,27 @@ class MMGenRegtest(MMGenObject):
|
|||
async def rpc(self):
|
||||
return await rpc_init(self.cfg, self.proto, backend=None, daemon=self.d)
|
||||
|
||||
@property
|
||||
async def miner_bip_hd_node(self):
|
||||
if not hasattr(self, '_miner_bip_hd_node'):
|
||||
from ...cfg import Config
|
||||
from ...bip_hd import BipHDNode
|
||||
data = await self.rpc_call('gethdkeys', {'private': True}, wallet='miner')
|
||||
self._miner_bip_hd_node = BipHDNode.from_path(
|
||||
Config({'regtest': True}),
|
||||
None,
|
||||
"m/{}'/1'/0'/0/0".format(44 if self.proto.coin == 'BCH' else 84),
|
||||
xprv = data[0]['xprv'],
|
||||
addr_type = 'compressed' if self.proto.coin == 'BCH' else 'bech32',
|
||||
no_path_checks = True)
|
||||
return self._miner_bip_hd_node
|
||||
|
||||
@property
|
||||
async def miner_addr(self):
|
||||
if not hasattr(self, '_miner_addr'):
|
||||
self._miner_addr = (
|
||||
self.bdb_miner_addrs[self.coin] if self.bdb_wallet else
|
||||
await self.rpc_call('getnewaddress', wallet='miner'))
|
||||
(await self.miner_bip_hd_node).address)
|
||||
return self._miner_addr
|
||||
|
||||
@property
|
||||
|
|
@ -108,7 +124,7 @@ class MMGenRegtest(MMGenObject):
|
|||
if not hasattr(self, '_miner_wif'):
|
||||
self._miner_wif = (
|
||||
self.bdb_miner_wif if self.bdb_wallet else
|
||||
None)
|
||||
(await self.miner_bip_hd_node).privkey.wif)
|
||||
return self._miner_wif
|
||||
|
||||
def create_hdseed_wif(self):
|
||||
|
|
@ -150,7 +166,19 @@ class MMGenRegtest(MMGenObject):
|
|||
descriptors = not self.bdb_wallet,
|
||||
load_on_startup = False)
|
||||
|
||||
async def setup(self):
|
||||
async def copy_wallet(self, user):
|
||||
gmsg(f'Copying {capfirst(user)}’s tracking wallet')
|
||||
from shutil import copytree
|
||||
src = os.path.join(self.cfg.wallet_src, user)
|
||||
if not os.path.exists(src):
|
||||
die(2, f'Source wallet ‘{os.path.abspath(src)}’ does not exist!')
|
||||
dest = os.path.join(self.d.network_datadir, 'wallets', user)
|
||||
copytree(src, dest)
|
||||
|
||||
async def create_wallets(self):
|
||||
await self.setup(create_wallets_only=True)
|
||||
|
||||
async def setup(self, create_wallets_only=False):
|
||||
|
||||
try:
|
||||
os.makedirs(self.d.datadir)
|
||||
|
|
@ -167,7 +195,19 @@ class MMGenRegtest(MMGenObject):
|
|||
self.d.start(silent=True)
|
||||
|
||||
for user in ('miner', 'bob', 'alice'):
|
||||
await self.create_wallet(user)
|
||||
if self.cfg.wallet_src:
|
||||
await self.copy_wallet(user)
|
||||
else:
|
||||
await self.create_wallet(user)
|
||||
|
||||
if create_wallets_only:
|
||||
msg(f"Wallets are in '{self.d.network_datadir}/wallets'")
|
||||
msg('Stopping regtest daemon')
|
||||
await self.rpc_call('stop')
|
||||
return
|
||||
|
||||
if self.cfg.wallet_src:
|
||||
await self.load_wallets()
|
||||
|
||||
# BCH and LTC daemons refuse to set HD seed with empty blockchain ("in IBD" error),
|
||||
# so generate a block:
|
||||
|
|
@ -204,6 +244,9 @@ class MMGenRegtest(MMGenObject):
|
|||
async def start_daemon(self, *, reindex=False, silent=True):
|
||||
self.init_daemon(reindex=reindex)
|
||||
self.d.start(silent=silent)
|
||||
await self.load_wallets()
|
||||
|
||||
async def load_wallets(self):
|
||||
for user in ('miner', 'bob', 'alice'):
|
||||
msg(f'Loading {capfirst(user)}’s wallet')
|
||||
await self.rpc_call('loadwallet', user, start_daemon=False)
|
||||
|
|
|
|||
|
|
@ -60,14 +60,14 @@ class CmdTestChainsplit(CmdTestRegtest):
|
|||
|
||||
def split_fork(self):
|
||||
self.coin = 'B2X'
|
||||
t = self.spawn('mmgen-regtest', ['fork', 'btc'])
|
||||
t = self.spawn('mmgen-regtest', self.regtest_opts + ['fork', 'btc'])
|
||||
t.expect('Creating fork from coin')
|
||||
t.expect('successfully created')
|
||||
t.ok()
|
||||
|
||||
def split_start(self, coin):
|
||||
self.coin = coin
|
||||
t = self.spawn('mmgen-regtest', ['bob'])
|
||||
t = self.spawn('mmgen-regtest', self.regtest_opts + ['bob'])
|
||||
t.expect('Starting')
|
||||
t.expect('done')
|
||||
t.ok()
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ 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, suf, fmt_list, is_hex_str
|
||||
from mmgen.util import msg_r, die, gmsg, capfirst, suf, fmt_list, is_hex_str, fmt
|
||||
from mmgen.protocol import init_proto
|
||||
from mmgen.addrlist import AddrList
|
||||
from mmgen.wallet import Wallet, get_wallet_cls
|
||||
|
|
@ -505,6 +505,7 @@ class CmdTestRegtest(CmdTestBase, CmdTestShared):
|
|||
self.test_rbf = True # tests are non-coin-dependent, so run just once for BTC
|
||||
if cfg.test_suite_deterministic:
|
||||
self.deterministic = True
|
||||
omsg('Deterministic testing enabled!')
|
||||
|
||||
self.spawn_env['MMGEN_BOGUS_SEND'] = ''
|
||||
self.write_to_tmpfile('wallet_password', rt_pw)
|
||||
|
|
@ -548,6 +549,17 @@ class CmdTestRegtest(CmdTestBase, CmdTestShared):
|
|||
rmtree(joinpath(self.tr.data_dir, 'regtest'))
|
||||
except:
|
||||
pass
|
||||
if self.deterministic:
|
||||
action = 'Loading'
|
||||
if not os.path.exists('wallets/alice'):
|
||||
die(1, fmt("""
|
||||
Saved tracking wallets are required for deterministic testing.
|
||||
|
||||
Run ‘mmgen-regtest create_wallets’, move or copy the resulting ‘wallet’
|
||||
directory to the repository root, and re-run the test.
|
||||
"""))
|
||||
else:
|
||||
action = 'Creating'
|
||||
t = self.spawn(
|
||||
'mmgen-regtest',
|
||||
self.regtest_opts
|
||||
|
|
@ -556,7 +568,7 @@ class CmdTestRegtest(CmdTestBase, CmdTestShared):
|
|||
no_passthru_opts = True)
|
||||
t.expect('Starting')
|
||||
for _ in range(3):
|
||||
t.expect('Creating')
|
||||
t.expect(action)
|
||||
for _ in range(17):
|
||||
t.expect('Mined')
|
||||
t.expect('Setup complete')
|
||||
|
|
|
|||
|
|
@ -588,7 +588,7 @@ class CmdTestSwap(CmdTestSwapMethods, CmdTestRegtest, CmdTestAutosignThreaded):
|
|||
addr = next(s for s in strip_ansi_escapes(t.read()).splitlines() if 'C:1 No' in s).split()[3]
|
||||
t = self.spawn(
|
||||
'mmgen-regtest',
|
||||
[coin_arg, 'send', addr, str(amt)],
|
||||
self.regtest_opts + [coin_arg, 'send', addr, str(amt)],
|
||||
no_passthru_opts = ['coin'],
|
||||
no_msg = True)
|
||||
return t
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue