In fec2019bdb3f97482fba54a1a4540f9e4ec44efd "test: cover keypath_only in wallet_taproot.py"
https://github.com/bitcoin/bitcoin/blob/5f33da9aa30ff80876f2f450b4370c446555bd71/test/functional/wallet_musig.py#L352
There's a very interesting test case in wallet_musig.py here where we contrive it to not be able to sign the 3-key-musig-keypath because of nosign_wallets=[0]. A new test case can be added there as well by not passing the nosign option and by instead passing this new option to not sign the script path. This test automatically generates all the required signers and is quite extensible. It would be nice to test the MuSig flow in this PR as well as this use case has been given as an example in the PR description too.
A diff like the below one works. I could not find a quick way to determine if the musig placeholders are within the script path so as to not count them in expected pubnonces and partialsigs.
diff --git a/test/functional/wallet_musig.py b/test/functional/wallet_musig.py
index 0e3e4377c0..43c2de0436 100755
--- a/test/functional/wallet_musig.py
+++ b/test/functional/wallet_musig.py
@@ -168,7 +168,7 @@ class WalletMuSigTest(BitcoinTestFramework):
assert "musig2_pubnonces" in dec["inputs"][0]
assert "musig2_partial_sigs" not in dec["inputs"][0]
- def test_success_case(self, comment, pattern, sighash_type=None, scriptpath=False, nosign_wallets=None, only_one_musig_wallet=False):
+ def test_success_case(self, comment, pattern, sighash_type=None, scriptpath=None, nosign_wallets=None, only_one_musig_wallet=False, expected_pubnonces_partialsigs=None):
self.log.info(f"Testing {comment}")
has_internal = MULTIPATH_TWO_RE.search(pattern) is not None
@@ -176,22 +176,26 @@ class WalletMuSigTest(BitcoinTestFramework):
wallets, keys = self.create_wallets_and_keys_from_pattern(pat)
self.construct_and_import_musig_descriptor_in_wallets(pat, wallets, keys, only_one_musig_wallet)
- expected_pubnonces = 0
- expected_partial_sigs = 0
- for musig in MUSIG_RE.findall(pat):
- musig_partial_sigs = 0
- for placeholder in PLACEHOLDER_RE.findall(musig):
- wallet_index = int(placeholder[1:])
- if nosign_wallets is None or wallet_index not in nosign_wallets:
- expected_pubnonces += 1
- else:
- musig_partial_sigs = None
+ if expected_pubnonces_partialsigs != None:
+ expected_pubnonces = expected_pubnonces_partialsigs['pubnonces']
+ expected_partial_sigs = expected_pubnonces_partialsigs['partialsigs']
+ else:
+ expected_pubnonces = 0
+ expected_partial_sigs = 0
+ for musig in MUSIG_RE.findall(pat):
+ musig_partial_sigs = 0
+ for placeholder in PLACEHOLDER_RE.findall(musig):
+ wallet_index = int(placeholder[1:])
+ if nosign_wallets is None or wallet_index not in nosign_wallets:
+ expected_pubnonces += 1
+ else:
+ musig_partial_sigs = None
+ if musig_partial_sigs is not None:
+ musig_partial_sigs += 1
+ if wallet_index < len(wallets):
+ continue
if musig_partial_sigs is not None:
- musig_partial_sigs += 1
- if wallet_index < len(wallets):
- continue
- if musig_partial_sigs is not None:
- expected_partial_sigs += musig_partial_sigs
+ expected_partial_sigs += musig_partial_sigs
# Check that the wallets agree on the same musig address
addr = None
@@ -252,7 +256,10 @@ class WalletMuSigTest(BitcoinTestFramework):
for i, wallet in enumerate(wallets):
if nosign_wallets and i in nosign_wallets:
continue
- proc = wallet.walletprocesspsbt(psbt=psbt, sighashtype=sighash_type)
+ if scriptpath == None:
+ proc = wallet.walletprocesspsbt(psbt=psbt, sighashtype=sighash_type)
+ else:
+ proc = wallet.walletprocesspsbt(psbt=psbt, sighashtype=sighash_type, keypath_only=not scriptpath)
assert_equal(proc["complete"], False)
nonce_psbts.append(proc["psbt"])
@@ -280,7 +287,10 @@ class WalletMuSigTest(BitcoinTestFramework):
for i, wallet in enumerate(wallets):
if nosign_wallets and i in nosign_wallets:
continue
- proc = wallet.walletprocesspsbt(psbt=comb_nonce_psbt, sighashtype=sighash_type)
+ if scriptpath == None:
+ proc = wallet.walletprocesspsbt(psbt=comb_nonce_psbt, sighashtype=sighash_type)
+ else:
+ proc = wallet.walletprocesspsbt(psbt=comb_nonce_psbt, sighashtype=sighash_type, keypath_only=not scriptpath)
assert_equal(proc["complete"], False)
psig_psbts.append(proc["psbt"])
@@ -333,6 +343,7 @@ class WalletMuSigTest(BitcoinTestFramework):
self.test_success_case("tr(H,{pk(musig/*), pk(same keys different musig/*)})", "tr($H,{pk(musig($0,$1,$2)/<0;1>/*),pk(musig($1,$2)/0/*)})", scriptpath=True)
self.test_success_case("tr(musig/*,{pk(partial keys diff musig-1/*),pk(partial keys diff musig-2/*)})}", "tr(musig($0,$1,$2)/<3;4>/*,{pk(musig($0,$1)/<5;6>/*),pk(musig($1,$2)/7/*)})")
self.test_success_case("tr(musig/*,{pk(partial keys diff musig-1/*),pk(partial keys diff musig-2/*)})} script-path", "tr(musig($0,$1,$2)/<3;4>/*,{pk(musig($0,$1)/<5;6>/*),pk(musig($1,$2)/7/*)})", scriptpath=True, nosign_wallets=[0])
+ self.test_success_case("tr(musig/*,{pk(partial keys diff musig-1/*),pk(partial keys diff musig-2/*)})} script-path", "tr(musig($0,$1,$2)/<3;4>/*,{pk(musig($0,$1)/<5;6>/*),pk(musig($1,$2)/7/*)})", scriptpath=False, expected_pubnonces_partialsigs={'pubnonces':3, 'partialsigs':3})
self.test_success_case("tr(H,and(pk(musig/*),after(1)))", "tr($H,and_v(v:pk(musig($0,$1,$2)/<0;1>/*),after(1)))", scriptpath=True)
self.test_success_case("tr(H,and(pk_k(musig/*),after(1)))", "tr($H,and_v(vc:pk_k(musig($0,$1,$2)/<0;1>/*),after(1)))", scriptpath=True)
self.test_success_case("tr(H,and(pkh(musig/*),after(1)))", "tr($H,and_v(v:pkh(musig($0,$1,$2)/<0;1>/*),after(1)))", scriptpath=True)