diff --git a/tests/fixtures.py b/tests/fixtures.py index 1c4c8624..ee8d5b7c 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -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 + ")" diff --git a/tests/test_misc.py b/tests/test_misc.py index 55841759..a1b23e6b 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -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):