wallet: allow skipping script paths #32857

pull Sjors wants to merge 6 commits into bitcoin:master from Sjors:2025/07/no_script_path changing 10 files +220 −22
  1. Sjors commented at 2:13 PM on July 2, 2025: member

    While testing MuSig2 integration in #29675 I ran into a Ledger bug https://github.com/LedgerHQ/app-bitcoin-new/issues/329 that was triggered because we signed for a script path in addition to the key path. The bug itself will be fixed, but it seems useful in general to be able to skip script path signing.

    For example, you may have a 2-of-2 musig() descriptor with some sort of fallback after coins are N blocks old. For both on chain privacy and fee reasons, you don't want to use this path unless absolutely necessary. But our wallet can't know if our co-signer still has their key, so we sign the script path at all times. This could lead to accidental broadcast.

    This PR introduces a keypath_only option (default false for now) to:

    • the send RPC
    • the walletprocesspsbt RPC.

    The resulting PSBT won't include taproot_scripts or taproot_script_path_sigs. It does still have taproot_bip32_derivs and musig2_participant_pubkeys.

    The wallet_taproot.py tests are expanded to cover this behavior.

    It can also be tested with https://github.com/Sjors/bitcoin/pull/91.

  2. DrahtBot added the label Wallet on Jul 2, 2025
  3. DrahtBot commented at 2:13 PM on July 2, 2025: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/32857.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    Concept ACK rkrux

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #35493 (wallet, descriptor: Fix MuSig private key completeness checks on importdescriptors by w0xlt)
    • #35370 (rpc: add stripbip32derivs to PSBT processing RPCs by junbyjun1238)
    • #34697 (descriptor: fix musig duplicate checks and origin handling by shuv-amp)
    • #32958 (wallet/refactor: Update SignPSBTInput to return util::Expected<void, PSBTError> and remove PSBTError:Ok by kevkevinpal)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  4. DrahtBot added the label CI failed on Jul 2, 2025
  5. DrahtBot commented at 3:53 PM on July 2, 2025: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task ARM, unit tests, no functional tests: https://github.com/bitcoin/bitcoin/runs/45219351756</sub> <sub>LLM reason (✨ experimental): Compilation error due to passing a bool where an int* is expected in fillPSBT function.</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>

  6. fanquake commented at 4:04 PM on July 2, 2025: member
  7. Sjors commented at 4:35 PM on July 2, 2025: member

    @fanquake because it's in the fuzzer code, I incorrectly changed one of the function signatures there.

  8. Sjors force-pushed on Jul 2, 2025
  9. Sjors commented at 4:53 PM on July 2, 2025: member

    From the original description:

    Under the hood it adds m_hide_script_paths to the HidingSigningProvider which triggers an early return in GetTaprootSpendData() when set.

    It's also missing taproot_scripts which might be a bit too much. At least in initial testing Ledger wouldn't sign it.

    I probably need to implement this at the SigningProvider level rather than HidingSigningProvider. The early return needs to be inside SignTaproot() right before // Try script path spending rather than in GetTaprootSpendData(). The goal isn't to hide leaf scripts from co-signers, only to make sure we don't sign them ourselves.

  10. Sjors force-pushed on Jul 2, 2025
  11. Sjors commented at 6:31 PM on July 2, 2025: member

    Shoehorning this into SigningProvider got ugly real fast. So instead I endup up passing avoid_script_path along the call stack from SignPSBTInput to SignTaproot. Which is also ugly...

    Well, it compiles and works. Thoughts on how to implement this elegantly?

  12. Sjors force-pushed on Jul 3, 2025
  13. Sjors commented at 12:48 PM on July 3, 2025: member

    The walletprocesspsbt RPC now also has this option. Added test coverage by expanding wallet_taproot.py.

  14. Sjors force-pushed on Jul 3, 2025
  15. Sjors commented at 2:01 PM on July 3, 2025: member

    I split off a non-behavior-changing commit that adds avoid_script_path to FillPSBT. I think it makes sense to pass this option here, although in general we may want to refactor FillPSBT to take an options struct instead of this ever expanding argument list. That could be an independent or prerequisite PR.

    I then did the same for SignPSBTInput, where I also think struct would be better.

    Rinse and repeat for ::SignTransaction.

    Will continue later to further split 09334ae0bd7939ed7476eb2b36f3bf8085885fe7. It might make sense to add a property to BaseSignatureCreator or it subclasses?

  16. DrahtBot removed the label CI failed on Jul 3, 2025
  17. Sjors referenced this in commit ea493972d2 on Jul 4, 2025
  18. Sjors referenced this in commit edbb5d8df3 on Jul 4, 2025
  19. Sjors referenced this in commit 2829cb78c5 on Jul 4, 2025
  20. Sjors force-pushed on Jul 4, 2025
  21. Sjors commented at 1:45 PM on July 4, 2025: member

    I opened #32876 and rebased this PR on top of it. That allowed me to drop 1486f05c8eded02d72690bf34d983a03e4ad748b + efc34a514b59cc1bab6e4d0f80c197481561c429.

  22. Sjors force-pushed on Jul 4, 2025
  23. Sjors commented at 4:02 PM on July 4, 2025: member

    I expanded #32876 with SignOptions. This shrinks 93fb607af3141ff1e22693588f498764401fc2c4 to just e2a151c3dc35997ac0f515feb292fc4543093593 which is very small ... but very ugly: casting BaseSignatureCreator to MutableTransactionSignatureCreator to access its avoid_script_path option.

  24. Sjors commented at 7:57 AM on July 7, 2025: member

    This may also be useful for Silent Payments, cc @josibake.

  25. Sjors commented at 12:59 PM on July 7, 2025: member

    Sidenote: currently it's unlikely you'll accidentally spend via an older() or after() script path. This is because you need to manually set the input sequence field in the send (etc.) RPC (and manually adjust the fee rate). Found out the hard way while testing 🤦 (there's currently no useful feedback when this happens).

  26. DrahtBot added the label Needs rebase on Jul 7, 2025
  27. Sjors referenced this in commit 2923087479 on Jul 8, 2025
  28. Sjors force-pushed on Jul 8, 2025
  29. DrahtBot removed the label Needs rebase on Jul 8, 2025
  30. Sjors referenced this in commit 576da4c7dd on Jul 8, 2025
  31. Sjors force-pushed on Jul 8, 2025
  32. Sjors referenced this in commit 8660b55c88 on Jul 11, 2025
  33. Sjors force-pushed on Jul 14, 2025
  34. DrahtBot added the label Needs rebase on Jul 29, 2025
  35. Sjors force-pushed on Jul 29, 2025
  36. Sjors referenced this in commit 8c268ff1d7 on Jul 29, 2025
  37. DrahtBot removed the label Needs rebase on Jul 29, 2025
  38. Sjors referenced this in commit 6703cc7743 on Aug 1, 2025
  39. DrahtBot added the label Needs rebase on Aug 19, 2025
  40. Sjors commented at 11:51 AM on August 25, 2025: member

    Holding off on rebasing until #32876 is merged or I have to touch it.

  41. rkrux commented at 12:39 PM on October 6, 2025: contributor

    Sidenote: currently it's unlikely you'll accidentally spend via an older() or after() script path. This is because you need to manually set the input sequence field in the send (etc.) RPC (and manually adjust the fee rate). Found out the hard way while testing 🤦 (there's currently no useful feedback when this happens).

    Scenario that I have not tested but expect to behave in this way: 3 signers (A, B, C) form a MuSig (ABC) in the keypath and also have 3 non-Musig multi-sig script paths (AB, BC, AC) without any timelocks. They intend to MuSig sign in order from A to C to spend via keypath and start the signing flow first by producing nonces in the mentioned order, and then by adding partial signatures. By the time B adds its nonce, there'd would be a fully signed spendable script path? If yes, seems unusual to have this when the intent of the signers was for keypath spending, which makes a good case for this PR.

    I did notice unconditional key and script path signing within SignTaproot function when I was reviewing #29675. We tried to simulate an intentional script path spending like above in #29675 by making A a no-signing wallet in the last test case in functional tests: https://github.com/bitcoin/bitcoin/pull/29675/commits/ac599c4a9cb3b2d424932d3fd91f9eed17426827#diff-c94f9555a2569240d362a00a82764f4714f6c65283e3f96725cf2a1043a296b5R238. Though the script path in that case is using MuSig but the overall unconditional script signing principle is still applicable.

  42. rkrux commented at 12:42 PM on October 6, 2025: contributor

    If #32876 is not garnering reviews, can consider undrafting this PR itself because it contains 7 commits only. Allowing skipping script path spending optionally seems reasonable to me and a ready-to-review PR is more inviting than a draft one.

  43. Sjors commented at 8:10 AM on October 7, 2025: member

    @rkrux I'm not too worried about reviews just yet, let's focus on getting #29675 in.

  44. Sjors referenced this in commit 4c11b25943 on Oct 16, 2025
  45. Sjors force-pushed on Oct 16, 2025
  46. DrahtBot removed the label Needs rebase on Oct 16, 2025
  47. Sjors referenced this in commit a2a20b97ca on Nov 4, 2025
  48. Sjors force-pushed on Nov 4, 2025
  49. DrahtBot added the label Needs rebase on Nov 18, 2025
  50. Sjors referenced this in commit 643e6dc59a on Jan 5, 2026
  51. Sjors force-pushed on Jan 5, 2026
  52. DrahtBot removed the label Needs rebase on Jan 5, 2026
  53. Sjors referenced this in commit e4a1397fea on Jan 22, 2026
  54. Sjors force-pushed on Jan 22, 2026
  55. DrahtBot added the label CI failed on Jan 22, 2026
  56. DrahtBot added the label Needs rebase on Mar 25, 2026
  57. Sjors referenced this in commit 66ce046ab6 on Mar 26, 2026
  58. Sjors force-pushed on Mar 26, 2026
  59. DrahtBot removed the label CI failed on Mar 26, 2026
  60. DrahtBot removed the label Needs rebase on Mar 26, 2026
  61. DrahtBot added the label Needs rebase on Apr 19, 2026
  62. Sjors referenced this in commit b3788bf2fc on Apr 22, 2026
  63. Sjors force-pushed on Apr 22, 2026
  64. DrahtBot added the label CI failed on Apr 22, 2026
  65. DrahtBot removed the label Needs rebase on Apr 23, 2026
  66. Sjors referenced this in commit dc4a5d1270 on Apr 28, 2026
  67. sedited referenced this in commit cef58341a0 on Apr 29, 2026
  68. DrahtBot added the label Needs rebase on Apr 29, 2026
  69. Sjors force-pushed on Apr 30, 2026
  70. Sjors commented at 9:45 AM on April 30, 2026: member

    Rebased after #32876 landed. I need to check a few more things before marking this as ready for review.

  71. DrahtBot removed the label CI failed on Apr 30, 2026
  72. DrahtBot removed the label Needs rebase on Apr 30, 2026
  73. Sjors force-pushed on May 1, 2026
  74. Sjors force-pushed on May 15, 2026
  75. Sjors commented at 3:22 PM on May 15, 2026: member

    Rebased after #29136 landed.

    Added test coverage for the send RPC (ad364249baebe9f75f24e32358d1f1f514c98f1d -> 8bd15fd779f8ac43c15f32d8b52a6439ec738d9f)

    Redesigned ed89145afb12138b8e6664bc9acdda4772028115 wallet: add option to avoid script path spends to pass SignOptions through ProduceSignature into SignTaproot (9bfdfaea2dbd62b8f86be90df18fb9cd61bac60f + f77a74743ececdf98dff9188c19f13c725b21801).

    SignTaproot now also clears spenddata.scripts when avoid_script_path is set.

  76. Sjors marked this as ready for review on May 15, 2026
  77. sedited requested review from rkrux on Jun 7, 2026
  78. in src/rpc/client.cpp:218 in 52a5ace371 outdated
     213 | @@ -214,6 +214,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
     214 |      { "walletprocesspsbt", 2, "sighashtype", ParamFormat::STRING },
     215 |      { "walletprocesspsbt", 3, "bip32derivs" },
     216 |      { "walletprocesspsbt", 4, "finalize" },
     217 | +    { "walletprocesspsbt", 5, "keypath_only"},
     218 |      { "descriptorprocesspsbt", 0, "psbt", ParamFormat::STRING },
    


    rkrux commented at 1:25 PM on June 8, 2026:

    In 52a5ace3718dae474ce09c1e06aa26293a4e82dc "rpc: add keypath_only to walletprocesspsbt"

    descriptorprocesspsbt also does signing, it won't be far fetched to allow this option in that RPC too.


    Sjors commented at 3:17 PM on June 9, 2026:

    Done in 8d819f7d8e6e93b8132ae0e621ad39740a9493df.

  79. in src/rpc/client.cpp:272 in 8bd15fd779 outdated
     266 | @@ -267,6 +267,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
     267 |      { "send", 4, "replaceable"},
     268 |      { "send", 4, "solving_data"},
     269 |      { "send", 4, "max_tx_weight"},
     270 | +    { "send", 4, "keypath_only"},
     271 |      { "send", 5, "version"},
     272 |      { "sendall", 0, "recipients" },
    


    rkrux commented at 1:27 PM on June 8, 2026:

    In 8bd15fd779f8ac43c15f32d8b52a6439ec738d9f "rpc: add keypath_only to send"

    FinishTransaction is updated in this PR to have this option. It's used by send and sendall, so it seems reasonable to have this option in sendall too.


    rkrux commented at 1:32 PM on June 8, 2026:

    In 8bd15fd "rpc: add keypath_only to send"

    Along similar lines, sendmany and sendtoaddress also have similar expectations as send, which includes signing. Although it seems congruent to add this option in those RPCs too but it might involve a little bit more refactoring because of a slightly different flow taken by them. Though ultimately they end up calling SignTransaction that already has been updated in this PR.


    Sjors commented at 2:19 PM on June 8, 2026:

    I'll add sendall, but I'm inclined leave the older sendmany and sendtoaddress alone. They also can't be used with external signers.


    rkrux commented at 2:23 PM on June 8, 2026:

    Oh, I didn't know they were older.

    Seems fine to me to not update them in this PR, they don't use the common internal signing/processing functions as well.

  80. rkrux commented at 1:53 PM on June 8, 2026: contributor

    Concept ACK 8bd15fd779f8ac43c15f32d8b52a6439ec738d9f

    Seems like a useful feature to have, the example in the PR description is helpful for the motivation. Asked a couple questions around updating other similar RPCs.

  81. in test/functional/wallet_taproot.py:467 in fec2019bdb outdated
     464 |          self.do_test_addr(comment, pattern, privmap, treefn, keys[0:nkeys])
     465 |          self.do_test_sendtoaddress(comment, pattern, privmap, treefn, keys[0:nkeys], keys[nkeys:2*nkeys])
     466 | -        self.do_test_psbt(comment, pattern, privmap, treefn, keys[2*nkeys:3*nkeys], keys[3*nkeys:4*nkeys])
     467 | +        self.do_test_psbt(comment, pattern, privmap, treefn, keys[2*nkeys:3*nkeys], keys[3*nkeys:4*nkeys], avoid_script_path=False)
     468 | +        if 'tr' in pattern:
     469 | +            self.do_test_psbt(comment, pattern, privmap, treefn, keys[4*nkeys:5*nkeys], keys[5*nkeys:6*nkeys], avoid_script_path=True)
    


    rkrux commented at 2:15 PM on June 8, 2026:

    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)
    
    

    Sjors commented at 3:15 PM on June 9, 2026:

    Taken with some tweaks for readability in 349462b7a97adc221fb2a1d6948f9197e4a1fef1.


    Sjors commented at 3:29 PM on June 9, 2026:

    Touching that file requires a rebase, so will do that now.

  82. rkrux commented at 2:16 PM on June 8, 2026: contributor

    The test reminded me of wallet_musig.py functional test that I believe can also be updated here because it works over walletprocesspsbt RPC.

  83. Sjors force-pushed on Jun 9, 2026
  84. wallet: add option to avoid script path spends fa971a09d5
  85. rpc: add keypath_only to walletprocesspsbt e6b5cef884
  86. test: cover keypath_only in wallet_taproot.py
    Expand taproot tests to cover avoid_script_path in  walletprocesspsbt.
    
    When avoiding script paths, there's no need for the workaround that increases fee_rate to compensate for the wallet's inability to estimate fees for script path spends. We use this to indirectly test that key path was used.
    
    We also check that taproot_script_path_sigs is not set.
    
    Finally, for transactions that can't be signed using their key path, we try again by allowing the script path.
    
    Additional test extended private keys were extracted from other tests.
    7ab4224ceb
  87. rpc: add keypath_only to send and sendall fa2d42e966
  88. rpc: add keypath_only to descriptorprocesspsbt 2d8d02d4da
  89. test: cover keypath_only in wallet_musig.py
    Extract the descriptor with both MuSig key and script paths into
    key_and_script_path_musigs. Reuse it for the existing cases and
    give those cases descriptions.
    
    Expand the same scenario with keypath_only=true. The new case asks
    walletprocesspsbt to avoid script-path signing.
    
    Co-authored-by: rkrux <rkrux.connect@gmail.com>
    af9ed2c680
  90. Sjors force-pushed on Jun 9, 2026
  91. Sjors commented at 3:45 PM on June 9, 2026: member

    Rebased after #33636, because the test I added in my previous push touches the same file. Also further simplified that test.

  92. DrahtBot added the label CI failed on Jun 9, 2026
  93. DrahtBot removed the label CI failed on Jun 10, 2026

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-06-13 21:31 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me