mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-26 19:23:26 -03:00
Add a --descriptors option to various tests
Adds a --descriptors option globally to the test framework. This will make the test create and use descriptor wallets. However some tests may not work with this. Some tests are modified to work with --descriptors and run with that option in test_runer: * wallet_basic.py * wallet_encryption.py * wallet_keypool.py * wallet_keypool_topup.py * wallet_labels.py * wallet_avoidreuse.py
This commit is contained in:
parent
869f7ab30a
commit
223588b1bb
12 changed files with 347 additions and 163 deletions
|
@ -4,13 +4,14 @@
|
||||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
"""Test multisig RPCs"""
|
"""Test multisig RPCs"""
|
||||||
|
|
||||||
|
from test_framework.authproxy import JSONRPCException
|
||||||
from test_framework.descriptors import descsum_create, drop_origins
|
from test_framework.descriptors import descsum_create, drop_origins
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import (
|
from test_framework.util import (
|
||||||
assert_raises_rpc_error,
|
assert_raises_rpc_error,
|
||||||
assert_equal,
|
assert_equal,
|
||||||
)
|
)
|
||||||
from test_framework.key import ECPubKey
|
from test_framework.key import ECPubKey, ECKey, bytes_to_wif
|
||||||
|
|
||||||
import binascii
|
import binascii
|
||||||
import decimal
|
import decimal
|
||||||
|
@ -28,10 +29,14 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
|
||||||
self.skip_if_no_wallet()
|
self.skip_if_no_wallet()
|
||||||
|
|
||||||
def get_keys(self):
|
def get_keys(self):
|
||||||
|
self.pub = []
|
||||||
|
self.priv = []
|
||||||
node0, node1, node2 = self.nodes
|
node0, node1, node2 = self.nodes
|
||||||
add = [node1.getnewaddress() for _ in range(self.nkeys)]
|
for _ in range(self.nkeys):
|
||||||
self.pub = [node1.getaddressinfo(a)["pubkey"] for a in add]
|
k = ECKey()
|
||||||
self.priv = [node1.dumpprivkey(a) for a in add]
|
k.generate()
|
||||||
|
self.pub.append(k.get_pubkey().get_bytes().hex())
|
||||||
|
self.priv.append(bytes_to_wif(k.get_bytes(), k.is_compressed))
|
||||||
self.final = node2.getnewaddress()
|
self.final = node2.getnewaddress()
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
|
@ -64,17 +69,20 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
|
||||||
pk_obj.compressed = False
|
pk_obj.compressed = False
|
||||||
pk2 = binascii.hexlify(pk_obj.get_bytes()).decode()
|
pk2 = binascii.hexlify(pk_obj.get_bytes()).decode()
|
||||||
|
|
||||||
|
node0.createwallet(wallet_name='wmulti0', disable_private_keys=True)
|
||||||
|
wmulti0 = node0.get_wallet_rpc('wmulti0')
|
||||||
|
|
||||||
# Check all permutations of keys because order matters apparently
|
# Check all permutations of keys because order matters apparently
|
||||||
for keys in itertools.permutations([pk0, pk1, pk2]):
|
for keys in itertools.permutations([pk0, pk1, pk2]):
|
||||||
# Results should be the same as this legacy one
|
# Results should be the same as this legacy one
|
||||||
legacy_addr = node0.createmultisig(2, keys, 'legacy')['address']
|
legacy_addr = node0.createmultisig(2, keys, 'legacy')['address']
|
||||||
assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'legacy')['address'])
|
assert_equal(legacy_addr, wmulti0.addmultisigaddress(2, keys, '', 'legacy')['address'])
|
||||||
|
|
||||||
# Generate addresses with the segwit types. These should all make legacy addresses
|
# Generate addresses with the segwit types. These should all make legacy addresses
|
||||||
assert_equal(legacy_addr, node0.createmultisig(2, keys, 'bech32')['address'])
|
assert_equal(legacy_addr, wmulti0.createmultisig(2, keys, 'bech32')['address'])
|
||||||
assert_equal(legacy_addr, node0.createmultisig(2, keys, 'p2sh-segwit')['address'])
|
assert_equal(legacy_addr, wmulti0.createmultisig(2, keys, 'p2sh-segwit')['address'])
|
||||||
assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'bech32')['address'])
|
assert_equal(legacy_addr, wmulti0.addmultisigaddress(2, keys, '', 'bech32')['address'])
|
||||||
assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'p2sh-segwit')['address'])
|
assert_equal(legacy_addr, wmulti0.addmultisigaddress(2, keys, '', 'p2sh-segwit')['address'])
|
||||||
|
|
||||||
self.log.info('Testing sortedmulti descriptors with BIP 67 test vectors')
|
self.log.info('Testing sortedmulti descriptors with BIP 67 test vectors')
|
||||||
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/rpc_bip67.json'), encoding='utf-8') as f:
|
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/rpc_bip67.json'), encoding='utf-8') as f:
|
||||||
|
@ -89,6 +97,8 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
|
||||||
assert_equal(self.nodes[0].deriveaddresses(sorted_key_desc)[0], t['address'])
|
assert_equal(self.nodes[0].deriveaddresses(sorted_key_desc)[0], t['address'])
|
||||||
|
|
||||||
def check_addmultisigaddress_errors(self):
|
def check_addmultisigaddress_errors(self):
|
||||||
|
if self.options.descriptors:
|
||||||
|
return
|
||||||
self.log.info('Check that addmultisigaddress fails when the private keys are missing')
|
self.log.info('Check that addmultisigaddress fails when the private keys are missing')
|
||||||
addresses = [self.nodes[1].getnewaddress(address_type='legacy') for _ in range(2)]
|
addresses = [self.nodes[1].getnewaddress(address_type='legacy') for _ in range(2)]
|
||||||
assert_raises_rpc_error(-5, 'no full public key for address', lambda: self.nodes[0].addmultisigaddress(nrequired=1, keys=addresses))
|
assert_raises_rpc_error(-5, 'no full public key for address', lambda: self.nodes[0].addmultisigaddress(nrequired=1, keys=addresses))
|
||||||
|
@ -115,6 +125,15 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
|
||||||
|
|
||||||
def do_multisig(self):
|
def do_multisig(self):
|
||||||
node0, node1, node2 = self.nodes
|
node0, node1, node2 = self.nodes
|
||||||
|
if 'wmulti' not in node1.listwallets():
|
||||||
|
try:
|
||||||
|
node1.loadwallet('wmulti')
|
||||||
|
except JSONRPCException as e:
|
||||||
|
if e.error['code'] == -18 and 'Wallet wmulti not found' in e.error['message']:
|
||||||
|
node1.createwallet(wallet_name='wmulti', disable_private_keys=True)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
wmulti = node1.get_wallet_rpc('wmulti')
|
||||||
|
|
||||||
# Construct the expected descriptor
|
# Construct the expected descriptor
|
||||||
desc = 'multi({},{})'.format(self.nsigs, ','.join(self.pub))
|
desc = 'multi({},{})'.format(self.nsigs, ','.join(self.pub))
|
||||||
|
@ -134,7 +153,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
|
||||||
assert madd[0:4] == "bcrt" # actually a bech32 address
|
assert madd[0:4] == "bcrt" # actually a bech32 address
|
||||||
|
|
||||||
# compare against addmultisigaddress
|
# compare against addmultisigaddress
|
||||||
msigw = node1.addmultisigaddress(self.nsigs, self.pub, None, self.output_type)
|
msigw = wmulti.addmultisigaddress(self.nsigs, self.pub, None, self.output_type)
|
||||||
maddw = msigw["address"]
|
maddw = msigw["address"]
|
||||||
mredeemw = msigw["redeemScript"]
|
mredeemw = msigw["redeemScript"]
|
||||||
assert_equal(desc, drop_origins(msigw['descriptor']))
|
assert_equal(desc, drop_origins(msigw['descriptor']))
|
||||||
|
@ -194,6 +213,8 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
|
||||||
txinfo = node0.getrawtransaction(tx, True, blk)
|
txinfo = node0.getrawtransaction(tx, True, blk)
|
||||||
self.log.info("n/m=%d/%d %s size=%d vsize=%d weight=%d" % (self.nsigs, self.nkeys, self.output_type, txinfo["size"], txinfo["vsize"], txinfo["weight"]))
|
self.log.info("n/m=%d/%d %s size=%d vsize=%d weight=%d" % (self.nsigs, self.nkeys, self.output_type, txinfo["size"], txinfo["vsize"], txinfo["weight"]))
|
||||||
|
|
||||||
|
wmulti.unloadwallet()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
RpcCreateMultiSigTest().main()
|
RpcCreateMultiSigTest().main()
|
||||||
|
|
|
@ -48,18 +48,23 @@ class PSBTTest(BitcoinTestFramework):
|
||||||
disconnect_nodes(offline_node, 2)
|
disconnect_nodes(offline_node, 2)
|
||||||
disconnect_nodes(mining_node, 0)
|
disconnect_nodes(mining_node, 0)
|
||||||
|
|
||||||
|
# Create watchonly on online_node
|
||||||
|
online_node.createwallet(wallet_name='wonline', disable_private_keys=True)
|
||||||
|
wonline = online_node.get_wallet_rpc('wonline')
|
||||||
|
w2 = online_node.get_wallet_rpc('')
|
||||||
|
|
||||||
# Mine a transaction that credits the offline address
|
# Mine a transaction that credits the offline address
|
||||||
offline_addr = offline_node.getnewaddress(address_type="p2sh-segwit")
|
offline_addr = offline_node.getnewaddress(address_type="p2sh-segwit")
|
||||||
online_addr = online_node.getnewaddress(address_type="p2sh-segwit")
|
online_addr = w2.getnewaddress(address_type="p2sh-segwit")
|
||||||
online_node.importaddress(offline_addr, "", False)
|
wonline.importaddress(offline_addr, "", False)
|
||||||
mining_node.sendtoaddress(address=offline_addr, amount=1.0)
|
mining_node.sendtoaddress(address=offline_addr, amount=1.0)
|
||||||
mining_node.generate(nblocks=1)
|
mining_node.generate(nblocks=1)
|
||||||
self.sync_blocks([mining_node, online_node])
|
self.sync_blocks([mining_node, online_node])
|
||||||
|
|
||||||
# Construct an unsigned PSBT on the online node (who doesn't know the output is Segwit, so will include a non-witness UTXO)
|
# Construct an unsigned PSBT on the online node (who doesn't know the output is Segwit, so will include a non-witness UTXO)
|
||||||
utxos = online_node.listunspent(addresses=[offline_addr])
|
utxos = wonline.listunspent(addresses=[offline_addr])
|
||||||
raw = online_node.createrawtransaction([{"txid":utxos[0]["txid"], "vout":utxos[0]["vout"]}],[{online_addr:0.9999}])
|
raw = wonline.createrawtransaction([{"txid":utxos[0]["txid"], "vout":utxos[0]["vout"]}],[{online_addr:0.9999}])
|
||||||
psbt = online_node.walletprocesspsbt(online_node.converttopsbt(raw))["psbt"]
|
psbt = wonline.walletprocesspsbt(online_node.converttopsbt(raw))["psbt"]
|
||||||
assert "non_witness_utxo" in mining_node.decodepsbt(psbt)["inputs"][0]
|
assert "non_witness_utxo" in mining_node.decodepsbt(psbt)["inputs"][0]
|
||||||
|
|
||||||
# Have the offline node sign the PSBT (which will update the UTXO to segwit)
|
# Have the offline node sign the PSBT (which will update the UTXO to segwit)
|
||||||
|
@ -72,6 +77,8 @@ class PSBTTest(BitcoinTestFramework):
|
||||||
self.sync_blocks([mining_node, online_node])
|
self.sync_blocks([mining_node, online_node])
|
||||||
assert_equal(online_node.gettxout(txid,0)["confirmations"], 1)
|
assert_equal(online_node.gettxout(txid,0)["confirmations"], 1)
|
||||||
|
|
||||||
|
wonline.unloadwallet()
|
||||||
|
|
||||||
# Reconnect
|
# Reconnect
|
||||||
connect_nodes(self.nodes[0], 1)
|
connect_nodes(self.nodes[0], 1)
|
||||||
connect_nodes(self.nodes[0], 2)
|
connect_nodes(self.nodes[0], 2)
|
||||||
|
@ -89,13 +96,23 @@ class PSBTTest(BitcoinTestFramework):
|
||||||
final_tx = self.nodes[0].finalizepsbt(signed_tx)['hex']
|
final_tx = self.nodes[0].finalizepsbt(signed_tx)['hex']
|
||||||
self.nodes[0].sendrawtransaction(final_tx)
|
self.nodes[0].sendrawtransaction(final_tx)
|
||||||
|
|
||||||
# Create p2sh, p2wpkh, and p2wsh addresses
|
# Get pubkeys
|
||||||
pubkey0 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())['pubkey']
|
pubkey0 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())['pubkey']
|
||||||
pubkey1 = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())['pubkey']
|
pubkey1 = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())['pubkey']
|
||||||
pubkey2 = self.nodes[2].getaddressinfo(self.nodes[2].getnewaddress())['pubkey']
|
pubkey2 = self.nodes[2].getaddressinfo(self.nodes[2].getnewaddress())['pubkey']
|
||||||
p2sh = self.nodes[1].addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "", "legacy")['address']
|
|
||||||
p2wsh = self.nodes[1].addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "", "bech32")['address']
|
# Setup watchonly wallets
|
||||||
p2sh_p2wsh = self.nodes[1].addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "", "p2sh-segwit")['address']
|
self.nodes[2].createwallet(wallet_name='wmulti', disable_private_keys=True)
|
||||||
|
wmulti = self.nodes[2].get_wallet_rpc('wmulti')
|
||||||
|
|
||||||
|
# Create all the addresses
|
||||||
|
p2sh = wmulti.addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "", "legacy")['address']
|
||||||
|
p2wsh = wmulti.addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "", "bech32")['address']
|
||||||
|
p2sh_p2wsh = wmulti.addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "", "p2sh-segwit")['address']
|
||||||
|
if not self.options.descriptors:
|
||||||
|
wmulti.importaddress(p2sh)
|
||||||
|
wmulti.importaddress(p2wsh)
|
||||||
|
wmulti.importaddress(p2sh_p2wsh)
|
||||||
p2wpkh = self.nodes[1].getnewaddress("", "bech32")
|
p2wpkh = self.nodes[1].getnewaddress("", "bech32")
|
||||||
p2pkh = self.nodes[1].getnewaddress("", "legacy")
|
p2pkh = self.nodes[1].getnewaddress("", "legacy")
|
||||||
p2sh_p2wpkh = self.nodes[1].getnewaddress("", "p2sh-segwit")
|
p2sh_p2wpkh = self.nodes[1].getnewaddress("", "p2sh-segwit")
|
||||||
|
@ -146,11 +163,14 @@ class PSBTTest(BitcoinTestFramework):
|
||||||
assert_raises_rpc_error(-4, "Fee exceeds maximum configured by -maxtxfee", self.nodes[1].walletcreatefundedpsbt, [{"txid":txid,"vout":p2wpkh_pos},{"txid":txid,"vout":p2sh_p2wpkh_pos},{"txid":txid,"vout":p2pkh_pos}], {self.nodes[1].getnewaddress():29.99}, 0, {"feeRate": 10})
|
assert_raises_rpc_error(-4, "Fee exceeds maximum configured by -maxtxfee", self.nodes[1].walletcreatefundedpsbt, [{"txid":txid,"vout":p2wpkh_pos},{"txid":txid,"vout":p2sh_p2wpkh_pos},{"txid":txid,"vout":p2pkh_pos}], {self.nodes[1].getnewaddress():29.99}, 0, {"feeRate": 10})
|
||||||
|
|
||||||
# partially sign multisig things with node 1
|
# partially sign multisig things with node 1
|
||||||
psbtx = self.nodes[1].walletcreatefundedpsbt([{"txid":txid,"vout":p2wsh_pos},{"txid":txid,"vout":p2sh_pos},{"txid":txid,"vout":p2sh_p2wsh_pos}], {self.nodes[1].getnewaddress():29.99})['psbt']
|
psbtx = wmulti.walletcreatefundedpsbt(inputs=[{"txid":txid,"vout":p2wsh_pos},{"txid":txid,"vout":p2sh_pos},{"txid":txid,"vout":p2sh_p2wsh_pos}], outputs={self.nodes[1].getnewaddress():29.99}, options={'changeAddress': self.nodes[1].getrawchangeaddress()})['psbt']
|
||||||
walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(psbtx)
|
walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(psbtx)
|
||||||
psbtx = walletprocesspsbt_out['psbt']
|
psbtx = walletprocesspsbt_out['psbt']
|
||||||
assert_equal(walletprocesspsbt_out['complete'], False)
|
assert_equal(walletprocesspsbt_out['complete'], False)
|
||||||
|
|
||||||
|
# Unload wmulti, we don't need it anymore
|
||||||
|
wmulti.unloadwallet()
|
||||||
|
|
||||||
# partially sign with node 2. This should be complete and sendable
|
# partially sign with node 2. This should be complete and sendable
|
||||||
walletprocesspsbt_out = self.nodes[2].walletprocesspsbt(psbtx)
|
walletprocesspsbt_out = self.nodes[2].walletprocesspsbt(psbtx)
|
||||||
assert_equal(walletprocesspsbt_out['complete'], True)
|
assert_equal(walletprocesspsbt_out['complete'], True)
|
||||||
|
@ -297,7 +317,7 @@ class PSBTTest(BitcoinTestFramework):
|
||||||
|
|
||||||
# Signer tests
|
# Signer tests
|
||||||
for i, signer in enumerate(signers):
|
for i, signer in enumerate(signers):
|
||||||
self.nodes[2].createwallet("wallet{}".format(i))
|
self.nodes[2].createwallet(wallet_name="wallet{}".format(i))
|
||||||
wrpc = self.nodes[2].get_wallet_rpc("wallet{}".format(i))
|
wrpc = self.nodes[2].get_wallet_rpc("wallet{}".format(i))
|
||||||
for key in signer['privkeys']:
|
for key in signer['privkeys']:
|
||||||
wrpc.importprivkey(key)
|
wrpc.importprivkey(key)
|
||||||
|
|
|
@ -8,6 +8,8 @@ keys, and is trivially vulnerable to side channel attacks. Do not use for
|
||||||
anything but tests."""
|
anything but tests."""
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
from .address import byte_to_base58
|
||||||
|
|
||||||
def modinv(a, n):
|
def modinv(a, n):
|
||||||
"""Compute the modular inverse of a modulo n
|
"""Compute the modular inverse of a modulo n
|
||||||
|
|
||||||
|
@ -384,3 +386,14 @@ class ECKey():
|
||||||
rb = r.to_bytes((r.bit_length() + 8) // 8, 'big')
|
rb = r.to_bytes((r.bit_length() + 8) // 8, 'big')
|
||||||
sb = s.to_bytes((s.bit_length() + 8) // 8, 'big')
|
sb = s.to_bytes((s.bit_length() + 8) // 8, 'big')
|
||||||
return b'\x30' + bytes([4 + len(rb) + len(sb), 2, len(rb)]) + rb + bytes([2, len(sb)]) + sb
|
return b'\x30' + bytes([4 + len(rb) + len(sb), 2, len(rb)]) + rb + bytes([2, len(sb)]) + sb
|
||||||
|
|
||||||
|
def bytes_to_wif(b, compressed=True):
|
||||||
|
if compressed:
|
||||||
|
b += b'\x01'
|
||||||
|
return byte_to_base58(b, 239)
|
||||||
|
|
||||||
|
def generate_wif_key():
|
||||||
|
# Makes a WIF privkey for imports
|
||||||
|
k = ECKey()
|
||||||
|
k.generate()
|
||||||
|
return bytes_to_wif(k.get_bytes(), k.is_compressed)
|
||||||
|
|
|
@ -165,6 +165,8 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
||||||
help="run nodes under the valgrind memory error detector: expect at least a ~10x slowdown, valgrind 3.14 or later required")
|
help="run nodes under the valgrind memory error detector: expect at least a ~10x slowdown, valgrind 3.14 or later required")
|
||||||
parser.add_argument("--randomseed", type=int,
|
parser.add_argument("--randomseed", type=int,
|
||||||
help="set a random seed for deterministically reproducing a previous test run")
|
help="set a random seed for deterministically reproducing a previous test run")
|
||||||
|
parser.add_argument("--descriptors", default=False, action="store_true",
|
||||||
|
help="Run test using a descriptor wallet")
|
||||||
self.add_options(parser)
|
self.add_options(parser)
|
||||||
self.options = parser.parse_args()
|
self.options = parser.parse_args()
|
||||||
|
|
||||||
|
@ -333,11 +335,23 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
||||||
|
|
||||||
def setup_nodes(self):
|
def setup_nodes(self):
|
||||||
"""Override this method to customize test node setup"""
|
"""Override this method to customize test node setup"""
|
||||||
extra_args = None
|
extra_args = [[]] * self.num_nodes
|
||||||
|
wallets = [[]] * self.num_nodes
|
||||||
if hasattr(self, "extra_args"):
|
if hasattr(self, "extra_args"):
|
||||||
extra_args = self.extra_args
|
extra_args = self.extra_args
|
||||||
|
wallets = [[x for x in eargs if x.startswith('-wallet=')] for eargs in extra_args]
|
||||||
|
extra_args = [x + ['-nowallet'] for x in extra_args]
|
||||||
self.add_nodes(self.num_nodes, extra_args)
|
self.add_nodes(self.num_nodes, extra_args)
|
||||||
self.start_nodes()
|
self.start_nodes()
|
||||||
|
for i, n in enumerate(self.nodes):
|
||||||
|
n.extra_args.pop()
|
||||||
|
if '-wallet=0' in n.extra_args or '-nowallet' in n.extra_args or '-disablewallet' in n.extra_args or not self.is_wallet_compiled():
|
||||||
|
continue
|
||||||
|
if '-wallet=' not in wallets[i] and not any([x.startswith('-wallet=') for x in wallets[i]]):
|
||||||
|
wallets[i].append('-wallet=')
|
||||||
|
for w in wallets[i]:
|
||||||
|
wallet_name = w.split('=', 1)[1]
|
||||||
|
n.createwallet(wallet_name=wallet_name, descriptors=self.options.descriptors)
|
||||||
self.import_deterministic_coinbase_privkeys()
|
self.import_deterministic_coinbase_privkeys()
|
||||||
if not self.setup_clean_chain:
|
if not self.setup_clean_chain:
|
||||||
for n in self.nodes:
|
for n in self.nodes:
|
||||||
|
@ -408,6 +422,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
||||||
use_cli=self.options.usecli,
|
use_cli=self.options.usecli,
|
||||||
start_perf=self.options.perf,
|
start_perf=self.options.perf,
|
||||||
use_valgrind=self.options.valgrind,
|
use_valgrind=self.options.valgrind,
|
||||||
|
descriptors=self.options.descriptors,
|
||||||
))
|
))
|
||||||
|
|
||||||
def start_node(self, i, *args, **kwargs):
|
def start_node(self, i, *args, **kwargs):
|
||||||
|
@ -547,6 +562,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
||||||
bitcoin_cli=self.options.bitcoincli,
|
bitcoin_cli=self.options.bitcoincli,
|
||||||
coverage_dir=None,
|
coverage_dir=None,
|
||||||
cwd=self.options.tmpdir,
|
cwd=self.options.tmpdir,
|
||||||
|
descriptors=self.options.descriptors,
|
||||||
))
|
))
|
||||||
self.start_node(CACHE_NODE_ID)
|
self.start_node(CACHE_NODE_ID)
|
||||||
cache_node = self.nodes[CACHE_NODE_ID]
|
cache_node = self.nodes[CACHE_NODE_ID]
|
||||||
|
|
|
@ -62,7 +62,7 @@ class TestNode():
|
||||||
To make things easier for the test writer, any unrecognised messages will
|
To make things easier for the test writer, any unrecognised messages will
|
||||||
be dispatched to the RPC connection."""
|
be dispatched to the RPC connection."""
|
||||||
|
|
||||||
def __init__(self, i, datadir, *, chain, rpchost, timewait, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None):
|
def __init__(self, i, datadir, *, chain, rpchost, timewait, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None, descriptors=False):
|
||||||
"""
|
"""
|
||||||
Kwargs:
|
Kwargs:
|
||||||
start_perf (bool): If True, begin profiling the node with `perf` as soon as
|
start_perf (bool): If True, begin profiling the node with `perf` as soon as
|
||||||
|
@ -80,6 +80,7 @@ class TestNode():
|
||||||
self.binary = bitcoind
|
self.binary = bitcoind
|
||||||
self.coverage_dir = coverage_dir
|
self.coverage_dir = coverage_dir
|
||||||
self.cwd = cwd
|
self.cwd = cwd
|
||||||
|
self.descriptors = descriptors
|
||||||
if extra_conf is not None:
|
if extra_conf is not None:
|
||||||
append_config(datadir, extra_conf)
|
append_config(datadir, extra_conf)
|
||||||
# Most callers will just need to add extra args to the standard list below.
|
# Most callers will just need to add extra args to the standard list below.
|
||||||
|
@ -171,10 +172,10 @@ class TestNode():
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
"""Dispatches any unrecognised messages to the RPC connection or a CLI instance."""
|
"""Dispatches any unrecognised messages to the RPC connection or a CLI instance."""
|
||||||
if self.use_cli:
|
if self.use_cli:
|
||||||
return getattr(RPCOverloadWrapper(self.cli, True), name)
|
return getattr(RPCOverloadWrapper(self.cli, True, self.descriptors), name)
|
||||||
else:
|
else:
|
||||||
assert self.rpc_connected and self.rpc is not None, self._node_msg("Error: no RPC connection")
|
assert self.rpc_connected and self.rpc is not None, self._node_msg("Error: no RPC connection")
|
||||||
return getattr(RPCOverloadWrapper(self.rpc), name)
|
return getattr(RPCOverloadWrapper(self.rpc, descriptors=self.descriptors), name)
|
||||||
|
|
||||||
def start(self, extra_args=None, *, cwd=None, stdout=None, stderr=None, **kwargs):
|
def start(self, extra_args=None, *, cwd=None, stdout=None, stderr=None, **kwargs):
|
||||||
"""Start the node."""
|
"""Start the node."""
|
||||||
|
@ -266,11 +267,11 @@ class TestNode():
|
||||||
|
|
||||||
def get_wallet_rpc(self, wallet_name):
|
def get_wallet_rpc(self, wallet_name):
|
||||||
if self.use_cli:
|
if self.use_cli:
|
||||||
return RPCOverloadWrapper(self.cli("-rpcwallet={}".format(wallet_name)), True)
|
return RPCOverloadWrapper(self.cli("-rpcwallet={}".format(wallet_name)), True, self.descriptors)
|
||||||
else:
|
else:
|
||||||
assert self.rpc_connected and self.rpc, self._node_msg("RPC not connected")
|
assert self.rpc_connected and self.rpc, self._node_msg("RPC not connected")
|
||||||
wallet_path = "wallet/{}".format(urllib.parse.quote(wallet_name))
|
wallet_path = "wallet/{}".format(urllib.parse.quote(wallet_name))
|
||||||
return RPCOverloadWrapper(self.rpc / wallet_path)
|
return RPCOverloadWrapper(self.rpc / wallet_path, descriptors=self.descriptors)
|
||||||
|
|
||||||
def stop_node(self, expected_stderr='', wait=0):
|
def stop_node(self, expected_stderr='', wait=0):
|
||||||
"""Stop the node."""
|
"""Stop the node."""
|
||||||
|
@ -598,13 +599,28 @@ class TestNodeCLI():
|
||||||
return cli_stdout.rstrip("\n")
|
return cli_stdout.rstrip("\n")
|
||||||
|
|
||||||
class RPCOverloadWrapper():
|
class RPCOverloadWrapper():
|
||||||
def __init__(self, rpc, cli=False):
|
def __init__(self, rpc, cli=False, descriptors=False):
|
||||||
self.rpc = rpc
|
self.rpc = rpc
|
||||||
self.is_cli = cli
|
self.is_cli = cli
|
||||||
|
self.descriptors = descriptors
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
return getattr(self.rpc, name)
|
return getattr(self.rpc, name)
|
||||||
|
|
||||||
|
def createwallet(self, wallet_name, disable_private_keys=None, blank=None, passphrase=None, avoid_reuse=None, descriptors=None):
|
||||||
|
if self.is_cli:
|
||||||
|
if disable_private_keys is None:
|
||||||
|
disable_private_keys = 'null'
|
||||||
|
if blank is None:
|
||||||
|
blank = 'null'
|
||||||
|
if passphrase is None:
|
||||||
|
passphrase = ''
|
||||||
|
if avoid_reuse is None:
|
||||||
|
avoid_reuse = 'null'
|
||||||
|
if descriptors is None:
|
||||||
|
descriptors = self.descriptors
|
||||||
|
return self.__getattr__('createwallet')(wallet_name, disable_private_keys, blank, passphrase, avoid_reuse, descriptors)
|
||||||
|
|
||||||
def importprivkey(self, privkey, label=None, rescan=None):
|
def importprivkey(self, privkey, label=None, rescan=None):
|
||||||
wallet_info = self.getwalletinfo()
|
wallet_info = self.getwalletinfo()
|
||||||
if self.is_cli:
|
if self.is_cli:
|
||||||
|
|
|
@ -76,6 +76,7 @@ BASE_SCRIPTS = [
|
||||||
# Scripts that are run by default.
|
# Scripts that are run by default.
|
||||||
# Longest test should go first, to favor running tests in parallel
|
# Longest test should go first, to favor running tests in parallel
|
||||||
'wallet_hd.py',
|
'wallet_hd.py',
|
||||||
|
'wallet_hd.py --descriptors',
|
||||||
'wallet_backup.py',
|
'wallet_backup.py',
|
||||||
# vv Tests less than 5m vv
|
# vv Tests less than 5m vv
|
||||||
'mining_getblocktemplate_longpoll.py',
|
'mining_getblocktemplate_longpoll.py',
|
||||||
|
@ -86,7 +87,9 @@ BASE_SCRIPTS = [
|
||||||
'feature_segwit.py',
|
'feature_segwit.py',
|
||||||
# vv Tests less than 2m vv
|
# vv Tests less than 2m vv
|
||||||
'wallet_basic.py',
|
'wallet_basic.py',
|
||||||
|
'wallet_basic.py --descriptors',
|
||||||
'wallet_labels.py',
|
'wallet_labels.py',
|
||||||
|
'wallet_labels.py --descriptors',
|
||||||
'p2p_segwit.py',
|
'p2p_segwit.py',
|
||||||
'p2p_timeouts.py',
|
'p2p_timeouts.py',
|
||||||
'p2p_tx_download.py',
|
'p2p_tx_download.py',
|
||||||
|
@ -109,6 +112,7 @@ BASE_SCRIPTS = [
|
||||||
'feature_abortnode.py',
|
'feature_abortnode.py',
|
||||||
# vv Tests less than 30s vv
|
# vv Tests less than 30s vv
|
||||||
'wallet_keypool_topup.py',
|
'wallet_keypool_topup.py',
|
||||||
|
'wallet_keypool_topup.py --descriptors',
|
||||||
'feature_fee_estimation.py',
|
'feature_fee_estimation.py',
|
||||||
'interface_zmq.py',
|
'interface_zmq.py',
|
||||||
'interface_bitcoin_cli.py',
|
'interface_bitcoin_cli.py',
|
||||||
|
@ -122,6 +126,7 @@ BASE_SCRIPTS = [
|
||||||
'interface_rest.py',
|
'interface_rest.py',
|
||||||
'mempool_spend_coinbase.py',
|
'mempool_spend_coinbase.py',
|
||||||
'wallet_avoidreuse.py',
|
'wallet_avoidreuse.py',
|
||||||
|
'wallet_avoidreuse.py --descriptors',
|
||||||
'mempool_reorg.py',
|
'mempool_reorg.py',
|
||||||
'mempool_persist.py',
|
'mempool_persist.py',
|
||||||
'wallet_multiwallet.py',
|
'wallet_multiwallet.py',
|
||||||
|
@ -134,6 +139,7 @@ BASE_SCRIPTS = [
|
||||||
'interface_http.py',
|
'interface_http.py',
|
||||||
'interface_rpc.py',
|
'interface_rpc.py',
|
||||||
'rpc_psbt.py',
|
'rpc_psbt.py',
|
||||||
|
'rpc_psbt.py --descriptors',
|
||||||
'rpc_users.py',
|
'rpc_users.py',
|
||||||
'rpc_whitelist.py',
|
'rpc_whitelist.py',
|
||||||
'feature_proxy.py',
|
'feature_proxy.py',
|
||||||
|
@ -147,6 +153,7 @@ BASE_SCRIPTS = [
|
||||||
'p2p_addr_relay.py',
|
'p2p_addr_relay.py',
|
||||||
'rpc_net.py',
|
'rpc_net.py',
|
||||||
'wallet_keypool.py',
|
'wallet_keypool.py',
|
||||||
|
'wallet_keypool.py --descriptors',
|
||||||
'wallet_descriptor.py',
|
'wallet_descriptor.py',
|
||||||
'p2p_mempool.py',
|
'p2p_mempool.py',
|
||||||
'p2p_filter.py',
|
'p2p_filter.py',
|
||||||
|
@ -169,6 +176,7 @@ BASE_SCRIPTS = [
|
||||||
'mempool_packages.py',
|
'mempool_packages.py',
|
||||||
'mempool_package_onemore.py',
|
'mempool_package_onemore.py',
|
||||||
'rpc_createmultisig.py',
|
'rpc_createmultisig.py',
|
||||||
|
'rpc_createmultisig.py --descriptors',
|
||||||
'feature_versionbits_warning.py',
|
'feature_versionbits_warning.py',
|
||||||
'rpc_preciousblock.py',
|
'rpc_preciousblock.py',
|
||||||
'wallet_importprunedfunds.py',
|
'wallet_importprunedfunds.py',
|
||||||
|
@ -192,6 +200,7 @@ BASE_SCRIPTS = [
|
||||||
'wallet_listsinceblock.py',
|
'wallet_listsinceblock.py',
|
||||||
'p2p_leak.py',
|
'p2p_leak.py',
|
||||||
'wallet_encryption.py',
|
'wallet_encryption.py',
|
||||||
|
'wallet_encryption.py --descriptors',
|
||||||
'feature_dersig.py',
|
'feature_dersig.py',
|
||||||
'feature_cltv.py',
|
'feature_cltv.py',
|
||||||
'rpc_uptime.py',
|
'rpc_uptime.py',
|
||||||
|
|
|
@ -133,7 +133,7 @@ class AvoidReuseTest(BitcoinTestFramework):
|
||||||
tempwallet = ".wallet_avoidreuse.py_test_immutable_wallet.dat"
|
tempwallet = ".wallet_avoidreuse.py_test_immutable_wallet.dat"
|
||||||
|
|
||||||
# Create a wallet with disable_private_keys set; this should work
|
# Create a wallet with disable_private_keys set; this should work
|
||||||
self.nodes[1].createwallet(tempwallet, True)
|
self.nodes[1].createwallet(wallet_name=tempwallet, disable_private_keys=True)
|
||||||
w = self.nodes[1].get_wallet_rpc(tempwallet)
|
w = self.nodes[1].get_wallet_rpc(tempwallet)
|
||||||
|
|
||||||
# Attempt to unset the disable_private_keys flag; this should not work
|
# Attempt to unset the disable_private_keys flag; this should not work
|
||||||
|
@ -249,6 +249,7 @@ class AvoidReuseTest(BitcoinTestFramework):
|
||||||
# getbalances should show no used, 5 btc trusted
|
# getbalances should show no used, 5 btc trusted
|
||||||
assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})
|
assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})
|
||||||
|
|
||||||
|
if not self.options.descriptors:
|
||||||
# For the second send, we transmute it to a related single-key address
|
# For the second send, we transmute it to a related single-key address
|
||||||
# to make sure it's also detected as re-use
|
# to make sure it's also detected as re-use
|
||||||
fund_spk = self.nodes[0].getaddressinfo(fundaddr)["scriptPubKey"]
|
fund_spk = self.nodes[0].getaddressinfo(fundaddr)["scriptPubKey"]
|
||||||
|
|
|
@ -49,6 +49,7 @@ class WalletTest(BitcoinTestFramework):
|
||||||
return self.nodes[0].decoderawtransaction(txn)['vsize']
|
return self.nodes[0].decoderawtransaction(txn)['vsize']
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
|
|
||||||
# Check that there's no UTXO on none of the nodes
|
# Check that there's no UTXO on none of the nodes
|
||||||
assert_equal(len(self.nodes[0].listunspent()), 0)
|
assert_equal(len(self.nodes[0].listunspent()), 0)
|
||||||
assert_equal(len(self.nodes[1].listunspent()), 0)
|
assert_equal(len(self.nodes[1].listunspent()), 0)
|
||||||
|
@ -219,7 +220,7 @@ class WalletTest(BitcoinTestFramework):
|
||||||
assert_equal(self.nodes[2].getbalance(), node_2_bal)
|
assert_equal(self.nodes[2].getbalance(), node_2_bal)
|
||||||
node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))
|
node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))
|
||||||
|
|
||||||
self.start_node(3)
|
self.start_node(3, self.nodes[3].extra_args)
|
||||||
connect_nodes(self.nodes[0], 3)
|
connect_nodes(self.nodes[0], 3)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|
||||||
|
@ -315,6 +316,8 @@ class WalletTest(BitcoinTestFramework):
|
||||||
# This will raise an exception since generate does not accept a string
|
# This will raise an exception since generate does not accept a string
|
||||||
assert_raises_rpc_error(-1, "not an integer", self.nodes[0].generate, "2")
|
assert_raises_rpc_error(-1, "not an integer", self.nodes[0].generate, "2")
|
||||||
|
|
||||||
|
if not self.options.descriptors:
|
||||||
|
|
||||||
# This will raise an exception for the invalid private key format
|
# This will raise an exception for the invalid private key format
|
||||||
assert_raises_rpc_error(-5, "Invalid private key encoding", self.nodes[0].importprivkey, "invalid")
|
assert_raises_rpc_error(-5, "Invalid private key encoding", self.nodes[0].importprivkey, "invalid")
|
||||||
|
|
||||||
|
@ -460,7 +463,8 @@ class WalletTest(BitcoinTestFramework):
|
||||||
# Try with walletrejectlongchains
|
# Try with walletrejectlongchains
|
||||||
# Double chain limit but require combining inputs, so we pass SelectCoinsMinConf
|
# Double chain limit but require combining inputs, so we pass SelectCoinsMinConf
|
||||||
self.stop_node(0)
|
self.stop_node(0)
|
||||||
self.start_node(0, extra_args=["-walletrejectlongchains", "-limitancestorcount=" + str(2 * chainlimit)])
|
extra_args = ["-walletrejectlongchains", "-limitancestorcount=" + str(2 * chainlimit)]
|
||||||
|
self.start_node(0, extra_args=extra_args)
|
||||||
|
|
||||||
# wait for loadmempool
|
# wait for loadmempool
|
||||||
timeout = 10
|
timeout = 10
|
||||||
|
|
|
@ -27,17 +27,21 @@ class WalletHDTest(BitcoinTestFramework):
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
# Make sure we use hd, keep masterkeyid
|
# Make sure we use hd, keep masterkeyid
|
||||||
masterkeyid = self.nodes[1].getwalletinfo()['hdseedid']
|
hd_fingerprint = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())['hdmasterfingerprint']
|
||||||
assert_equal(len(masterkeyid), 40)
|
assert_equal(len(hd_fingerprint), 8)
|
||||||
|
|
||||||
# create an internal key
|
# create an internal key
|
||||||
change_addr = self.nodes[1].getrawchangeaddress()
|
change_addr = self.nodes[1].getrawchangeaddress()
|
||||||
change_addrV= self.nodes[1].getaddressinfo(change_addr)
|
change_addrV= self.nodes[1].getaddressinfo(change_addr)
|
||||||
|
if self.options.descriptors:
|
||||||
|
assert_equal(change_addrV["hdkeypath"], "m/84'/1'/0'/1/0")
|
||||||
|
else:
|
||||||
assert_equal(change_addrV["hdkeypath"], "m/0'/1'/0'") #first internal child key
|
assert_equal(change_addrV["hdkeypath"], "m/0'/1'/0'") #first internal child key
|
||||||
|
|
||||||
# Import a non-HD private key in the HD wallet
|
# Import a non-HD private key in the HD wallet
|
||||||
non_hd_add = self.nodes[0].getnewaddress()
|
non_hd_add = 'bcrt1qmevj8zfx0wdvp05cqwkmr6mxkfx60yezwjksmt'
|
||||||
self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add))
|
non_hd_key = 'cS9umN9w6cDMuRVYdbkfE4c7YUFLJRoXMfhQ569uY4odiQbVN8Rt'
|
||||||
|
self.nodes[1].importprivkey(non_hd_key)
|
||||||
|
|
||||||
# This should be enough to keep the master key and the non-HD key
|
# This should be enough to keep the master key and the non-HD key
|
||||||
self.nodes[1].backupwallet(os.path.join(self.nodes[1].datadir, "hd.bak"))
|
self.nodes[1].backupwallet(os.path.join(self.nodes[1].datadir, "hd.bak"))
|
||||||
|
@ -48,11 +52,14 @@ class WalletHDTest(BitcoinTestFramework):
|
||||||
self.nodes[0].generate(101)
|
self.nodes[0].generate(101)
|
||||||
hd_add = None
|
hd_add = None
|
||||||
NUM_HD_ADDS = 10
|
NUM_HD_ADDS = 10
|
||||||
for i in range(NUM_HD_ADDS):
|
for i in range(1, NUM_HD_ADDS + 1):
|
||||||
hd_add = self.nodes[1].getnewaddress()
|
hd_add = self.nodes[1].getnewaddress()
|
||||||
hd_info = self.nodes[1].getaddressinfo(hd_add)
|
hd_info = self.nodes[1].getaddressinfo(hd_add)
|
||||||
|
if self.options.descriptors:
|
||||||
|
assert_equal(hd_info["hdkeypath"], "m/84'/1'/0'/0/" + str(i))
|
||||||
|
else:
|
||||||
assert_equal(hd_info["hdkeypath"], "m/0'/0'/"+str(i)+"'")
|
assert_equal(hd_info["hdkeypath"], "m/0'/0'/"+str(i)+"'")
|
||||||
assert_equal(hd_info["hdseedid"], masterkeyid)
|
assert_equal(hd_info["hdmasterfingerprint"], hd_fingerprint)
|
||||||
self.nodes[0].sendtoaddress(hd_add, 1)
|
self.nodes[0].sendtoaddress(hd_add, 1)
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
self.nodes[0].sendtoaddress(non_hd_add, 1)
|
self.nodes[0].sendtoaddress(non_hd_add, 1)
|
||||||
|
@ -61,6 +68,9 @@ class WalletHDTest(BitcoinTestFramework):
|
||||||
# create an internal key (again)
|
# create an internal key (again)
|
||||||
change_addr = self.nodes[1].getrawchangeaddress()
|
change_addr = self.nodes[1].getrawchangeaddress()
|
||||||
change_addrV= self.nodes[1].getaddressinfo(change_addr)
|
change_addrV= self.nodes[1].getaddressinfo(change_addr)
|
||||||
|
if self.options.descriptors:
|
||||||
|
assert_equal(change_addrV["hdkeypath"], "m/84'/1'/0'/1/1")
|
||||||
|
else:
|
||||||
assert_equal(change_addrV["hdkeypath"], "m/0'/1'/1'") #second internal child key
|
assert_equal(change_addrV["hdkeypath"], "m/0'/1'/1'") #second internal child key
|
||||||
|
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
@ -72,16 +82,19 @@ class WalletHDTest(BitcoinTestFramework):
|
||||||
# otherwise node1 would auto-recover all funds in flag the keypool keys as used
|
# otherwise node1 would auto-recover all funds in flag the keypool keys as used
|
||||||
shutil.rmtree(os.path.join(self.nodes[1].datadir, self.chain, "blocks"))
|
shutil.rmtree(os.path.join(self.nodes[1].datadir, self.chain, "blocks"))
|
||||||
shutil.rmtree(os.path.join(self.nodes[1].datadir, self.chain, "chainstate"))
|
shutil.rmtree(os.path.join(self.nodes[1].datadir, self.chain, "chainstate"))
|
||||||
shutil.copyfile(os.path.join(self.nodes[1].datadir, "hd.bak"), os.path.join(self.nodes[1].datadir, self.chain, "wallets", "wallet.dat"))
|
shutil.copyfile(os.path.join(self.nodes[1].datadir, "hd.bak"), os.path.join(self.nodes[1].datadir, self.chain, 'wallets', "wallet.dat"))
|
||||||
self.start_node(1)
|
self.start_node(1)
|
||||||
|
|
||||||
# Assert that derivation is deterministic
|
# Assert that derivation is deterministic
|
||||||
hd_add_2 = None
|
hd_add_2 = None
|
||||||
for i in range(NUM_HD_ADDS):
|
for i in range(1, NUM_HD_ADDS + 1):
|
||||||
hd_add_2 = self.nodes[1].getnewaddress()
|
hd_add_2 = self.nodes[1].getnewaddress()
|
||||||
hd_info_2 = self.nodes[1].getaddressinfo(hd_add_2)
|
hd_info_2 = self.nodes[1].getaddressinfo(hd_add_2)
|
||||||
|
if self.options.descriptors:
|
||||||
|
assert_equal(hd_info_2["hdkeypath"], "m/84'/1'/0'/0/" + str(i))
|
||||||
|
else:
|
||||||
assert_equal(hd_info_2["hdkeypath"], "m/0'/0'/"+str(i)+"'")
|
assert_equal(hd_info_2["hdkeypath"], "m/0'/0'/"+str(i)+"'")
|
||||||
assert_equal(hd_info_2["hdseedid"], masterkeyid)
|
assert_equal(hd_info_2["hdmasterfingerprint"], hd_fingerprint)
|
||||||
assert_equal(hd_add, hd_add_2)
|
assert_equal(hd_add, hd_add_2)
|
||||||
connect_nodes(self.nodes[0], 1)
|
connect_nodes(self.nodes[0], 1)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
@ -117,8 +130,12 @@ class WalletHDTest(BitcoinTestFramework):
|
||||||
if out['value'] != 1:
|
if out['value'] != 1:
|
||||||
keypath = self.nodes[1].getaddressinfo(out['scriptPubKey']['addresses'][0])['hdkeypath']
|
keypath = self.nodes[1].getaddressinfo(out['scriptPubKey']['addresses'][0])['hdkeypath']
|
||||||
|
|
||||||
|
if self.options.descriptors:
|
||||||
|
assert_equal(keypath[0:14], "m/84'/1'/0'/1/")
|
||||||
|
else:
|
||||||
assert_equal(keypath[0:7], "m/0'/1'")
|
assert_equal(keypath[0:7], "m/0'/1'")
|
||||||
|
|
||||||
|
if not self.options.descriptors:
|
||||||
# Generate a new HD seed on node 1 and make sure it is set
|
# Generate a new HD seed on node 1 and make sure it is set
|
||||||
orig_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid']
|
orig_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid']
|
||||||
self.nodes[1].sethdseed()
|
self.nodes[1].sethdseed()
|
||||||
|
|
|
@ -22,15 +22,62 @@ class KeyPoolTest(BitcoinTestFramework):
|
||||||
addr_before_encrypting = nodes[0].getnewaddress()
|
addr_before_encrypting = nodes[0].getnewaddress()
|
||||||
addr_before_encrypting_data = nodes[0].getaddressinfo(addr_before_encrypting)
|
addr_before_encrypting_data = nodes[0].getaddressinfo(addr_before_encrypting)
|
||||||
wallet_info_old = nodes[0].getwalletinfo()
|
wallet_info_old = nodes[0].getwalletinfo()
|
||||||
|
if not self.options.descriptors:
|
||||||
assert addr_before_encrypting_data['hdseedid'] == wallet_info_old['hdseedid']
|
assert addr_before_encrypting_data['hdseedid'] == wallet_info_old['hdseedid']
|
||||||
|
|
||||||
# Encrypt wallet and wait to terminate
|
# Encrypt wallet and wait to terminate
|
||||||
nodes[0].encryptwallet('test')
|
nodes[0].encryptwallet('test')
|
||||||
|
if self.options.descriptors:
|
||||||
|
# Import hardened derivation only descriptors
|
||||||
|
nodes[0].walletpassphrase('test', 10)
|
||||||
|
nodes[0].importdescriptors([
|
||||||
|
{
|
||||||
|
"desc": "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/*h)#y4dfsj7n",
|
||||||
|
"timestamp": "now",
|
||||||
|
"range": [0,0],
|
||||||
|
"active": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"desc": "pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1h/*h)#a0nyvl0k",
|
||||||
|
"timestamp": "now",
|
||||||
|
"range": [0,0],
|
||||||
|
"active": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"desc": "sh(wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/2h/*h))#lmeu2axg",
|
||||||
|
"timestamp": "now",
|
||||||
|
"range": [0,0],
|
||||||
|
"active": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"desc": "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/3h/*h)#jkl636gm",
|
||||||
|
"timestamp": "now",
|
||||||
|
"range": [0,0],
|
||||||
|
"active": True,
|
||||||
|
"internal": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"desc": "pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/4h/*h)#l3crwaus",
|
||||||
|
"timestamp": "now",
|
||||||
|
"range": [0,0],
|
||||||
|
"active": True,
|
||||||
|
"internal": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"desc": "sh(wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/5h/*h))#qg8wa75f",
|
||||||
|
"timestamp": "now",
|
||||||
|
"range": [0,0],
|
||||||
|
"active": True,
|
||||||
|
"internal": True
|
||||||
|
}
|
||||||
|
])
|
||||||
|
nodes[0].walletlock()
|
||||||
# Keep creating keys
|
# Keep creating keys
|
||||||
addr = nodes[0].getnewaddress()
|
addr = nodes[0].getnewaddress()
|
||||||
addr_data = nodes[0].getaddressinfo(addr)
|
addr_data = nodes[0].getaddressinfo(addr)
|
||||||
wallet_info = nodes[0].getwalletinfo()
|
wallet_info = nodes[0].getwalletinfo()
|
||||||
assert addr_before_encrypting_data['hdseedid'] != wallet_info['hdseedid']
|
assert addr_before_encrypting_data['hdmasterfingerprint'] != addr_data['hdmasterfingerprint']
|
||||||
|
if not self.options.descriptors:
|
||||||
assert addr_data['hdseedid'] == wallet_info['hdseedid']
|
assert addr_data['hdseedid'] == wallet_info['hdseedid']
|
||||||
assert_raises_rpc_error(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress)
|
assert_raises_rpc_error(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress)
|
||||||
|
|
||||||
|
@ -39,6 +86,10 @@ class KeyPoolTest(BitcoinTestFramework):
|
||||||
nodes[0].keypoolrefill(6)
|
nodes[0].keypoolrefill(6)
|
||||||
nodes[0].walletlock()
|
nodes[0].walletlock()
|
||||||
wi = nodes[0].getwalletinfo()
|
wi = nodes[0].getwalletinfo()
|
||||||
|
if self.options.descriptors:
|
||||||
|
assert_equal(wi['keypoolsize_hd_internal'], 18)
|
||||||
|
assert_equal(wi['keypoolsize'], 18)
|
||||||
|
else:
|
||||||
assert_equal(wi['keypoolsize_hd_internal'], 6)
|
assert_equal(wi['keypoolsize_hd_internal'], 6)
|
||||||
assert_equal(wi['keypoolsize'], 6)
|
assert_equal(wi['keypoolsize'], 6)
|
||||||
|
|
||||||
|
@ -80,11 +131,15 @@ class KeyPoolTest(BitcoinTestFramework):
|
||||||
nodes[0].walletpassphrase('test', 100)
|
nodes[0].walletpassphrase('test', 100)
|
||||||
nodes[0].keypoolrefill(100)
|
nodes[0].keypoolrefill(100)
|
||||||
wi = nodes[0].getwalletinfo()
|
wi = nodes[0].getwalletinfo()
|
||||||
|
if self.options.descriptors:
|
||||||
|
assert_equal(wi['keypoolsize_hd_internal'], 300)
|
||||||
|
assert_equal(wi['keypoolsize'], 300)
|
||||||
|
else:
|
||||||
assert_equal(wi['keypoolsize_hd_internal'], 100)
|
assert_equal(wi['keypoolsize_hd_internal'], 100)
|
||||||
assert_equal(wi['keypoolsize'], 100)
|
assert_equal(wi['keypoolsize'], 100)
|
||||||
|
|
||||||
# create a blank wallet
|
# create a blank wallet
|
||||||
nodes[0].createwallet(wallet_name='w2', blank=True)
|
nodes[0].createwallet(wallet_name='w2', blank=True, disable_private_keys=True)
|
||||||
w2 = nodes[0].get_wallet_rpc('w2')
|
w2 = nodes[0].get_wallet_rpc('w2')
|
||||||
|
|
||||||
# refer to initial wallet as w1
|
# refer to initial wallet as w1
|
||||||
|
@ -92,8 +147,11 @@ class KeyPoolTest(BitcoinTestFramework):
|
||||||
|
|
||||||
# import private key and fund it
|
# import private key and fund it
|
||||||
address = addr.pop()
|
address = addr.pop()
|
||||||
privkey = w1.dumpprivkey(address)
|
desc = w1.getaddressinfo(address)['desc']
|
||||||
res = w2.importmulti([{'scriptPubKey': {'address': address}, 'keys': [privkey], 'timestamp': 'now'}])
|
if self.options.descriptors:
|
||||||
|
res = w2.importdescriptors([{'desc': desc, 'timestamp': 'now'}])
|
||||||
|
else:
|
||||||
|
res = w2.importmulti([{'desc': desc, 'timestamp': 'now'}])
|
||||||
assert_equal(res[0]['success'], True)
|
assert_equal(res[0]['success'], True)
|
||||||
w1.walletpassphrase('test', 100)
|
w1.walletpassphrase('test', 100)
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,15 @@ class KeypoolRestoreTest(BitcoinTestFramework):
|
||||||
assert_equal(self.nodes[idx].getbalance(), 15)
|
assert_equal(self.nodes[idx].getbalance(), 15)
|
||||||
assert_equal(self.nodes[idx].listtransactions()[0]['category'], "receive")
|
assert_equal(self.nodes[idx].listtransactions()[0]['category'], "receive")
|
||||||
# Check that we have marked all keys up to the used keypool key as used
|
# Check that we have marked all keys up to the used keypool key as used
|
||||||
assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress())['hdkeypath'], "m/0'/0'/110'")
|
if self.options.descriptors:
|
||||||
|
if output_type == 'legacy':
|
||||||
|
assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress(address_type=output_type))['hdkeypath'], "m/44'/1'/0'/0/110")
|
||||||
|
elif output_type == 'p2sh-segwit':
|
||||||
|
assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress(address_type=output_type))['hdkeypath'], "m/49'/1'/0'/0/110")
|
||||||
|
elif output_type == 'bech32':
|
||||||
|
assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress(address_type=output_type))['hdkeypath'], "m/84'/1'/0'/0/110")
|
||||||
|
else:
|
||||||
|
assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress(address_type=output_type))['hdkeypath'], "m/0'/0'/110'")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -115,6 +115,7 @@ class WalletLabelsTest(BitcoinTestFramework):
|
||||||
assert_raises_rpc_error(-11, "No addresses with label", node.getaddressesbylabel, "")
|
assert_raises_rpc_error(-11, "No addresses with label", node.getaddressesbylabel, "")
|
||||||
|
|
||||||
# Check that addmultisigaddress can assign labels.
|
# Check that addmultisigaddress can assign labels.
|
||||||
|
if not self.options.descriptors:
|
||||||
for label in labels:
|
for label in labels:
|
||||||
addresses = []
|
addresses = []
|
||||||
for x in range(10):
|
for x in range(10):
|
||||||
|
|
Loading…
Add table
Reference in a new issue