qa: don't use a static dummy origin for descriptor xpubs

This commit is contained in:
Antoine Poinsot 2023-10-06 18:17:45 +02:00
parent a81d39c81a
commit b71bd693d6
No known key found for this signature in database
GPG Key ID: E13FC145CD3F4304
2 changed files with 57 additions and 40 deletions

View File

@ -1,4 +1,5 @@
from bip32 import BIP32
from bip32.utils import _pubkey_to_fingerprint
from bip380.descriptors import Descriptor
from concurrent import futures
from test_framework.bitcoind import Bitcoind
@ -115,6 +116,10 @@ def bitcoind(directory):
bitcoind.cleanup()
def xpub_fingerprint(hd):
return _pubkey_to_fingerprint(hd.pubkey).hex()
@pytest.fixture
def lianad(bitcoind, directory):
datadir = os.path.join(directory, "lianad")
@ -122,13 +127,15 @@ def lianad(bitcoind, directory):
bitcoind_cookie = os.path.join(bitcoind.bitcoin_dir, "regtest", ".cookie")
signer = SingleSigner()
primary_xpub, recovery_xpub = (
signer.primary_hd.get_xpub(),
signer.recovery_hd.get_xpub(),
(prim_fingerprint, primary_xpub), (reco_fingerprint, recovery_xpub) = (
(xpub_fingerprint(signer.primary_hd), signer.primary_hd.get_xpub()),
(xpub_fingerprint(signer.recovery_hd), signer.recovery_hd.get_xpub()),
)
csv_value = 10
# NOTE: origins are the actual xpub themselves which is incorrect but make it
# possible to differentiate them.
main_desc = Descriptor.from_str(
f"wsh(or_d(pk([aabbccdd]{primary_xpub}/<0;1>/*),and_v(v:pkh([aabbccdd]{recovery_xpub}/<0;1>/*),older({csv_value}))))"
f"wsh(or_d(pk([{prim_fingerprint}]{primary_xpub}/<0;1>/*),and_v(v:pkh([{reco_fingerprint}]{recovery_xpub}/<0;1>/*),older({csv_value}))))"
)
lianad = Lianad(
@ -152,7 +159,10 @@ def lianad(bitcoind, directory):
def multi_expression(thresh, keys):
exp = f"multi({thresh},"
for i, key in enumerate(keys):
exp += f"[aabbccdd]{key.get_xpub()}/<0;1>/*"
# NOTE: origins are the actual xpub themselves which is incorrect but make it
# possible to differentiate them.
fingerprint = xpub_fingerprint(key)
exp += f"[{fingerprint}]{key.get_xpub()}/<0;1>/*"
if i != len(keys) - 1:
exp += ","
return exp + ")"

View File

@ -127,11 +127,16 @@ def test_multipath(lianad_multipath, bitcoind):
reco_psbt = PSBT.from_base64(res["psbt"])
txid = reco_psbt.tx.txid().hex()
# NOTE: this test was commented out due to the introduced restriction to not include
# the BIP32 derivations for other spending paths in PSBT inputs to support the Bitbox2
# signing device (and most likely others).
# TODO: reintroduce these tests once we get rid of this restriction.
# Try to sign with the keys for the next recovery spending path, it'll fail.
signed_psbt = lianad_multipath.signer.sign_psbt(reco_psbt, {20: range(3)})
lianad_multipath.rpc.updatespend(signed_psbt.to_base64())
with pytest.raises(RpcError, match="Failed to finalize"):
lianad_multipath.rpc.broadcastspend(txid)
# signed_psbt = lianad_multipath.signer.sign_psbt(reco_psbt, {20: range(3)})
# lianad_multipath.rpc.updatespend(signed_psbt.to_base64())
# with pytest.raises(RpcError, match="Failed to finalize"):
# lianad_multipath.rpc.broadcastspend(txid)
# Try to sign with the right keys but only two of them, it'll fail.
signed_psbt = lianad_multipath.signer.sign_psbt(reco_psbt, {10: range(2)})
@ -144,52 +149,54 @@ def test_multipath(lianad_multipath, bitcoind):
lianad_multipath.rpc.updatespend(signed_psbt.to_base64())
lianad_multipath.rpc.broadcastspend(txid)
# NOTE: commented out for the same reason as above.
# Receive 3 more coins and make the second recovery path (20 blocks) available.
txids = []
for _ in range(3):
addr = lianad_multipath.rpc.getnewaddress()["address"]
txids.append(bitcoind.rpc.sendtoaddress(addr, 0.42))
bitcoind.generate_block(20, wait_for_mempool=txids)
wait_for(
lambda: lianad_multipath.rpc.getinfo()["block_height"]
== bitcoind.rpc.getblockcount()
)
# txids = []
# for _ in range(3):
# addr = lianad_multipath.rpc.getnewaddress()["address"]
# txids.append(bitcoind.rpc.sendtoaddress(addr, 0.42))
# bitcoind.generate_block(20, wait_for_mempool=txids)
# wait_for(
# lambda: lianad_multipath.rpc.getinfo()["block_height"]
# == bitcoind.rpc.getblockcount()
# )
# We can create a recovery transaction for an earlier timelock.
lianad_multipath.rpc.createrecovery(bitcoind.rpc.getnewaddress(), 2)
# lianad_multipath.rpc.createrecovery(bitcoind.rpc.getnewaddress(), 2)
# Sweep all coins through the second recovery path (that is available after 20 blocks).
# It needs 3 signatures out of 5 keys.
res = lianad_multipath.rpc.createrecovery(bitcoind.rpc.getnewaddress(), 2, 20)
reco_psbt = PSBT.from_base64(res["psbt"])
txid = reco_psbt.tx.txid().hex()
# res = lianad_multipath.rpc.createrecovery(bitcoind.rpc.getnewaddress(), 2, 20)
# reco_psbt = PSBT.from_base64(res["psbt"])
# txid = reco_psbt.tx.txid().hex()
# We can sign with any keys for the second recovery path (we need only 1 out of 10)
signed_psbt = lianad_multipath.signer.sign_psbt(reco_psbt, {20: [8]})
lianad_multipath.rpc.updatespend(signed_psbt.to_base64())
lianad_multipath.rpc.broadcastspend(txid)
# signed_psbt = lianad_multipath.signer.sign_psbt(reco_psbt, {20: [8]})
# lianad_multipath.rpc.updatespend(signed_psbt.to_base64())
# lianad_multipath.rpc.broadcastspend(txid)
# Now do this again but with signing using keys for the first recovery path.
# Receive 3 more coins and make the second recovery path (20 blocks) available. Note this
# is possible since the CSV checks the nSequence is >= to the value, not ==.
txids = []
for _ in range(3):
addr = lianad_multipath.rpc.getnewaddress()["address"]
txids.append(bitcoind.rpc.sendtoaddress(addr, 0.398))
bitcoind.generate_block(20, wait_for_mempool=txids)
wait_for(
lambda: lianad_multipath.rpc.getinfo()["block_height"]
== bitcoind.rpc.getblockcount()
)
# txids = []
# for _ in range(3):
# addr = lianad_multipath.rpc.getnewaddress()["address"]
# txids.append(bitcoind.rpc.sendtoaddress(addr, 0.398))
# bitcoind.generate_block(20, wait_for_mempool=txids)
# wait_for(
# lambda: lianad_multipath.rpc.getinfo()["block_height"]
# == bitcoind.rpc.getblockcount()
# )
# Sweep all coins through the second recovery path (that is available after 20 blocks).
# It needs 3 signatures out of 5 keys.
res = lianad_multipath.rpc.createrecovery(bitcoind.rpc.getnewaddress(), 2, 20)
reco_psbt = PSBT.from_base64(res["psbt"])
txid = reco_psbt.tx.txid().hex()
# res = lianad_multipath.rpc.createrecovery(bitcoind.rpc.getnewaddress(), 2, 20)
# reco_psbt = PSBT.from_base64(res["psbt"])
# txid = reco_psbt.tx.txid().hex()
# We can sign with keys for the first recovery path (we need 3 out of 5)
signed_psbt = lianad_multipath.signer.sign_psbt(reco_psbt, {10: range(2, 5)})
lianad_multipath.rpc.updatespend(signed_psbt.to_base64())
lianad_multipath.rpc.broadcastspend(txid)
# signed_psbt = lianad_multipath.signer.sign_psbt(reco_psbt, {10: range(2, 5)})
# lianad_multipath.rpc.updatespend(signed_psbt.to_base64())
# lianad_multipath.rpc.broadcastspend(txid)
def test_coinbase_deposit(lianad, bitcoind):