mirror of
https://github.com/Retropex/bitcoin.git
synced 2025-05-12 19:20:42 +02:00
codex32: add functional test for seed import
Github-Pull: #27351 Rebased-From: 91771366a3df22b9e8b4b7152d368d739bfeda94
This commit is contained in:
parent
b78c428f19
commit
de53d61a18
@ -307,6 +307,7 @@ BASE_SCRIPTS = [
|
||||
'mempool_expiry.py',
|
||||
'wallet_import_with_label.py --legacy-wallet',
|
||||
'wallet_importdescriptors.py --descriptors',
|
||||
'wallet_importseed.py --descriptors',
|
||||
'wallet_upgradewallet.py --legacy-wallet',
|
||||
'wallet_crosschain.py',
|
||||
'mining_basic.py',
|
||||
|
269
test/functional/wallet_importseed.py
Executable file
269
test/functional/wallet_importseed.py
Executable file
@ -0,0 +1,269 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2013 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test the 'seeds' argument to the importdescriptors RPC
|
||||
|
||||
Test importingi seeds by using the BIP 93 test vectors to verify that imported
|
||||
seeds are compatible with descriptors containing the corresponding xpubs, that
|
||||
the wallet is able to recognize and send funds, and that the wallet can derive
|
||||
addresses, when given only seeds as private data."""
|
||||
|
||||
import time
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
assert_raises_rpc_error,
|
||||
)
|
||||
|
||||
|
||||
class ImportDescriptorsTest(BitcoinTestFramework):
|
||||
def add_options(self, parser):
|
||||
self.add_wallet_options(parser, legacy=False)
|
||||
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 1
|
||||
self.setup_clean_chain = True
|
||||
self.wallet_names = []
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
test_start = int(time.time())
|
||||
|
||||
# Spend/receive tests
|
||||
self.nodes[0].createwallet(wallet_name='w0', descriptors=True)
|
||||
self.nodes[0].createwallet(wallet_name='w1', descriptors=True, blank=True)
|
||||
w0 = self.nodes[0].get_wallet_rpc('w0')
|
||||
w1 = self.nodes[0].get_wallet_rpc('w1')
|
||||
|
||||
self.generatetoaddress(self.nodes[0], 2, w0.getnewaddress())
|
||||
self.generate(self.nodes[0], 100)
|
||||
|
||||
# Test 1: send coins to wallet, check they are not received, then import
|
||||
# the descriptor and make sure they are recognized. Send them
|
||||
# back and repeat. Uses single codex32 seed.
|
||||
#
|
||||
# xpub converted from BIP 93 test vector 1 xpriv using rust-bitcoin
|
||||
xpub = "tpubD6NzVbkrYhZ4YAqhvsGTCD5axU32P9MH7ySPr38icriLyJc4KcCvwVzE3rsi" \
|
||||
"XaAHBC8QtYWhiBGdc6aZRmroQShGcWygQfErbvLULfJSi8j"
|
||||
descriptors = [
|
||||
f"wsh(pk({xpub}/55/*))",
|
||||
f"tr({xpub}/1/2/3/4/5/*)",
|
||||
f"pkh({xpub}/*)",
|
||||
f"wpkh({xpub}/*)",
|
||||
f"rawtr({xpub}/1/2/3/*)",
|
||||
]
|
||||
assert_raises_rpc_error(-4, "This wallet has no available keys", w1.getnewaddress)
|
||||
for descriptor in descriptors:
|
||||
descriptor_chk = w0.getdescriptorinfo(descriptor)["descriptor"]
|
||||
addr = w0.deriveaddresses(descriptor_chk, range=[0, 20])[0]
|
||||
|
||||
assert w0.getbalance() > 99 # sloppy balance checks, to account for fees
|
||||
w0.sendtoaddress(addr, 95)
|
||||
self.generate(self.nodes[0], 1)
|
||||
assert w0.getbalance() < 5
|
||||
|
||||
w1.importdescriptors(
|
||||
[{"desc": descriptor_chk, "timestamp": test_start, "range": 0, "active": True}],
|
||||
[["ms10testsxxxxxxxxxxxxxxxxxxxxxxxxxx4nzvca9cmczlw"]],
|
||||
)
|
||||
|
||||
assert w1.getbalance() > 94
|
||||
w1.sendtoaddress(w0.getnewaddress(), 95, "", "", True)
|
||||
self.generate(self.nodes[0], 1)
|
||||
assert w0.getbalance() > 99
|
||||
w1.getnewaddress() # no failure now
|
||||
|
||||
# Test 2: deriveaddresses on hardened keys fails before import, succeeds after.
|
||||
# Uses single codex32 seed in 2 shares.
|
||||
#
|
||||
# xpub converted from BIP 93 test vector 2 xpriv using rust-bitcoin
|
||||
self.nodes[0].createwallet(wallet_name='w2', descriptors=True, blank=True)
|
||||
w2 = self.nodes[0].get_wallet_rpc('w2')
|
||||
|
||||
xpub = "tpubD6NzVbkrYhZ4Wf289qp46iFM6zACTdXTqqrA3pKUV8bF8SNBcYS8xvVPZg43" \
|
||||
"6YhSuCqTKLfnDkmwi9TE6fa5cvxm3NHRCBbgJoC6YgsQBFY"
|
||||
descriptor = f"tr([fab6868a/1h/2]{xpub}/1h/2/*h)"
|
||||
descriptor_chk = w2.getdescriptorinfo(descriptor)["descriptor"]
|
||||
assert_raises_rpc_error(
|
||||
-4,
|
||||
"This wallet has no available keys",
|
||||
w2.getnewaddress,
|
||||
address_type="bech32m",
|
||||
)
|
||||
|
||||
# Try importing descriptor with wrong seed
|
||||
err = w2.importdescriptors(
|
||||
[{"desc": descriptor_chk, "timestamp": test_start, "active": True, "range": [0, 20]}],
|
||||
[["ms10testsxxxxxxxxxxxxxxxxxxxxxxxxxx4nzvca9cmczlw"]],
|
||||
)
|
||||
assert "Cannot expand descriptor." in err[0]["error"]["message"]
|
||||
assert_raises_rpc_error(
|
||||
-4,
|
||||
"This wallet has no available keys",
|
||||
w2.getnewaddress,
|
||||
address_type="bech32m",
|
||||
)
|
||||
|
||||
# Try various failure cases
|
||||
assert_raises_rpc_error(
|
||||
-5,
|
||||
"single share must be the S share",
|
||||
w2.importdescriptors,
|
||||
[{"desc": descriptor_chk, "timestamp": test_start, "active": True, "range": [0, 20]}],
|
||||
[["MS12NAMEA320ZYXWVUTSRQPNMLKJHGFEDCAXRPP870HKKQRM"]],
|
||||
)
|
||||
|
||||
assert_raises_rpc_error(
|
||||
-5,
|
||||
"two input shares had the same index",
|
||||
w2.importdescriptors,
|
||||
[{"desc": descriptor_chk, "timestamp": test_start, "active": True, "range": [0, 20]}],
|
||||
[[
|
||||
"MS12NAMEA320ZYXWVUTSRQPNMLKJHGFEDCAXRPP870HKKQRM",
|
||||
"MS12NAMEA320ZYXWVUTSRQPNMLKJHGFEDCAXRPP870HKKQRM",
|
||||
]],
|
||||
)
|
||||
|
||||
assert_raises_rpc_error(
|
||||
-5,
|
||||
"input shares had inconsistent seed IDs",
|
||||
w2.importdescriptors,
|
||||
[{"desc": descriptor_chk, "timestamp": test_start, "active": True, "range": [0, 20]}],
|
||||
[[
|
||||
"MS12NAMEA320ZYXWVUTSRQPNMLKJHGFEDCAXRPP870HKKQRM",
|
||||
"ms13cashcacdefghjklmnpqrstuvwxyz023949xq35my48dr",
|
||||
]],
|
||||
)
|
||||
|
||||
# Do it correctly
|
||||
w2.importdescriptors(
|
||||
[{"desc": descriptor_chk, "timestamp": test_start, "active": True, "range": [0, 20]}],
|
||||
[[
|
||||
"MS12NAMEA320ZYXWVUTSRQPNMLKJHGFEDCAXRPP870HKKQRM",
|
||||
"MS12NAMECACDEFGHJKLMNPQRSTUVWXYZ023FTR2GDZMPY6PN",
|
||||
]],
|
||||
)
|
||||
# getnewaddress no longer fails. Annoyingl, deriveaddresses will
|
||||
w2.getnewaddress(address_type="bech32m")
|
||||
assert_raises_rpc_error(
|
||||
-5,
|
||||
"Cannot derive script without private keys",
|
||||
w2.deriveaddresses,
|
||||
descriptor_chk,
|
||||
0,
|
||||
)
|
||||
# Do it again, to see if nothing breaks
|
||||
w2.importdescriptors(
|
||||
[{"desc": descriptor_chk, "timestamp": test_start, "active": True, "range": [0, 20]}],
|
||||
[[
|
||||
"MS12NAMEA320ZYXWVUTSRQPNMLKJHGFEDCAXRPP870HKKQRM",
|
||||
"MS12NAMECACDEFGHJKLMNPQRSTUVWXYZ023FTR2GDZMPY6PN",
|
||||
]],
|
||||
)
|
||||
|
||||
# Test 3: multiple seeds, multiple descriptors
|
||||
#
|
||||
# xpubs converted from BIP 93 test vector 3, 4 and 5 xprivs using rust-bitcoin
|
||||
|
||||
self.nodes[0].createwallet(wallet_name='w3', descriptors=True, blank=True)
|
||||
w3 = self.nodes[0].get_wallet_rpc('w3')
|
||||
xpub1 = "tpubD6NzVbkrYhZ4WNNA2qNKYbaxKR3TYtP2n5bNSj6JKzYsVUPxahe2vWJKwiX2" \
|
||||
"wfoTJyERQNJ8YnmJvprMHygyaXziTdyFVsSGNmfQtDCCSJ3" # vector 3
|
||||
xpub2 = "tpubD6NzVbkrYhZ4Y9KL2R346X9ZwcN16c37vjXuZEhDV2LaMt84zqVbKVbVAw1z" \
|
||||
"nMksNtdKnSRZQXyBL9qJaNnq9BkjtRBdsQbxkTbSGZGrcG6" # vector 4
|
||||
xpub3 = "tpubD6NzVbkrYhZ4Ykomd4u92cmRCkhZtctLkKU3vCVi7DKBAopRDWVpq6wEGoq7" \
|
||||
"xYbCQQjEGM8KkqxvQDoLa3sdfpzTBv1yodq4FKwrCdxweHE" # vector 5
|
||||
|
||||
descriptor1 = f"rawtr({xpub1}/1/2h/*)"
|
||||
descriptor1_chk = w3.getdescriptorinfo(descriptor1)["descriptor"]
|
||||
descriptor2 = f"wpkh({xpub2}/1h/2/*)"
|
||||
descriptor2_chk = w3.getdescriptorinfo(descriptor2)["descriptor"]
|
||||
descriptor3 = f"pkh({xpub3}/1h/2/3/4/5/6/7/8/9/10/*)"
|
||||
descriptor3_chk = w3.getdescriptorinfo(descriptor3)["descriptor"]
|
||||
|
||||
assert_raises_rpc_error(
|
||||
-4,
|
||||
"This wallet has no available keys",
|
||||
w3.getnewaddress,
|
||||
address_type="bech32m",
|
||||
)
|
||||
assert_raises_rpc_error(
|
||||
-4,
|
||||
"This wallet has no available keys",
|
||||
w3.getnewaddress,
|
||||
address_type="bech32",
|
||||
)
|
||||
assert_raises_rpc_error(
|
||||
-4,
|
||||
"This wallet has no available keys",
|
||||
w3.getnewaddress,
|
||||
address_type="legacy",
|
||||
)
|
||||
|
||||
# First try without enough input shares.
|
||||
assert_raises_rpc_error(
|
||||
-5,
|
||||
"did not have enough input shares",
|
||||
w3.importdescriptors,
|
||||
[
|
||||
{"desc": descriptor1_chk, "timestamp": test_start, "active": True, "range": 10},
|
||||
{"desc": descriptor2_chk, "timestamp": test_start, "active": True, "range": 15},
|
||||
],
|
||||
[[
|
||||
"ms13casheekgpemxzshcrmqhaydlp6yhms3ws7320xyxsar9",
|
||||
"ms13cashf8jh6sdrkpyrsp5ut94pj8ktehhw2hfvyrj48704",
|
||||
], [
|
||||
"ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqqtum9pgv99ycma",
|
||||
]],
|
||||
)
|
||||
# Wallet still doesn't work, even the descriptor whose seed was correctly specified
|
||||
assert_raises_rpc_error(
|
||||
-4,
|
||||
"This wallet has no available keys",
|
||||
w3.getnewaddress,
|
||||
address_type="bech32",
|
||||
)
|
||||
|
||||
# Do it properly
|
||||
w3.importdescriptors(
|
||||
[
|
||||
{"desc": descriptor1_chk, "timestamp": test_start, "active": True, "range": 10},
|
||||
{"desc": descriptor2_chk, "timestamp": test_start, "active": True, "range": 15},
|
||||
{"desc": descriptor3_chk, "timestamp": test_start, "active": True, "range": 15},
|
||||
],
|
||||
[[
|
||||
"ms13cashd0wsedstcdcts64cd7wvy4m90lm28w4ffupqs7rm",
|
||||
"ms13casheekgpemxzshcrmqhaydlp6yhms3ws7320xyxsar9",
|
||||
"ms13cashf8jh6sdrkpyrsp5ut94pj8ktehhw2hfvyrj48704",
|
||||
], [
|
||||
"ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqqtum9pgv99ycma",
|
||||
]],
|
||||
)
|
||||
# All good now for the two descriptors that had seeds
|
||||
w3.getnewaddress(address_type="bech32")
|
||||
w3.getnewaddress(address_type="bech32m")
|
||||
# but the one without a seed still doesn't work
|
||||
assert_raises_rpc_error(
|
||||
-12,
|
||||
"No legacy addresses available",
|
||||
w3.getnewaddress,
|
||||
address_type="legacy",
|
||||
)
|
||||
|
||||
# Ok, try to import the legacy one separately.
|
||||
w3.importdescriptors(
|
||||
[{"desc": descriptor3_chk, "timestamp": test_start, "active": True, "range": 15}],
|
||||
[["MS100C8VSM32ZXFGUHPCHTLUPZRY9X8GF2TVDW0S3JN54KHCE6MUA7LQPZYGSFJD" # concat string
|
||||
"6AN074RXVCEMLH8WU3TK925ACDEFGHJKLMNPQRSTUVWXY06FHPV80UNDVARHRAK"]],
|
||||
)
|
||||
# And all is well!
|
||||
w3.getnewaddress(address_type="bech32")
|
||||
w3.getnewaddress(address_type="bech32m")
|
||||
w3.getnewaddress(address_type="legacy")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ImportDescriptorsTest(__file__).main()
|
Loading…
Reference in New Issue
Block a user