Changeset View
Changeset View
Standalone View
Standalone View
test/functional/wallet_importdescriptors.py
Show All 32 Lines | def set_test_params(self): | ||||
# whitelist peers to speed up tx relay / mempool sync | # whitelist peers to speed up tx relay / mempool sync | ||||
for args in self.extra_args: | for args in self.extra_args: | ||||
args.append("-whitelist=noban@127.0.0.1") | args.append("-whitelist=noban@127.0.0.1") | ||||
self.setup_clean_chain = True | self.setup_clean_chain = True | ||||
def skip_test_if_missing_module(self): | def skip_test_if_missing_module(self): | ||||
self.skip_if_no_wallet() | self.skip_if_no_wallet() | ||||
def test_importdesc(self, req, success, error_code=None, | def test_importdesc( | ||||
error_message=None, warnings=None, wallet=None): | self, | ||||
req, | |||||
success, | |||||
error_code=None, | |||||
error_message=None, | |||||
warnings=None, | |||||
wallet=None, | |||||
): | |||||
"""Run importdescriptors and assert success""" | """Run importdescriptors and assert success""" | ||||
if warnings is None: | if warnings is None: | ||||
warnings = [] | warnings = [] | ||||
wrpc = self.nodes[1].get_wallet_rpc('w1') | wrpc = self.nodes[1].get_wallet_rpc("w1") | ||||
if wallet is not None: | if wallet is not None: | ||||
wrpc = wallet | wrpc = wallet | ||||
result = wrpc.importdescriptors([req]) | result = wrpc.importdescriptors([req]) | ||||
observed_warnings = [] | observed_warnings = [] | ||||
if 'warnings' in result[0]: | if "warnings" in result[0]: | ||||
observed_warnings = result[0]['warnings'] | observed_warnings = result[0]["warnings"] | ||||
assert_equal( | assert_equal("\n".join(sorted(warnings)), "\n".join(sorted(observed_warnings))) | ||||
"\n".join( | assert_equal(result[0]["success"], success) | ||||
sorted(warnings)), "\n".join( | |||||
sorted(observed_warnings))) | |||||
assert_equal(result[0]['success'], success) | |||||
if error_code is not None: | if error_code is not None: | ||||
assert_equal(result[0]['error']['code'], error_code) | assert_equal(result[0]["error"]["code"], error_code) | ||||
assert_equal(result[0]['error']['message'], error_message) | assert_equal(result[0]["error"]["message"], error_message) | ||||
def run_test(self): | def run_test(self): | ||||
self.log.info('Setting up wallets') | self.log.info("Setting up wallets") | ||||
self.nodes[0].createwallet( | self.nodes[0].createwallet(wallet_name="w0", disable_private_keys=False) | ||||
wallet_name='w0', | w0 = self.nodes[0].get_wallet_rpc("w0") | ||||
disable_private_keys=False) | |||||
w0 = self.nodes[0].get_wallet_rpc('w0') | |||||
self.nodes[1].createwallet( | self.nodes[1].createwallet( | ||||
wallet_name='w1', | wallet_name="w1", disable_private_keys=True, blank=True, descriptors=True | ||||
disable_private_keys=True, | ) | ||||
blank=True, | w1 = self.nodes[1].get_wallet_rpc("w1") | ||||
descriptors=True) | assert_equal(w1.getwalletinfo()["keypoolsize"], 0) | ||||
w1 = self.nodes[1].get_wallet_rpc('w1') | |||||
assert_equal(w1.getwalletinfo()['keypoolsize'], 0) | |||||
self.nodes[1].createwallet( | self.nodes[1].createwallet( | ||||
wallet_name="wpriv", | wallet_name="wpriv", | ||||
disable_private_keys=False, | disable_private_keys=False, | ||||
blank=True, | blank=True, | ||||
descriptors=True) | descriptors=True, | ||||
) | |||||
wpriv = self.nodes[1].get_wallet_rpc("wpriv") | wpriv = self.nodes[1].get_wallet_rpc("wpriv") | ||||
assert_equal(wpriv.getwalletinfo()['keypoolsize'], 0) | assert_equal(wpriv.getwalletinfo()["keypoolsize"], 0) | ||||
self.log.info('Mining coins') | self.log.info("Mining coins") | ||||
self.generatetoaddress(self.nodes[0], 101, w0.getnewaddress()) | self.generatetoaddress(self.nodes[0], 101, w0.getnewaddress()) | ||||
# RPC importdescriptors ----------------------------------------------- | # RPC importdescriptors ----------------------------------------------- | ||||
# # Test import fails if no descriptor present | # # Test import fails if no descriptor present | ||||
key = get_generate_key() | key = get_generate_key() | ||||
self.log.info("Import should fail if a descriptor is not provided") | self.log.info("Import should fail if a descriptor is not provided") | ||||
self.test_importdesc({"timestamp": "now"}, | self.test_importdesc( | ||||
{"timestamp": "now"}, | |||||
success=False, | success=False, | ||||
error_code=-8, | error_code=-8, | ||||
error_message='Descriptor not found.') | error_message="Descriptor not found.", | ||||
) | |||||
# # Test importing of a P2PKH descriptor | # # Test importing of a P2PKH descriptor | ||||
key = get_generate_key() | key = get_generate_key() | ||||
self.log.info("Should import a p2pkh descriptor") | self.log.info("Should import a p2pkh descriptor") | ||||
self.test_importdesc({"desc": descsum_create(f"pkh({key.pubkey})"), | self.test_importdesc( | ||||
{ | |||||
"desc": descsum_create(f"pkh({key.pubkey})"), | |||||
"timestamp": "now", | "timestamp": "now", | ||||
"label": "Descriptor import test"}, | "label": "Descriptor import test", | ||||
success=True) | }, | ||||
test_address(w1, | success=True, | ||||
) | |||||
test_address( | |||||
w1, | |||||
key.p2pkh_addr, | key.p2pkh_addr, | ||||
solvable=True, | solvable=True, | ||||
ismine=True, | ismine=True, | ||||
labels=["Descriptor import test"]) | labels=["Descriptor import test"], | ||||
assert_equal(w1.getwalletinfo()['keypoolsize'], 0) | ) | ||||
assert_equal(w1.getwalletinfo()["keypoolsize"], 0) | |||||
self.log.info("Internal addresses cannot have labels") | self.log.info("Internal addresses cannot have labels") | ||||
self.test_importdesc({"desc": descsum_create(f"pkh({key.pubkey})"), | self.test_importdesc( | ||||
{ | |||||
"desc": descsum_create(f"pkh({key.pubkey})"), | |||||
"timestamp": "now", | "timestamp": "now", | ||||
"internal": True, | "internal": True, | ||||
"label": "Descriptor import test"}, | "label": "Descriptor import test", | ||||
}, | |||||
success=False, | success=False, | ||||
error_code=-8, | error_code=-8, | ||||
error_message="Internal addresses should not have a label") | error_message="Internal addresses should not have a label", | ||||
) | |||||
self.log.info("Internal addresses should be detected as such") | self.log.info("Internal addresses should be detected as such") | ||||
key = get_generate_key() | key = get_generate_key() | ||||
addr = key_to_p2pkh(key.pubkey) | addr = key_to_p2pkh(key.pubkey) | ||||
self.test_importdesc({"desc": descsum_create(f"pkh({key.pubkey})"), | self.test_importdesc( | ||||
{ | |||||
"desc": descsum_create(f"pkh({key.pubkey})"), | |||||
"timestamp": "now", | "timestamp": "now", | ||||
"internal": True}, | "internal": True, | ||||
success=True) | }, | ||||
success=True, | |||||
) | |||||
info = w1.getaddressinfo(addr) | info = w1.getaddressinfo(addr) | ||||
assert_equal(info["ismine"], True) | assert_equal(info["ismine"], True) | ||||
assert_equal(info["ischange"], True) | assert_equal(info["ischange"], True) | ||||
assert_equal(w1.getwalletinfo()['keypoolsize'], 0) | assert_equal(w1.getwalletinfo()["keypoolsize"], 0) | ||||
test_address(w1, | test_address(w1, key.p2pkh_addr, ismine=True, solvable=True) | ||||
key.p2pkh_addr, | |||||
ismine=True, | |||||
solvable=True) | |||||
# Check persistence of data and that loading works correctly | # Check persistence of data and that loading works correctly | ||||
w1.unloadwallet() | w1.unloadwallet() | ||||
self.nodes[1].loadwallet('w1') | self.nodes[1].loadwallet("w1") | ||||
test_address(w1, | test_address(w1, key.p2pkh_addr, ismine=True, solvable=True) | ||||
key.p2pkh_addr, | |||||
ismine=True, | |||||
solvable=True) | |||||
# # Test importing of a multisig descriptor | # # Test importing of a multisig descriptor | ||||
key1 = get_generate_key() | key1 = get_generate_key() | ||||
key2 = get_generate_key() | key2 = get_generate_key() | ||||
self.log.info("Should import a 1-of-2 bare multisig from descriptor") | self.log.info("Should import a 1-of-2 bare multisig from descriptor") | ||||
self.test_importdesc({"desc": descsum_create(f"multi(1,{key1.pubkey},{key2.pubkey})"), | self.test_importdesc( | ||||
"timestamp": "now"}, | { | ||||
success=True) | "desc": descsum_create(f"multi(1,{key1.pubkey},{key2.pubkey})"), | ||||
"timestamp": "now", | |||||
}, | |||||
success=True, | |||||
) | |||||
self.log.info( | self.log.info( | ||||
"Should not treat individual keys from the imported bare multisig as watchonly") | "Should not treat individual keys from the imported bare multisig as" | ||||
test_address(w1, | " watchonly" | ||||
key1.p2pkh_addr, | ) | ||||
ismine=False) | test_address(w1, key1.p2pkh_addr, ismine=False) | ||||
# # Test ranged descriptors | # # Test ranged descriptors | ||||
xpriv = "tprv8ZgxMBicQKsPeuVhWwi6wuMQGfPKi9Li5GtX35jVNknACgqe3CY4g5xgkfDDJcmtF7o1QnxWDRYw4H5P26PXq7sbcUkEqeR4fg3Kxp2tigg" | xpriv = "tprv8ZgxMBicQKsPeuVhWwi6wuMQGfPKi9Li5GtX35jVNknACgqe3CY4g5xgkfDDJcmtF7o1QnxWDRYw4H5P26PXq7sbcUkEqeR4fg3Kxp2tigg" | ||||
xpub = "tpubD6NzVbkrYhZ4YNXVQbNhMK1WqguFsUXceaVJKbmno2aZ3B6QfbMeraaYvnBSGpV3vxLyTTK9DYT1yoEck4XUScMzXoQ2U2oSmE2JyMedq3H" | xpub = "tpubD6NzVbkrYhZ4YNXVQbNhMK1WqguFsUXceaVJKbmno2aZ3B6QfbMeraaYvnBSGpV3vxLyTTK9DYT1yoEck4XUScMzXoQ2U2oSmE2JyMedq3H" | ||||
addresses = [ | addresses = [ | ||||
"2N7yv4p8G8yEaPddJxY41kPihnWvs39qCMf", | "2N7yv4p8G8yEaPddJxY41kPihnWvs39qCMf", | ||||
"2MsHxyb2JS3pAySeNUsJ7mNnurtpeenDzLA"] # hdkeypath=m/0'/0'/0' and 1' | "2MsHxyb2JS3pAySeNUsJ7mNnurtpeenDzLA", | ||||
] # hdkeypath=m/0'/0'/0' and 1' | |||||
# wpkh subscripts corresponding to the above addresses | # wpkh subscripts corresponding to the above addresses | ||||
addresses += ["ecregtest:prvn9ycvgr5atuyh49sua3mapskh2mnnzg7t9yp6dt", | addresses += [ | ||||
"ecregtest:pp3n087yx0njv2e5wcvltahfxqst7l66rutz8ceeat"] | "ecregtest:prvn9ycvgr5atuyh49sua3mapskh2mnnzg7t9yp6dt", | ||||
"ecregtest:pp3n087yx0njv2e5wcvltahfxqst7l66rutz8ceeat", | |||||
] | |||||
desc = f"sh(pkh({xpub}/0/0/*))" | desc = f"sh(pkh({xpub}/0/0/*))" | ||||
self.log.info("Ranged descriptors cannot have labels") | self.log.info("Ranged descriptors cannot have labels") | ||||
self.test_importdesc({"desc": descsum_create(desc), | self.test_importdesc( | ||||
{ | |||||
"desc": descsum_create(desc), | |||||
"timestamp": "now", | "timestamp": "now", | ||||
"range": [0, 100], | "range": [0, 100], | ||||
"label": "test"}, | "label": "test", | ||||
}, | |||||
success=False, | success=False, | ||||
error_code=-8, | error_code=-8, | ||||
error_message='Ranged descriptors should not have a label') | error_message="Ranged descriptors should not have a label", | ||||
) | |||||
self.log.info("Private keys required for private keys enabled wallet") | self.log.info("Private keys required for private keys enabled wallet") | ||||
self.test_importdesc({"desc": descsum_create(desc), | self.test_importdesc( | ||||
"timestamp": "now", | {"desc": descsum_create(desc), "timestamp": "now", "range": [0, 100]}, | ||||
"range": [0, 100]}, | |||||
success=False, | success=False, | ||||
error_code=-4, | error_code=-4, | ||||
error_message='Cannot import descriptor without private keys to a wallet with private keys enabled', | error_message=( | ||||
wallet=wpriv) | "Cannot import descriptor without private keys to a wallet with private" | ||||
" keys enabled" | |||||
), | |||||
wallet=wpriv, | |||||
) | |||||
self.log.info( | self.log.info("Ranged descriptor import should warn without a specified range") | ||||
"Ranged descriptor import should warn without a specified range") | self.test_importdesc( | ||||
self.test_importdesc({"desc": descsum_create(desc), | {"desc": descsum_create(desc), "timestamp": "now"}, | ||||
"timestamp": "now"}, | |||||
success=True, | success=True, | ||||
warnings=['Range not given, using default keypool range']) | warnings=["Range not given, using default keypool range"], | ||||
assert_equal(w1.getwalletinfo()['keypoolsize'], 0) | ) | ||||
assert_equal(w1.getwalletinfo()["keypoolsize"], 0) | |||||
# # Test importing of a ranged descriptor with xpriv | # # Test importing of a ranged descriptor with xpriv | ||||
self.log.info( | self.log.info( | ||||
"Should not import a ranged descriptor that includes xpriv into a watch-only wallet") | "Should not import a ranged descriptor that includes xpriv into a" | ||||
" watch-only wallet" | |||||
) | |||||
desc = f"sh(pkh({xpriv}/0'/0'/*'))" | desc = f"sh(pkh({xpriv}/0'/0'/*'))" | ||||
self.test_importdesc({"desc": descsum_create(desc), | self.test_importdesc( | ||||
"timestamp": "now", | {"desc": descsum_create(desc), "timestamp": "now", "range": 1}, | ||||
"range": 1}, | |||||
success=False, | success=False, | ||||
error_code=-4, | error_code=-4, | ||||
error_message='Cannot import private keys to a wallet with private keys disabled') | error_message=( | ||||
"Cannot import private keys to a wallet with private keys disabled" | |||||
), | |||||
) | |||||
self.log.info("Should not import a descriptor with hardened " | self.log.info( | ||||
"derivations when private keys are disabled") | "Should not import a descriptor with hardened " | ||||
self.test_importdesc({"desc": descsum_create(f"pkh({xpub}/1h/*)"), | "derivations when private keys are disabled" | ||||
) | |||||
self.test_importdesc( | |||||
{ | |||||
"desc": descsum_create(f"pkh({xpub}/1h/*)"), | |||||
"timestamp": "now", | "timestamp": "now", | ||||
"range": 1}, | "range": 1, | ||||
}, | |||||
success=False, | success=False, | ||||
error_code=-4, | error_code=-4, | ||||
error_message='Cannot expand descriptor. Probably because of hardened derivations without private keys provided') | error_message=( | ||||
"Cannot expand descriptor. Probably because of hardened derivations" | |||||
" without private keys provided" | |||||
), | |||||
) | |||||
for address in addresses: | for address in addresses: | ||||
test_address(w1, | test_address(w1, address, ismine=False, solvable=False) | ||||
address, | |||||
ismine=False, | |||||
solvable=False) | |||||
self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now", "range": -1}, | self.test_importdesc( | ||||
success=False, error_code=-8, error_message='End of range is too high') | {"desc": descsum_create(desc), "timestamp": "now", "range": -1}, | ||||
success=False, | |||||
error_code=-8, | |||||
error_message="End of range is too high", | |||||
) | |||||
self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now", "range": [-1, 10]}, | self.test_importdesc( | ||||
success=False, error_code=-8, error_message='Range should be greater or equal than 0') | {"desc": descsum_create(desc), "timestamp": "now", "range": [-1, 10]}, | ||||
success=False, | |||||
error_code=-8, | |||||
error_message="Range should be greater or equal than 0", | |||||
) | |||||
self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now", "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)]}, | self.test_importdesc( | ||||
success=False, error_code=-8, error_message='End of range is too high') | { | ||||
"desc": descsum_create(desc), | |||||
"timestamp": "now", | |||||
"range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)], | |||||
}, | |||||
success=False, | |||||
error_code=-8, | |||||
error_message="End of range is too high", | |||||
) | |||||
self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now", "range": [2, 1]}, | self.test_importdesc( | ||||
success=False, error_code=-8, error_message='Range specified as [begin,end] must not have begin after end') | {"desc": descsum_create(desc), "timestamp": "now", "range": [2, 1]}, | ||||
success=False, | |||||
error_code=-8, | |||||
error_message=( | |||||
"Range specified as [begin,end] must not have begin after end" | |||||
), | |||||
) | |||||
self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now", "range": [0, 1000001]}, | self.test_importdesc( | ||||
success=False, error_code=-8, error_message='Range is too large') | {"desc": descsum_create(desc), "timestamp": "now", "range": [0, 1000001]}, | ||||
success=False, | |||||
error_code=-8, | |||||
error_message="Range is too large", | |||||
) | |||||
# Make sure ranged imports import keys in order | # Make sure ranged imports import keys in order | ||||
w1 = self.nodes[1].get_wallet_rpc('w1') | w1 = self.nodes[1].get_wallet_rpc("w1") | ||||
self.log.info('Key ranges should be imported in order') | self.log.info("Key ranges should be imported in order") | ||||
xpub = "tpubDAXcJ7s7ZwicqjprRaEWdPoHKrCS215qxGYxpusRLLmJuT69ZSicuGdSfyvyKpvUNYBW1s2U3NSrT6vrCYB9e6nZUEvrqnwXPF8ArTCRXMY" | xpub = "tpubDAXcJ7s7ZwicqjprRaEWdPoHKrCS215qxGYxpusRLLmJuT69ZSicuGdSfyvyKpvUNYBW1s2U3NSrT6vrCYB9e6nZUEvrqnwXPF8ArTCRXMY" | ||||
addresses = [ | addresses = [ | ||||
'ecregtest:qp0v86h53rc92hjrlpwzpjtdlgzsxu25svv6g40fpl', # m/0'/0'/0 | "ecregtest:qp0v86h53rc92hjrlpwzpjtdlgzsxu25svv6g40fpl", # m/0'/0'/0 | ||||
'ecregtest:qqasy0zlkdleqt4pkn8fs4ehm5gnnz6qpgdcpt90fq', # m/0'/0'/1 | "ecregtest:qqasy0zlkdleqt4pkn8fs4ehm5gnnz6qpgdcpt90fq", # m/0'/0'/1 | ||||
'ecregtest:qp0sp4wlhctvprqvdt2dgvqcfdjssu04xgey0l3syw', # m/0'/0'/2 | "ecregtest:qp0sp4wlhctvprqvdt2dgvqcfdjssu04xgey0l3syw", # m/0'/0'/2 | ||||
'ecregtest:qrhn24tegn04cptfv4ldhtkduxq55zcwrycjfdj9vr', # m/0'/0'/3 | "ecregtest:qrhn24tegn04cptfv4ldhtkduxq55zcwrycjfdj9vr", # m/0'/0'/3 | ||||
'ecregtest:qzpqhett2uwltq803vrxv7zkqhft5vsnmcjeh50v0p', # m/0'/0'/4 | "ecregtest:qzpqhett2uwltq803vrxv7zkqhft5vsnmcjeh50v0p", # m/0'/0'/4 | ||||
] | ] | ||||
self.test_importdesc({'desc': descsum_create(f"sh(pkh([abcdef12/0h/0h]{xpub}/*))"), | self.test_importdesc( | ||||
'active': True, | { | ||||
'range': [0, 2], | "desc": descsum_create(f"sh(pkh([abcdef12/0h/0h]{xpub}/*))"), | ||||
'timestamp': 'now' | "active": True, | ||||
}, | "range": [0, 2], | ||||
success=True) | "timestamp": "now", | ||||
self.test_importdesc({'desc': descsum_create(f"pkh([12345678/0h/0h]{xpub}/*)"), | |||||
'active': True, | |||||
'range': [0, 2], | |||||
'timestamp': 'now' | |||||
}, | }, | ||||
success=True) | success=True, | ||||
) | |||||
self.test_importdesc( | |||||
{ | |||||
"desc": descsum_create(f"pkh([12345678/0h/0h]{xpub}/*)"), | |||||
"active": True, | |||||
"range": [0, 2], | |||||
"timestamp": "now", | |||||
}, | |||||
success=True, | |||||
) | |||||
assert_equal(w1.getwalletinfo()['keypoolsize'], 5) | assert_equal(w1.getwalletinfo()["keypoolsize"], 5) | ||||
for i, expected_addr in enumerate(addresses): | for i, expected_addr in enumerate(addresses): | ||||
pkh_addr = w1.getnewaddress('') | pkh_addr = w1.getnewaddress("") | ||||
assert_raises_rpc_error(-4, | assert_raises_rpc_error( | ||||
'This wallet has no available keys', | -4, "This wallet has no available keys", w1.getrawchangeaddress | ||||
w1.getrawchangeaddress) | ) | ||||
assert_equal(pkh_addr, expected_addr) | assert_equal(pkh_addr, expected_addr) | ||||
pkh_addr_info = w1.getaddressinfo(pkh_addr) | pkh_addr_info = w1.getaddressinfo(pkh_addr) | ||||
assert_equal(pkh_addr_info['desc'][:22], | assert_equal(pkh_addr_info["desc"][:22], f"pkh([12345678/0'/0'/{i}]") | ||||
f'pkh([12345678/0\'/0\'/{i}]') | |||||
# After retrieving a key, we don't refill the keypool again, so | # After retrieving a key, we don't refill the keypool again, so | ||||
# it's one less for each address type | # it's one less for each address type | ||||
assert_equal(w1.getwalletinfo()['keypoolsize'], 4) | assert_equal(w1.getwalletinfo()["keypoolsize"], 4) | ||||
w1.keypoolrefill() | w1.keypoolrefill() | ||||
assert_equal(w1.getwalletinfo()['keypoolsize'], 5) | assert_equal(w1.getwalletinfo()["keypoolsize"], 5) | ||||
# Check active=False default | # Check active=False default | ||||
self.log.info('Check imported descriptors are not active by default') | self.log.info("Check imported descriptors are not active by default") | ||||
self.test_importdesc({'desc': descsum_create(f"pkh([12345678/0h/0h]{xpub}/*)"), | self.test_importdesc( | ||||
'range': [0, 2], | { | ||||
'timestamp': 'now', | "desc": descsum_create(f"pkh([12345678/0h/0h]{xpub}/*)"), | ||||
'internal': True | "range": [0, 2], | ||||
}, | "timestamp": "now", | ||||
success=True) | "internal": True, | ||||
assert_raises_rpc_error(-4, | }, | ||||
'This wallet has no available keys', | success=True, | ||||
w1.getrawchangeaddress) | ) | ||||
assert_raises_rpc_error( | |||||
-4, "This wallet has no available keys", w1.getrawchangeaddress | |||||
) | |||||
# # Test importing a descriptor containing a WIF private key | # # Test importing a descriptor containing a WIF private key | ||||
wif_priv = "cTe1f5rdT8A8DFgVWTjyPwACsDPJM9ff4QngFxUixCSvvbg1x6sh" | wif_priv = "cTe1f5rdT8A8DFgVWTjyPwACsDPJM9ff4QngFxUixCSvvbg1x6sh" | ||||
address = "ecregtest:ppn85zpvym8cdccmgw8km6e48jfhnpa435h3hkyfd6" | address = "ecregtest:ppn85zpvym8cdccmgw8km6e48jfhnpa435h3hkyfd6" | ||||
desc = f"sh(pkh({wif_priv}))" | desc = f"sh(pkh({wif_priv}))" | ||||
self.log.info( | self.log.info("Should import a descriptor with a WIF private key as spendable") | ||||
"Should import a descriptor with a WIF private key as spendable") | self.test_importdesc( | ||||
self.test_importdesc({"desc": descsum_create(desc), | {"desc": descsum_create(desc), "timestamp": "now"}, | ||||
"timestamp": "now"}, | success=True, | ||||
success=True, | wallet=wpriv, | ||||
wallet=wpriv) | ) | ||||
test_address(wpriv, | test_address(wpriv, address, solvable=True, ismine=True) | ||||
address, | |||||
solvable=True, | |||||
ismine=True) | |||||
txid = w0.sendtoaddress(address, 49999996.00) | txid = w0.sendtoaddress(address, 49999996.00) | ||||
self.generatetoaddress(self.nodes[0], 6, w0.getnewaddress()) | self.generatetoaddress(self.nodes[0], 6, w0.getnewaddress()) | ||||
tx = wpriv.createrawtransaction([{"txid": txid, "vout": 0}], { | tx = wpriv.createrawtransaction( | ||||
w0.getnewaddress(): 49999000}) | [{"txid": txid, "vout": 0}], {w0.getnewaddress(): 49999000} | ||||
) | |||||
signed_tx = wpriv.signrawtransactionwithwallet(tx) | signed_tx = wpriv.signrawtransactionwithwallet(tx) | ||||
w1.sendrawtransaction(signed_tx['hex']) | w1.sendrawtransaction(signed_tx["hex"]) | ||||
# Make sure that we can use import and use multisig as addresses | # Make sure that we can use import and use multisig as addresses | ||||
self.log.info( | self.log.info( | ||||
'Test that multisigs can be imported, signed for, and getnewaddress\'d') | "Test that multisigs can be imported, signed for, and getnewaddress'd" | ||||
) | |||||
self.nodes[1].createwallet( | self.nodes[1].createwallet( | ||||
wallet_name="wmulti_priv", | wallet_name="wmulti_priv", | ||||
disable_private_keys=False, | disable_private_keys=False, | ||||
blank=True, | blank=True, | ||||
descriptors=True) | descriptors=True, | ||||
) | |||||
wmulti_priv = self.nodes[1].get_wallet_rpc("wmulti_priv") | wmulti_priv = self.nodes[1].get_wallet_rpc("wmulti_priv") | ||||
assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 0) | assert_equal(wmulti_priv.getwalletinfo()["keypoolsize"], 0) | ||||
self.test_importdesc({"desc": "sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/0h/0h/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/0h/0h/*,tprv8ZgxMBicQKsPeonDt8Ka2mrQmHa61hQ5FQCsvWBTpSNzBFgM58cV2EuXNAHF14VawVpznnme3SuTbA62sGriwWyKifJmXntfNeK7zeqMCj1/84h/0h/0h/*))#f5nqn4ax", | self.test_importdesc( | ||||
{ | |||||
"desc": "sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/0h/0h/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/0h/0h/*,tprv8ZgxMBicQKsPeonDt8Ka2mrQmHa61hQ5FQCsvWBTpSNzBFgM58cV2EuXNAHF14VawVpznnme3SuTbA62sGriwWyKifJmXntfNeK7zeqMCj1/84h/0h/0h/*))#f5nqn4ax", | |||||
"active": True, | "active": True, | ||||
"range": 1000, | "range": 1000, | ||||
"next_index": 0, | "next_index": 0, | ||||
"timestamp": "now"}, | "timestamp": "now", | ||||
}, | |||||
success=True, | success=True, | ||||
wallet=wmulti_priv) | wallet=wmulti_priv, | ||||
self.test_importdesc({"desc": "sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/1h/0h/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/1h/0h/*,tprv8ZgxMBicQKsPeonDt8Ka2mrQmHa61hQ5FQCsvWBTpSNzBFgM58cV2EuXNAHF14VawVpznnme3SuTbA62sGriwWyKifJmXntfNeK7zeqMCj1/84h/1h/0h/*))#m4e4s5de", | ) | ||||
self.test_importdesc( | |||||
{ | |||||
"desc": "sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/1h/0h/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/1h/0h/*,tprv8ZgxMBicQKsPeonDt8Ka2mrQmHa61hQ5FQCsvWBTpSNzBFgM58cV2EuXNAHF14VawVpznnme3SuTbA62sGriwWyKifJmXntfNeK7zeqMCj1/84h/1h/0h/*))#m4e4s5de", | |||||
"active": True, | "active": True, | ||||
"internal": True, | "internal": True, | ||||
"range": 1000, | "range": 1000, | ||||
"next_index": 0, | "next_index": 0, | ||||
"timestamp": "now"}, | "timestamp": "now", | ||||
}, | |||||
success=True, | success=True, | ||||
wallet=wmulti_priv) | wallet=wmulti_priv, | ||||
) | |||||
# Range end (1000) is inclusive, so 1001 addresses generated | # Range end (1000) is inclusive, so 1001 addresses generated | ||||
assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 1001) | assert_equal(wmulti_priv.getwalletinfo()["keypoolsize"], 1001) | ||||
addr = wmulti_priv.getnewaddress('') | addr = wmulti_priv.getnewaddress("") | ||||
# Derived at m/84'/0'/0'/0 | # Derived at m/84'/0'/0'/0 | ||||
assert_equal( | assert_equal(addr, "ecregtest:pzkcf26dw7np58jcspnpxaupgz9csnc3wsf5wdh2a3") | ||||
addr, | |||||
'ecregtest:pzkcf26dw7np58jcspnpxaupgz9csnc3wsf5wdh2a3') | |||||
change_addr = wmulti_priv.getrawchangeaddress() | change_addr = wmulti_priv.getrawchangeaddress() | ||||
assert_equal( | assert_equal( | ||||
change_addr, | change_addr, "ecregtest:prnkfg7pxe3kpyv3l4v00ft6q3sfseag7vnva0k49n" | ||||
'ecregtest:prnkfg7pxe3kpyv3l4v00ft6q3sfseag7vnva0k49n') | ) | ||||
assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 1000) | assert_equal(wmulti_priv.getwalletinfo()["keypoolsize"], 1000) | ||||
txid = w0.sendtoaddress(addr, 10000000) | txid = w0.sendtoaddress(addr, 10000000) | ||||
self.generate(self.nodes[0], 6) | self.generate(self.nodes[0], 6) | ||||
self.nodes[1].createwallet( | self.nodes[1].createwallet( | ||||
wallet_name="wmulti_pub", | wallet_name="wmulti_pub", | ||||
disable_private_keys=True, | disable_private_keys=True, | ||||
blank=True, | blank=True, | ||||
descriptors=True) | descriptors=True, | ||||
) | |||||
wmulti_pub = self.nodes[1].get_wallet_rpc("wmulti_pub") | wmulti_pub = self.nodes[1].get_wallet_rpc("wmulti_pub") | ||||
assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 0) | assert_equal(wmulti_pub.getwalletinfo()["keypoolsize"], 0) | ||||
self.test_importdesc({"desc": "sh(multi(2,[7b2d0242/84h/0h/0h]tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*,[59b09cd6/84h/0h/0h]tpubDDBF2BTR6s8drwrfDei8WxtckGuSm1cyoKxYY1QaKSBFbHBYQArWhHPA6eJrzZej6nfHGLSURYSLHr7GuYch8aY5n61tGqgn8b4cXrMuoPH/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))#x75vpsak", | self.test_importdesc( | ||||
{ | |||||
"desc": "sh(multi(2,[7b2d0242/84h/0h/0h]tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*,[59b09cd6/84h/0h/0h]tpubDDBF2BTR6s8drwrfDei8WxtckGuSm1cyoKxYY1QaKSBFbHBYQArWhHPA6eJrzZej6nfHGLSURYSLHr7GuYch8aY5n61tGqgn8b4cXrMuoPH/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))#x75vpsak", | |||||
"active": True, | "active": True, | ||||
"range": 1000, | "range": 1000, | ||||
"next_index": 0, | "next_index": 0, | ||||
"timestamp": "now"}, | "timestamp": "now", | ||||
}, | |||||
success=True, | success=True, | ||||
wallet=wmulti_pub) | wallet=wmulti_pub, | ||||
self.test_importdesc({"desc": "sh(multi(2,[7b2d0242/84h/1h/0h]tpubDCXqdwWZcszwqYJSnZp8eARkxGJfHAk23KDxbztV4BbschfaTfYLTcSkSJ3TN64dRqwa1rnFUScsYormKkGqNbbPwkorQimVevXjxzUV9Gf/*,[59b09cd6/84h/1h/0h]tpubDCYfZY2ceyHzYzMMVPt9MNeiqtQ2T7Uyp9QSFwYXh8Vi9iJFYXcuphJaGXfF3jUQJi5Y3GMNXvM11gaL4txzZgNGK22BFAwMXynnzv4z2Jh/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))#v0t48ucu", | ) | ||||
self.test_importdesc( | |||||
{ | |||||
"desc": "sh(multi(2,[7b2d0242/84h/1h/0h]tpubDCXqdwWZcszwqYJSnZp8eARkxGJfHAk23KDxbztV4BbschfaTfYLTcSkSJ3TN64dRqwa1rnFUScsYormKkGqNbbPwkorQimVevXjxzUV9Gf/*,[59b09cd6/84h/1h/0h]tpubDCYfZY2ceyHzYzMMVPt9MNeiqtQ2T7Uyp9QSFwYXh8Vi9iJFYXcuphJaGXfF3jUQJi5Y3GMNXvM11gaL4txzZgNGK22BFAwMXynnzv4z2Jh/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))#v0t48ucu", | |||||
"active": True, | "active": True, | ||||
"internal": True, | "internal": True, | ||||
"range": 1000, | "range": 1000, | ||||
"next_index": 0, | "next_index": 0, | ||||
"timestamp": "now"}, | "timestamp": "now", | ||||
}, | |||||
success=True, | success=True, | ||||
wallet=wmulti_pub) | wallet=wmulti_pub, | ||||
) | |||||
# The first one was already consumed by previous import and is detected | # The first one was already consumed by previous import and is detected | ||||
# as used | # as used | ||||
assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 1000) | assert_equal(wmulti_pub.getwalletinfo()["keypoolsize"], 1000) | ||||
addr = wmulti_pub.getnewaddress('') | addr = wmulti_pub.getnewaddress("") | ||||
# Derived at m/84'/0'/0'/1 | # Derived at m/84'/0'/0'/1 | ||||
assert_equal( | assert_equal(addr, "ecregtest:pr5xql8r03jp5dvrep22dns59vf7hhykr5nmaucy2h") | ||||
addr, | |||||
'ecregtest:pr5xql8r03jp5dvrep22dns59vf7hhykr5nmaucy2h') | |||||
change_addr = wmulti_pub.getrawchangeaddress() | change_addr = wmulti_pub.getrawchangeaddress() | ||||
assert_equal( | assert_equal( | ||||
change_addr, | change_addr, "ecregtest:prnkfg7pxe3kpyv3l4v00ft6q3sfseag7vnva0k49n" | ||||
'ecregtest:prnkfg7pxe3kpyv3l4v00ft6q3sfseag7vnva0k49n') | ) | ||||
assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 999) | assert_equal(wmulti_pub.getwalletinfo()["keypoolsize"], 999) | ||||
txid = w0.sendtoaddress(addr, 10000000) | txid = w0.sendtoaddress(addr, 10000000) | ||||
vout = find_vout_for_address(self.nodes[0], txid, addr) | vout = find_vout_for_address(self.nodes[0], txid, addr) | ||||
self.generate(self.nodes[0], 6) | self.generate(self.nodes[0], 6) | ||||
assert_equal(wmulti_pub.getbalance(), wmulti_priv.getbalance()) | assert_equal(wmulti_pub.getbalance(), wmulti_priv.getbalance()) | ||||
# Make sure that descriptor wallets containing multiple xpubs in a | # Make sure that descriptor wallets containing multiple xpubs in a | ||||
# single descriptor load correctly | # single descriptor load correctly | ||||
wmulti_pub.unloadwallet() | wmulti_pub.unloadwallet() | ||||
self.nodes[1].loadwallet('wmulti_pub') | self.nodes[1].loadwallet("wmulti_pub") | ||||
self.log.info("Multisig with distributed keys") | self.log.info("Multisig with distributed keys") | ||||
self.nodes[1].createwallet( | self.nodes[1].createwallet(wallet_name="wmulti_priv1", descriptors=True) | ||||
wallet_name="wmulti_priv1", | |||||
descriptors=True) | |||||
wmulti_priv1 = self.nodes[1].get_wallet_rpc("wmulti_priv1") | wmulti_priv1 = self.nodes[1].get_wallet_rpc("wmulti_priv1") | ||||
res = wmulti_priv1.importdescriptors([ | res = wmulti_priv1.importdescriptors( | ||||
[ | |||||
{ | { | ||||
"desc": descsum_create("sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/0h/0h/*,[59b09cd6/84h/0h/0h]tpubDDBF2BTR6s8drwrfDei8WxtckGuSm1cyoKxYY1QaKSBFbHBYQArWhHPA6eJrzZej6nfHGLSURYSLHr7GuYch8aY5n61tGqgn8b4cXrMuoPH/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))"), | "desc": descsum_create( | ||||
"sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/0h/0h/*,[59b09cd6/84h/0h/0h]tpubDDBF2BTR6s8drwrfDei8WxtckGuSm1cyoKxYY1QaKSBFbHBYQArWhHPA6eJrzZej6nfHGLSURYSLHr7GuYch8aY5n61tGqgn8b4cXrMuoPH/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))" | |||||
), | |||||
"active": True, | "active": True, | ||||
"range": 1000, | "range": 1000, | ||||
"next_index": 0, | "next_index": 0, | ||||
"timestamp": "now" | "timestamp": "now", | ||||
}, | }, | ||||
{ | { | ||||
"desc": descsum_create("sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/1h/0h/*,[59b09cd6/84h/1h/0h]tpubDCYfZY2ceyHzYzMMVPt9MNeiqtQ2T7Uyp9QSFwYXh8Vi9iJFYXcuphJaGXfF3jUQJi5Y3GMNXvM11gaL4txzZgNGK22BFAwMXynnzv4z2Jh/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))"), | "desc": descsum_create( | ||||
"sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/1h/0h/*,[59b09cd6/84h/1h/0h]tpubDCYfZY2ceyHzYzMMVPt9MNeiqtQ2T7Uyp9QSFwYXh8Vi9iJFYXcuphJaGXfF3jUQJi5Y3GMNXvM11gaL4txzZgNGK22BFAwMXynnzv4z2Jh/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))" | |||||
), | |||||
"active": True, | "active": True, | ||||
"internal": True, | "internal": True, | ||||
"range": 1000, | "range": 1000, | ||||
"next_index": 0, | "next_index": 0, | ||||
"timestamp": "now" | "timestamp": "now", | ||||
}]) | }, | ||||
assert_equal(res[0]['success'], True) | ] | ||||
) | |||||
assert_equal(res[0]["success"], True) | |||||
assert_equal( | assert_equal( | ||||
res[0]['warnings'][0], | res[0]["warnings"][0], | ||||
'Not all private keys provided. Some wallet functionality may return unexpected errors') | ( | ||||
assert_equal(res[1]['success'], True) | "Not all private keys provided. Some wallet functionality may return" | ||||
" unexpected errors" | |||||
), | |||||
) | |||||
assert_equal(res[1]["success"], True) | |||||
assert_equal( | assert_equal( | ||||
res[1]['warnings'][0], | res[1]["warnings"][0], | ||||
'Not all private keys provided. Some wallet functionality may return unexpected errors') | ( | ||||
"Not all private keys provided. Some wallet functionality may return" | |||||
" unexpected errors" | |||||
), | |||||
) | |||||
self.nodes[1].createwallet( | self.nodes[1].createwallet( | ||||
wallet_name='wmulti_priv2', | wallet_name="wmulti_priv2", blank=True, descriptors=True | ||||
blank=True, | ) | ||||
descriptors=True) | wmulti_priv2 = self.nodes[1].get_wallet_rpc("wmulti_priv2") | ||||
wmulti_priv2 = self.nodes[1].get_wallet_rpc('wmulti_priv2') | res = wmulti_priv2.importdescriptors( | ||||
res = wmulti_priv2.importdescriptors([ | [ | ||||
{ | { | ||||
"desc": descsum_create("sh(multi(2,[7b2d0242/84h/0h/0h]tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/0h/0h/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))"), | "desc": descsum_create( | ||||
"sh(multi(2,[7b2d0242/84h/0h/0h]tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/0h/0h/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))" | |||||
), | |||||
"active": True, | "active": True, | ||||
"range": 1000, | "range": 1000, | ||||
"next_index": 0, | "next_index": 0, | ||||
"timestamp": "now" | "timestamp": "now", | ||||
}, | }, | ||||
{ | { | ||||
"desc": descsum_create("sh(multi(2,[7b2d0242/84h/1h/0h]tpubDCXqdwWZcszwqYJSnZp8eARkxGJfHAk23KDxbztV4BbschfaTfYLTcSkSJ3TN64dRqwa1rnFUScsYormKkGqNbbPwkorQimVevXjxzUV9Gf/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/1h/0h/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))"), | "desc": descsum_create( | ||||
"sh(multi(2,[7b2d0242/84h/1h/0h]tpubDCXqdwWZcszwqYJSnZp8eARkxGJfHAk23KDxbztV4BbschfaTfYLTcSkSJ3TN64dRqwa1rnFUScsYormKkGqNbbPwkorQimVevXjxzUV9Gf/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/1h/0h/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))" | |||||
), | |||||
"active": True, | "active": True, | ||||
"internal": True, | "internal": True, | ||||
"range": 1000, | "range": 1000, | ||||
"next_index": 0, | "next_index": 0, | ||||
"timestamp": "now" | "timestamp": "now", | ||||
}]) | }, | ||||
assert_equal(res[0]['success'], True) | ] | ||||
) | |||||
assert_equal(res[0]["success"], True) | |||||
assert_equal( | assert_equal( | ||||
res[0]['warnings'][0], | res[0]["warnings"][0], | ||||
'Not all private keys provided. Some wallet functionality may return unexpected errors') | ( | ||||
assert_equal(res[1]['success'], True) | "Not all private keys provided. Some wallet functionality may return" | ||||
" unexpected errors" | |||||
), | |||||
) | |||||
assert_equal(res[1]["success"], True) | |||||
assert_equal( | assert_equal( | ||||
res[1]['warnings'][0], | res[1]["warnings"][0], | ||||
'Not all private keys provided. Some wallet functionality may return unexpected errors') | ( | ||||
"Not all private keys provided. Some wallet functionality may return" | |||||
" unexpected errors" | |||||
), | |||||
) | |||||
rawtx = self.nodes[1].createrawtransaction( | rawtx = self.nodes[1].createrawtransaction( | ||||
[{'txid': txid, 'vout': vout}], {w0.getnewaddress(): 9999000}) | [{"txid": txid, "vout": vout}], {w0.getnewaddress(): 9999000} | ||||
) | |||||
tx_signed_1 = wmulti_priv1.signrawtransactionwithwallet(rawtx) | tx_signed_1 = wmulti_priv1.signrawtransactionwithwallet(rawtx) | ||||
assert_equal(tx_signed_1['complete'], False) | assert_equal(tx_signed_1["complete"], False) | ||||
tx_signed_2 = wmulti_priv2.signrawtransactionwithwallet( | tx_signed_2 = wmulti_priv2.signrawtransactionwithwallet(tx_signed_1["hex"]) | ||||
tx_signed_1['hex']) | assert_equal(tx_signed_2["complete"], True) | ||||
assert_equal(tx_signed_2['complete'], True) | self.nodes[1].sendrawtransaction(tx_signed_2["hex"]) | ||||
self.nodes[1].sendrawtransaction(tx_signed_2['hex']) | |||||
self.log.info("Combo descriptors cannot be active") | self.log.info("Combo descriptors cannot be active") | ||||
self.test_importdesc({"desc": descsum_create("combo(tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*)"), | self.test_importdesc( | ||||
{ | |||||
"desc": descsum_create( | |||||
"combo(tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*)" | |||||
), | |||||
"active": True, | "active": True, | ||||
"range": 1, | "range": 1, | ||||
"timestamp": "now"}, | "timestamp": "now", | ||||
}, | |||||
success=False, | success=False, | ||||
error_code=-4, | error_code=-4, | ||||
error_message="Combo descriptors cannot be set to active") | error_message="Combo descriptors cannot be set to active", | ||||
) | |||||
self.log.info("Descriptors with no type cannot be active") | self.log.info("Descriptors with no type cannot be active") | ||||
self.test_importdesc({"desc": descsum_create("pk(tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*)"), | self.test_importdesc( | ||||
{ | |||||
"desc": descsum_create( | |||||
"pk(tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*)" | |||||
), | |||||
"active": True, | "active": True, | ||||
"range": 1, | "range": 1, | ||||
"timestamp": "now"}, | "timestamp": "now", | ||||
}, | |||||
success=True, | success=True, | ||||
warnings=["Unknown output type, cannot set descriptor to active."]) | warnings=["Unknown output type, cannot set descriptor to active."], | ||||
) | |||||
if __name__ == '__main__': | if __name__ == "__main__": | ||||
ImportDescriptorsTest().main() | ImportDescriptorsTest().main() |