{
 "number": 32857,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/32857",
 "title": "wallet: allow skipping script paths",
 "author": "Sjors",
 "author_association": "MEMBER",
 "created_at": "2025-07-02T14:13:31Z",
 "updated_at": "2026-09-17T11:08:58Z",
 "age_days": 442,
 "draft": false,
 "labels": [
  "Wallet"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "798522e0489dabe9c65845646375d42b11b6f1ed",
 "head_ref": "2025/07/no_script_path",
 "head_repo": "Sjors/bitcoin",
 "head_history": [
  {
   "t": "2025-07-02T16:44:43Z",
   "sha": "22013ba37dcc56b5aa44195f88e0dab858e2ce20"
  },
  {
   "t": "2025-07-02T18:30:57Z",
   "sha": "370081a481e52b10c9099c540fb0e9b50da4a983"
  },
  {
   "t": "2025-07-03T12:47:25Z",
   "sha": "1c4dfcb0ea078625b3ee5d00741bcdf422ce17a8"
  },
  {
   "t": "2025-07-03T13:55:33Z",
   "sha": "5542074a006371f98daa1bba3775e9c591d549e1"
  },
  {
   "t": "2025-07-04T13:45:44Z",
   "sha": "4c6a1c7e56152c9799ea1b9377d426e462a700c9"
  },
  {
   "t": "2025-07-04T16:02:39Z",
   "sha": "51928800f5e2fb85518890b934e8b049a6739821"
  },
  {
   "t": "2025-07-08T07:16:25Z",
   "sha": "b0a162fbb88b24cbab38cf01db3f18257a58aa8b"
  },
  {
   "t": "2025-07-08T11:30:36Z",
   "sha": "33eaf87e2f496fbe414454f23b73ddf01202f63f"
  },
  {
   "t": "2025-07-14T09:02:34Z",
   "sha": "50023a918e1e9b264bc1e3ad4234d04ceb07e992"
  },
  {
   "t": "2025-07-29T18:52:57Z",
   "sha": "db07d061f0cd942c042bad5167eb415bc6f73950"
  },
  {
   "t": "2025-10-16T07:09:23Z",
   "sha": "0e70253e3071897f7c3786ee749533baa163d08a"
  },
  {
   "t": "2025-11-04T09:19:42Z",
   "sha": "9b5ee077e7220c140d99ebee2d3b6cb5a0b7a9d7"
  },
  {
   "t": "2026-01-05T04:47:20Z",
   "sha": "afe5cfafa08a6bcce460315339868a03bb59bd62"
  },
  {
   "t": "2026-01-22T15:25:43Z",
   "sha": "bd3f2b7db6c57c61d3543ed07896681aad2cbbaa"
  },
  {
   "t": "2026-03-26T15:29:41Z",
   "sha": "e57e763ff42b85cccb1532b7f8d55609640934be"
  },
  {
   "t": "2026-04-22T08:36:17Z",
   "sha": "dc1711b842efeff4da416f3afad9e94297197efd"
  },
  {
   "t": "2026-04-30T09:45:05Z",
   "sha": "bd00f2b0da48b3cf1bce98567c8b02b00075170e"
  },
  {
   "t": "2026-05-01T10:43:27Z",
   "sha": "ad364249baebe9f75f24e32358d1f1f514c98f1d"
  },
  {
   "t": "2026-05-15T15:21:49Z",
   "sha": "8bd15fd779f8ac43c15f32d8b52a6439ec738d9f"
  },
  {
   "t": "2026-06-09T15:15:25Z",
   "sha": "349462b7a97adc221fb2a1d6948f9197e4a1fef1"
  },
  {
   "t": "2026-06-09T15:45:01Z",
   "sha": "af9ed2c68024178745318e5d9e17ce8e06180f31"
  },
  {
   "t": "2026-06-19T14:36:02Z",
   "sha": "7679d54952b635d2e41f07e3bbadcae6dee82f0c"
  },
  {
   "t": "2026-06-29T14:38:29Z",
   "sha": "707b6132af3713aa40dcda4a9a52c18d68e5e85f"
  },
  {
   "t": "2026-08-06T12:38:58Z",
   "sha": "dbdf524e480dbf43ea45cd2968ab4aba18133bb0"
  },
  {
   "t": "2026-08-17T12:23:24Z",
   "sha": "e730fc4c282876a085c56c28c69103d97772cf85"
  },
  {
   "t": "2026-08-19T12:30:44Z",
   "sha": "17c58d79c293a14d168e0a29d3b40336a4781d7c"
  },
  {
   "t": "2026-08-19T12:53:38Z",
   "sha": "c41bc0ee5b0157ee126257a0e748f60977a89958"
  },
  {
   "t": "2026-08-21T07:22:13Z",
   "sha": "425f08136000dcf640855388bbe5d558f80e614d"
  },
  {
   "t": "2026-08-21T08:40:55Z",
   "sha": "4f30b3b9f5dcfa5c05e889fd82b8517ab992e8ab"
  },
  {
   "t": "2026-08-24T13:53:48Z",
   "sha": "798522e0489dabe9c65845646375d42b11b6f1ed"
  }
 ],
 "additions": 243,
 "deletions": 27,
 "changed_files": 13,
 "commit_count": 9,
 "size_bucket": "M",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_ack": [
     {
      "login": "rkrux",
      "url": "https://github.com/bitcoin/bitcoin/pull/32857#pullrequestreview-4449901463"
     },
     {
      "login": "w0xlt",
      "url": "https://github.com/bitcoin/bitcoin/pull/32857#issuecomment-4701147471"
     }
    ],
    "stale_ack": [
     {
      "login": "jeanpablojp",
      "url": "https://github.com/bitcoin/bitcoin/pull/32857#pullrequestreview-4960355945"
     }
    ]
   },
   "conflicts": [
    {
     "number": 36257,
     "title": "qa: assert_equals -> assert_true/assert_false",
     "author": "hodlinator"
    },
    {
     "number": 35317,
     "title": "wallet: fix ignored subtract_fee_from_outputs option",
     "author": "stutxo"
    }
   ]
  }
 },
 "acks_parsed": {
  "rkrux": {
   "kind": "concept_ack",
   "hash": "8bd15fd779f8ac43c15f32d8b52a6439ec738d9f",
   "t": "2026-06-08T13:53:19Z",
   "stale": false
  },
  "w0xlt": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-06-14T08:11:50Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 2,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "dangervslash",
   "fanquake",
   "jeanpablojp",
   "rkrux",
   "w0xlt"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-08-24T13:54:02Z",
  "last_reviewer_activity": "2026-08-25T03:33:14Z",
  "last_reviewer": "dangervslash",
  "author_silent_days": 24,
  "waiting_on_author_days": 23,
  "days_since_update": 0
 },
 "refs": {
  "mentioned": [
   29136,
   29675,
   32876,
   32958,
   33636,
   34075,
   34697,
   35370,
   35504,
   35543,
   35619,
   35852
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 29675,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2025-10-14",
    "title": "wallet: Be able to receive and spend inputs involving MuSig2 aggregate keys"
   },
   {
    "number": 29136,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-05-14",
    "title": "wallet: `addhdkey` RPC to add just keys to wallets via new `unused(KEY)` descriptor"
   },
   {
    "number": 32876,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-04-29",
    "title": "refactor: use options struct for signing and PSBT operations"
   },
   {
    "number": 32958,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-08-20",
    "title": "wallet/refactor: Update SignPSBTInput to return util::Expected<void, PSBTError> and remove PSBTError:Ok"
   },
   {
    "number": 33636,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2025-12-23",
    "title": "wallet: Expand MuSig test coverage and follow-ups"
   },
   {
    "number": 34075,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-08-21",
    "title": "fees: Introduce Mempool Based Fee Estimation to reduce overestimation"
   },
   {
    "number": 34697,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-08-24",
    "title": "descriptor: fix musig() duplicate key checks and doubled PSBT origin paths"
   },
   {
    "number": 35370,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "rpc: add key-origin modes to PSBT processing RPCs"
   },
   {
    "number": 35504,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-06-15",
    "title": "test/doc: Follow-up nits for #35269"
   },
   {
    "number": 35543,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-06-26",
    "title": "test: introduce ExtendedPrivateKey and ExtendedPublicKey classes"
   },
   {
    "number": 35619,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "test:  ExtendedPrivateKey follow-ups"
   },
   {
    "number": 35852,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-08-14",
    "title": "scripted-diff: Use inline const(expr) over static constexpr in headers"
   }
  ],
  "conflicts": [
   36257,
   35317
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "src/common/types.h",
  "src/rpc/client.cpp",
  "src/script/sign.cpp",
  "src/script/sign.h",
  "src/wallet/rpc/spend.cpp",
  "test/functional/rpc_psbt.py",
  "test/functional/wallet_taproot.py"
 ],
 "body": "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 (and finalizing).\n\nFor 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.\n\nThis PR introduces a `keypath_only` option (default `false` for now) to the following RPC methods:\n- `send`\n- `sendall`\n- `walletcreatefundedpsbt`\n- `walletprocesspsbt`\n- `descriptorprocesspsbt`\n\nThe resulting PSBT won't _add_ `taproot_scripts` or `taproot_script_path_sigs`. It does still have `taproot_bip32_derivs` and `musig2_participant_pubkeys`.\n\nIt will not remove `taproot_scripts` from an existing PSBT, but it won't add a corresponding entry to `taproot_script_path_sigs`. We also won't finalize a PSBT without keypath spend, even with complete script paths. This protects against other participants accidentally including them.\n\nThe `wallet_taproot.py` tests are expanded to cover this behavior.\n\nIt can also be tested with https://github.com/Sjors/bitcoin/pull/91.",
 "commits": [
  {
   "sha": "3ac60775644be1a0f24f4fea69bec19957f8105c",
   "date": "2026-08-24T13:51:33Z",
   "message": "wallet: add option to avoid script path spends"
  },
  {
   "sha": "a8734b210199d72cad0cb368ca1e2d79f2365b57",
   "date": "2026-08-24T13:51:33Z",
   "message": "rpc: add keypath_only to walletprocesspsbt"
  },
  {
   "sha": "c8bfd5da8371e1b7281544134406136539d87a84",
   "date": "2026-08-24T13:51:33Z",
   "message": "test: cover keypath_only in wallet_taproot.py\n\nExpand taproot tests to cover avoid_script_path in  walletprocesspsbt.\n\nWhen 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.\n\nWe also check that taproot_script_path_sigs is not set.\n\nFinally, for transactions that can't be signed using their key path, we try again by allowing the script path.\n\nAdditional test extended private keys were extracted from other tests.\n\nCo-authored-by: rkrux <rkrux.connect@gmail.com>"
  },
  {
   "sha": "f6587dc376de75a65effc998fb5cbaafd070e727",
   "date": "2026-08-24T13:51:33Z",
   "message": "rpc: add keypath_only to send and sendall"
  },
  {
   "sha": "d4501d12f0806229f81173cf63956758b1537539",
   "date": "2026-08-24T13:51:33Z",
   "message": "rpc: add keypath_only to walletcreatefundedpsbt"
  },
  {
   "sha": "27aa32d46da46a7fbfbac0776eb707b651d4c945",
   "date": "2026-08-24T13:51:33Z",
   "message": "rpc: add keypath_only to descriptorprocesspsbt"
  },
  {
   "sha": "203e493f026d42396247522421958409e5b26354",
   "date": "2026-08-24T13:51:33Z",
   "message": "test: cover keypath_only in wallet_musig.py\n\nExtract the descriptor with both MuSig key and script paths into\nkey_and_script_path_musigs. Reuse it for the existing cases and\ngive those cases descriptions.\n\nExpand the same scenario with keypath_only=true. The new case asks\nwalletprocesspsbt to avoid script-path signing.\n\nCo-authored-by: rkrux <rkrux.connect@gmail.com>"
  },
  {
   "sha": "bad6f06a5c7d7b3f61484f2fcb1d25a1aa6806b8",
   "date": "2026-08-24T13:51:33Z",
   "message": "doc: add release note for keypath_only"
  },
  {
   "sha": "798522e0489dabe9c65845646375d42b11b6f1ed",
   "date": "2026-08-24T13:52:17Z",
   "message": "test: remove unused wallet_taproot init_wallet"
  }
 ],
 "timeline": [
  {
   "t": "2025-07-02T16:04:58Z",
   "kind": "comment",
   "who": "fanquake",
   "assoc": "MEMBER",
   "text": "Why is one of the native Windows jobs failing to compile: https://github.com/bitcoin/bitcoin/actions/runs/16027562790/job/45219347987?pr=32857#step:10:553, but not the other: https://github.com/bitcoin/bitcoin/actions/runs/16027562790/job/45219348012?pr=32857 ?"
  },
  {
   "t": "2025-07-02T16:35:47Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "@fanquake because it's in the fuzzer code, I incorrectly changed one of the function signatures there."
  },
  {
   "t": "2025-07-02T16:44:43Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "22013ba37dcc56b5aa44195f88e0dab858e2ce20"
  },
  {
   "t": "2025-07-02T16:53:37Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "From the original description:\n\n[quoted text omitted]\nI 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."
  },
  {
   "t": "2025-07-02T18:30:57Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "370081a481e52b10c9099c540fb0e9b50da4a983"
  },
  {
   "t": "2025-07-02T18:31:02Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "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...\n\nWell, it compiles and works. Thoughts on how to implement this elegantly?"
  },
  {
   "t": "2025-07-03T12:47:25Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "1c4dfcb0ea078625b3ee5d00741bcdf422ce17a8"
  },
  {
   "t": "2025-07-03T12:48:06Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "The `walletprocesspsbt` RPC now also has this option. Added test coverage by expanding `wallet_taproot.py`."
  },
  {
   "t": "2025-07-03T13:55:33Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "5542074a006371f98daa1bba3775e9c591d549e1"
  },
  {
   "t": "2025-07-03T14:01:34Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "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.\n\nI then did the same for `SignPSBTInput`, where I also think struct would be better.\n\nRinse and repeat for `::SignTransaction`.\n\nWill continue later to further split 09334ae0bd7939ed7476eb2b36f3bf8085885fe7. It might make sense to add a property to `BaseSignatureCreator` or it subclasses?"
  },
  {
   "t": "2025-07-04T13:45:44Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "4c6a1c7e56152c9799ea1b9377d426e462a700c9"
  },
  {
   "t": "2025-07-04T13:45:56Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "I opened #32876 and rebased this PR on top of it. That allowed me to drop 1486f05c8eded02d72690bf34d983a03e4ad748b + efc34a514b59cc1bab6e4d0f80c197481561c429."
  },
  {
   "t": "2025-07-04T16:02:39Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "51928800f5e2fb85518890b934e8b049a6739821"
  },
  {
   "t": "2025-07-04T16:02:42Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "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."
  },
  {
   "t": "2025-07-07T07:57:22Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "This may also be useful for Silent Payments, cc @josibake."
  },
  {
   "t": "2025-07-07T12:59:06Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "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 \ud83e\udd26 (there's currently no useful feedback when this happens)."
  },
  {
   "t": "2025-07-08T07:16:25Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "b0a162fbb88b24cbab38cf01db3f18257a58aa8b"
  },
  {
   "t": "2025-07-08T11:30:36Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "33eaf87e2f496fbe414454f23b73ddf01202f63f"
  },
  {
   "t": "2025-07-14T09:02:34Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "50023a918e1e9b264bc1e3ad4234d04ceb07e992"
  },
  {
   "t": "2025-07-29T18:52:57Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "db07d061f0cd942c042bad5167eb415bc6f73950"
  },
  {
   "t": "2025-08-25T11:51:26Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Holding off on rebasing until #32876 is merged or I have to touch it."
  },
  {
   "t": "2025-10-06T12:39:52Z",
   "kind": "comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\n**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.\n\nI 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."
  },
  {
   "t": "2025-10-06T12:42:43Z",
   "kind": "comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "text": "If #32876 is not garnering reviews, can consider undrafting this PR itself because it contains 7 commits only.\nAllowing skipping script path spending optionally seems reasonable to me and a ready-to-review PR is more inviting than a draft one."
  },
  {
   "t": "2025-10-07T08:10:55Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "@rkrux I'm not too worried about reviews just yet, let's focus on getting  https://github.com/bitcoin/bitcoin/pull/29675 in."
  },
  {
   "t": "2025-10-16T07:09:23Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "0e70253e3071897f7c3786ee749533baa163d08a"
  },
  {
   "t": "2025-11-04T09:19:42Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "9b5ee077e7220c140d99ebee2d3b6cb5a0b7a9d7"
  },
  {
   "t": "2026-01-05T04:47:20Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "afe5cfafa08a6bcce460315339868a03bb59bd62"
  },
  {
   "t": "2026-01-22T15:25:43Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "bd3f2b7db6c57c61d3543ed07896681aad2cbbaa"
  },
  {
   "t": "2026-03-26T15:29:41Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "e57e763ff42b85cccb1532b7f8d55609640934be"
  },
  {
   "t": "2026-04-22T08:36:17Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "dc1711b842efeff4da416f3afad9e94297197efd"
  },
  {
   "t": "2026-04-30T09:45:05Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "bd00f2b0da48b3cf1bce98567c8b02b00075170e"
  },
  {
   "t": "2026-04-30T09:45:28Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #32876 landed. I need to check a few more things before marking this as ready for review."
  },
  {
   "t": "2026-05-01T10:43:27Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "ad364249baebe9f75f24e32358d1f1f514c98f1d"
  },
  {
   "t": "2026-05-15T15:21:49Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "8bd15fd779f8ac43c15f32d8b52a6439ec738d9f"
  },
  {
   "t": "2026-05-15T15:22:00Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #29136 landed.\n\nAdded test coverage for the `send` RPC (ad364249baebe9f75f24e32358d1f1f514c98f1d -> 8bd15fd779f8ac43c15f32d8b52a6439ec738d9f)\n\nRedesigned ed89145afb12138b8e6664bc9acdda4772028115 _wallet: add option to avoid script path spends_ to pass `SignOptions` through `ProduceSignature` into `SignTaproot` (9bfdfaea2dbd62b8f86be90df18fb9cd61bac60f + f77a74743ececdf98dff9188c19f13c725b21801).\n\n`SignTaproot` now also clears `spenddata.scripts` when `avoid_script_path` is set."
  },
  {
   "t": "2026-06-08T13:25:58Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "src/rpc/client.cpp",
   "commit": "798522e0489dabe9c65845646375d42b11b6f1ed",
   "in_reply_to": null,
   "text": "In 52a5ace3718dae474ce09c1e06aa26293a4e82dc \"rpc: add keypath_only to walletprocesspsbt\"\n\ndescriptorprocesspsbt also does signing, it won't be far fetched to allow this option in that RPC too."
  },
  {
   "t": "2026-06-08T13:27:00Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "src/rpc/client.cpp",
   "commit": "798522e0489dabe9c65845646375d42b11b6f1ed",
   "in_reply_to": null,
   "text": "In 8bd15fd779f8ac43c15f32d8b52a6439ec738d9f \"rpc: add keypath_only to send\"\n\nFinishTransaction 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."
  },
  {
   "t": "2026-06-08T13:32:04Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "src/rpc/client.cpp",
   "commit": "798522e0489dabe9c65845646375d42b11b6f1ed",
   "in_reply_to": 3373545774,
   "text": "In 8bd15fd \"rpc: add keypath_only to send\"\n\nAlong 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."
  },
  {
   "t": "2026-06-08T13:53:19Z",
   "kind": "review",
   "who": "rkrux",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "8bd15fd779f8ac43c15f32d8b52a6439ec738d9f",
   "text": "Concept ACK 8bd15fd779f8ac43c15f32d8b52a6439ec738d9f\n\nSeems 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."
  },
  {
   "t": "2026-06-08T14:15:10Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "test/functional/wallet_taproot.py",
   "commit": "03541dff2424352b8e366c8deb25ed36190388e0",
   "in_reply_to": null,
   "text": "In fec2019bdb3f97482fba54a1a4540f9e4ec44efd \"test: cover keypath_only in wallet_taproot.py\"\n\nhttps://github.com/bitcoin/bitcoin/blob/5f33da9aa30ff80876f2f450b4370c446555bd71/test/functional/wallet_musig.py#L352\n\nThere'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.\n\nA 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.\n\n```diff\ndiff --git a/test/functional/wallet_musig.py b/test/functional/wallet_musig.py\nindex 0e3e4377c0..43c2de0436 100755\n--- a/test/functional/wallet_musig.py\n+++ b/test/functional/wallet_musig.py\n@@ -168,7 +168,7 @@ class WalletMuSigTest(BitcoinTestFramework):\n         assert \"musig2_pubnonces\" in dec[\"inputs\"][0]\n         assert \"musig2_partial_sigs\" not in dec[\"inputs\"][0]\n\n-    def test_success_case(self, comment, pattern, sighash_type=None, scriptpath=False, nosign_wallets=None, only_one_musig_wallet=False):\n+    def test_success_case(self, comment, pattern, sighash_type=None, scriptpath=None, nosign_wallets=None, only_one_musig_wallet=False, expected_pubnonces_partialsigs=None):\n         self.log.info(f\"Testing {comment}\")\n         has_internal = MULTIPATH_TWO_RE.search(pattern) is not None\n\n@@ -176,22 +176,26 @@ class WalletMuSigTest(BitcoinTestFramework):\n         wallets, keys = self.create_wallets_and_keys_from_pattern(pat)\n         self.construct_and_import_musig_descriptor_in_wallets(pat, wallets, keys, only_one_musig_wallet)\n\n-        expected_pubnonces = 0\n-        expected_partial_sigs = 0\n-        for musig in MUSIG_RE.findall(pat):\n-            musig_partial_sigs = 0\n-            for placeholder in PLACEHOLDER_RE.findall(musig):\n-                wallet_index = int(placeholder[1:])\n-                if nosign_wallets is None or wallet_index not in nosign_wallets:\n-                    expected_pubnonces += 1\n-                else:\n-                    musig_partial_sigs = None\n+        if expected_pubnonces_partialsigs != None:\n+            expected_pubnonces = expected_pubnonces_partialsigs['pubnonces']\n+            expected_partial_sigs = expected_pubnonces_partialsigs['partialsigs']\n+        else:\n+            expected_pubnonces = 0\n+            expected_partial_sigs = 0\n+            for musig in MUSIG_RE.findall(pat):\n+                musig_partial_sigs = 0\n+                for placeholder in PLACEHOLDER_RE.findall(musig):\n+                    wallet_index = int(placeholder[1:])\n+                    if nosign_wallets is None or wallet_index not in nosign_wallets:\n+                        expected_pubnonces += 1\n+                    else:\n+                        musig_partial_sigs = None\n+                    if musig_partial_sigs is not None:\n+                        musig_partial_sigs += 1\n+                    if wallet_index < len(wallets):\n+                        continue\n                 if musig_partial_sigs is not None:\n-                    musig_partial_sigs += 1\n-                if wallet_index < len(wallets):\n-                    continue\n-            if musig_partial_sigs is not None:\n-                expected_partial_sigs += musig_partial_sigs\n+                    expected_partial_sigs += musig_partial_sigs\n\n         # Check that the wallets agree on the same musig address\n         addr = None\n@@ -252,7 +256,10 @@ class WalletMuSigTest(BitcoinTestFramework):\n         for i, wallet in enumerate(wallets):\n             if nosign_wallets and i in nosign_wallets:\n                 continue\n-            proc = wallet.walletprocesspsbt(psbt=psbt, sighashtype=sighash_type)\n+            if scriptpath == None:\n+                proc = wallet.walletprocesspsbt(psbt=psbt, sighashtype=sighash_type)\n+            else:\n+                proc = wallet.walletprocesspsbt(psbt=psbt, sighashtype=sighash_type, keypath_only=not scriptpath)\n             assert_equal(proc[\"complete\"], False)\n             nonce_psbts.append(proc[\"psbt\"])\n\n@@ -280,7 +287,10 @@ class WalletMuSigTest(BitcoinTestFramework):\n         for i, wallet in enumerate(wallets):\n             if nosign_wallets and i in nosign_wallets:\n                 continue\n-            proc = wallet.walletprocesspsbt(psbt=comb_nonce_psbt, sighashtype=sighash_type)\n+            if scriptpath == None:\n+                proc = wallet.walletprocesspsbt(psbt=comb_nonce_psbt, sighashtype=sighash_type)\n+            else:\n+                proc = wallet.walletprocesspsbt(psbt=comb_nonce_psbt, sighashtype=sighash_type, keypath_only=not scriptpath)\n             assert_equal(proc[\"complete\"], False)\n             psig_psbts.append(proc[\"psbt\"])\n\n@@ -333,6 +343,7 @@ class WalletMuSigTest(BitcoinTestFramework):\n         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)\n         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/*)})\")\n         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])\n+        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})\n         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)\n         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)\n         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)\n\n```"
  },
  {
   "t": "2026-06-08T14:16:31Z",
   "kind": "review",
   "who": "rkrux",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "8bd15fd779f8ac43c15f32d8b52a6439ec738d9f",
   "text": "The test reminded me of wallet_musig.py functional test that I believe can also be updated here because it works over walletprocesspsbt RPC."
  },
  {
   "t": "2026-06-08T14:19:19Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/rpc/client.cpp",
   "commit": "798522e0489dabe9c65845646375d42b11b6f1ed",
   "in_reply_to": 3373545774,
   "text": "I'll add `sendall`, but I'm inclined leave the older `sendmany` and `sendtoaddress` alone. They also can't be used with external signers."
  },
  {
   "t": "2026-06-08T14:23:36Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "src/rpc/client.cpp",
   "commit": "798522e0489dabe9c65845646375d42b11b6f1ed",
   "in_reply_to": 3373545774,
   "text": "Oh, I didn't know they were older.\n\nSeems fine to me to not update them in this PR, they don't use the common internal signing/processing functions as well."
  },
  {
   "t": "2026-06-09T15:15:25Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "349462b7a97adc221fb2a1d6948f9197e4a1fef1"
  },
  {
   "t": "2026-06-09T15:15:25Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "test/functional/wallet_taproot.py",
   "commit": "03541dff2424352b8e366c8deb25ed36190388e0",
   "in_reply_to": 3373884121,
   "text": "Taken with some tweaks for readability in 349462b7a97adc221fb2a1d6948f9197e4a1fef1."
  },
  {
   "t": "2026-06-09T15:17:09Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/rpc/client.cpp",
   "commit": "798522e0489dabe9c65845646375d42b11b6f1ed",
   "in_reply_to": 3373538840,
   "text": "Done in 8d819f7d8e6e93b8132ae0e621ad39740a9493df."
  },
  {
   "t": "2026-06-09T15:29:25Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "test/functional/wallet_taproot.py",
   "commit": "03541dff2424352b8e366c8deb25ed36190388e0",
   "in_reply_to": 3373884121,
   "text": "Touching that file requires a rebase, so will do that now."
  },
  {
   "t": "2026-06-09T15:45:01Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "af9ed2c68024178745318e5d9e17ce8e06180f31"
  },
  {
   "t": "2026-06-09T15:45:05Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #33636, because the test I added in my previous push touches the same file. Also further simplified that test."
  },
  {
   "t": "2026-06-14T08:11:50Z",
   "kind": "comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "text": "Concept ACK"
  },
  {
   "t": "2026-06-15T10:59:02Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "test/functional/wallet_taproot.py",
   "commit": "03541dff2424352b8e366c8deb25ed36190388e0",
   "in_reply_to": 3373884121,
   "text": "[quoted text omitted]\n\nNice, the changes in the commit are cleaner than what I suggested."
  },
  {
   "t": "2026-06-15T11:00:35Z",
   "kind": "review",
   "who": "rkrux",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "af9ed2c68024178745318e5d9e17ce8e06180f31",
   "text": "I believe the changes in the multiple RPCs require a release note."
  },
  {
   "t": "2026-06-16T16:04:56Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "@rkrux pushed a release note commit."
  },
  {
   "t": "2026-06-19T12:19:28Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "test/functional/rpc_psbt.py",
   "commit": "798522e0489dabe9c65845646375d42b11b6f1ed",
   "in_reply_to": null,
   "text": "In 2d8d02d4da89b5e928dd7007365f31ab2f8f9761 \"rpc: add keypath_only to descriptorprocesspsbt\"\n\nFrom the PR description:\n[quoted text omitted]\n\nThe PR description is outdated?"
  },
  {
   "t": "2026-06-19T12:22:24Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "src/common/types.h",
   "commit": "fa971a09d5227d29aea57836d46538d6e11ea911",
   "in_reply_to": null,
   "text": "In fa971a09d5227d29aea57836d46538d6e11ea911 \"wallet: add option to avoid script path spends\"\n\nI am not seeing any benefit of having two kinds of naming for the same feature - keypath_only in the RPCs and avoid_script_path within the code.\n\nWould really prefer to have only one kind of naming, I'd let keypath_only stay."
  },
  {
   "t": "2026-06-19T12:25:00Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "src/common/types.h",
   "commit": "fa971a09d5227d29aea57836d46538d6e11ea911",
   "in_reply_to": null,
   "text": "In fa971a0 \"wallet: add option to avoid script path spends\"\n\nPSBTFillOptions is a more generic struct and not having taproot in the avoid_script_path name can be confusing for the uninitiated (though its present in the documentation comment). Maybe prefix it with `taproot_`?"
  },
  {
   "t": "2026-06-19T12:27:58Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "src/script/sign.h",
   "commit": "fa971a09d5227d29aea57836d46538d6e11ea911",
   "in_reply_to": null,
   "text": "In fa971a0 \"wallet: add option to avoid script path spends\"\n\nThere are 2 private and public sections each in the class. Is this intentional? Or can these be clubbed?"
  },
  {
   "t": "2026-06-19T12:28:55Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "src/script/sign.h",
   "commit": "798522e0489dabe9c65845646375d42b11b6f1ed",
   "in_reply_to": null,
   "text": "In fa971a0 \"wallet: add option to avoid script path spends\"\n\nSame taproot_ prefix suggestion for this generic SignOptions struct as well."
  },
  {
   "t": "2026-06-19T12:35:49Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/spend.cpp",
   "commit": "03541dff2424352b8e366c8deb25ed36190388e0",
   "in_reply_to": null,
   "text": "In multiple commits:\n\nThe false default for all this option in all the affected RPCs can be a wallet constant named DEFAULT_SIGN_TAPROOT_KEYPATH_ONLY.  It needs to be in the wallet namespace, either in this file wallet/rpc/spend.cpp where its used almost exclusively, or in the wallet/wallet.h file where other defaults also are (not my preference though)."
  },
  {
   "t": "2026-06-19T12:41:03Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/spend.cpp",
   "commit": "e6b5cef884b9b728954b4e3d3a483b5d41132066",
   "in_reply_to": null,
   "text": "In e6b5cef884b9b728954b4e3d3a483b5d41132066 \"rpc: add keypath_only to walletprocesspsbt\"\n\nRelated to an earlier suggestion, seeing this double naming together seems unnecessary to me."
  },
  {
   "t": "2026-06-19T12:48:48Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "test/functional/wallet_taproot.py",
   "commit": "7679d54952b635d2e41f07e3bbadcae6dee82f0c",
   "in_reply_to": null,
   "text": "From the comment few lines above:\n\n[quoted text omitted]\n1. Where were these xprvs and xpubs gotten from?\n2. Do the 4 pubs here correspond to m/0, m/1, m/2, m/3 respectively?\n\nI don't prefer to have hardcoded extended keys that are created via some outside implementation in the testing framework because it clutters the testing code, is not self documenting, and makes the tests difficult to update - that's why I raised #35543 recently.\n\nIf it gets merged before this PR (this one doesn't need to be dependent on it), it'd be really nice to use the ExtendedPrivate(|Public)Key class(es) from there so that we can have programmatic test cases generation that would make these tests self-documenting."
  },
  {
   "t": "2026-06-19T12:49:40Z",
   "kind": "review",
   "who": "rkrux",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "03541dff2424352b8e366c8deb25ed36190388e0",
   "text": "Code review 03541dff2424352b8e366c8deb25ed36190388e0\n\nI'm reviewing the wallet_taproot changes at the moment. I've shared the points that I have till now.\n\nAlso the PR description can be updated to mention the remaining changed RPCs."
  },
  {
   "t": "2026-06-19T13:24:14Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/common/types.h",
   "commit": "fa971a09d5227d29aea57836d46538d6e11ea911",
   "in_reply_to": 3442443271,
   "text": "Good point, I'll switch over to `keypath_only`."
  },
  {
   "t": "2026-06-19T13:29:14Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "test/functional/rpc_psbt.py",
   "commit": "798522e0489dabe9c65845646375d42b11b6f1ed",
   "in_reply_to": 3442425436,
   "text": "When the fields are present, we should not sign them, that was already correct. When the fields are absent, we should not add them. This prevents other signers from accidentally signing them (or get confused by them, as I found with earlier Ledger firmware).\n\n(update: it worked correctly, but PR description was wrong)\n\nI also added some code comments."
  },
  {
   "t": "2026-06-19T13:54:20Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/spend.cpp",
   "commit": "03541dff2424352b8e366c8deb25ed36190388e0",
   "in_reply_to": 3442502617,
   "text": "I'll move it to `wallet/wallet.h` since one day the GUI might have a similar toggle.\n\n`descriptorprocesspsbt` keeps a hardcoded `{false}`, since it doesn't include the wallet.\n\nUltimately it doesn't matter that much, because changing the default would be a breaking change for older RPC clients, so it seems unlikely to happen."
  },
  {
   "t": "2026-06-19T14:00:53Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "test/functional/wallet_taproot.py",
   "commit": "7679d54952b635d2e41f07e3bbadcae6dee82f0c",
   "in_reply_to": 3442568953,
   "text": "1. Lifted from various other tests. Happy to rebase after #35543 and get them from a more canonical source.\n2. I believe so, yes."
  },
  {
   "t": "2026-06-19T14:01:48Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/script/sign.h",
   "commit": "fa971a09d5227d29aea57836d46538d6e11ea911",
   "in_reply_to": 3442468371,
   "text": "It is, but it's ugly. I'm adding a `TaprootKeypathOnly()` helper so we can keep `m_options` private and drop the annotations."
  },
  {
   "t": "2026-06-19T14:18:05Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/spend.cpp",
   "commit": "e6b5cef884b9b728954b4e3d3a483b5d41132066",
   "in_reply_to": null,
   "text": "In e6b5cef \"rpc: add keypath_only to walletprocesspsbt\"\n\nThis point is specific to walletprocesspsbt RPC only because all the 3 other affected RPCs don't provide an option to not sign.\n\nHaving both sign and keypath_only booleans might be confusing for the end user as the latter is a form of former. I was reviewing #35370 and noticed multiple overlapping boolean RPC options over there and believe the same point is applicable here as well (to some extent).\n\nOne way could be to make this sign option an enum (ALL, NONE, KEYPATH_ONLY), though that would be a breaking change for the end users. An alternative could be to add a condition in the code that sign needs to be true if keypath_only is passed true because keypath_only:true with sign:false is conflicting.\n\nIdeally I prefer the enum approach because it allows us to have fewer RPC arguments but given that it'd be a breaking change and only one RPC needs to be updated at the moment, I'm inclining towards the latter.\n\nWDYT?"
  },
  {
   "t": "2026-06-19T14:19:51Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/script/sign.h",
   "commit": "fa971a09d5227d29aea57836d46538d6e11ea911",
   "in_reply_to": 3442468371,
   "text": "On second thought, exposing `Options()` seems generic."
  },
  {
   "t": "2026-06-19T14:23:29Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/spend.cpp",
   "commit": "e6b5cef884b9b728954b4e3d3a483b5d41132066",
   "in_reply_to": 3443033699,
   "text": "I think it's better to keep similar RPC methods consistent, even if it's a bit awkward for one of them."
  },
  {
   "t": "2026-06-19T14:36:02Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "7679d54952b635d2e41f07e3bbadcae6dee82f0c"
  },
  {
   "t": "2026-06-19T14:36:05Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Addressed feedback from @rkrux. Most importantly:\n- added `Options()` to `BaseSignatureCreator` to avoid having to make `m_options` public. See https://github.com/bitcoin/bitcoin/pull/32857#discussion_r3442943643\n\nClarified in PR description as well code comments that we don't _add_  new `taproot_scripts`. We also  don't _remove_ exiting ones, but don't _sign_ them. See https://github.com/bitcoin/bitcoin/pull/32857#discussion_r3442425436\n\nRebased just in case after #35504."
  },
  {
   "t": "2026-06-27T07:44:15Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "test/functional/wallet_taproot.py",
   "commit": "7679d54952b635d2e41f07e3bbadcae6dee82f0c",
   "in_reply_to": 3442568953,
   "text": "PR #35543 is merged now, only the following change would be required now I believe:\n\n```diff\ndiff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py\nindex b312d4e153..89d45f0ca5 100755\n--- a/test/functional/wallet_taproot.py\n+++ b/test/functional/wallet_taproot.py\n@@ -256,7 +256,7 @@ class WalletTaprootTest(BitcoinTestFramework):\n         self.do_test_psbt(comment, pattern, privmap, treefn, keys[2*nkeys:3*nkeys], keys[3*nkeys:4*nkeys])\n\n     def generate_test_keys(self):\n-        xprvs = [ExtendedPrivateKey.generate() for _ in range(0, 13)]\n+        xprvs = [ExtendedPrivateKey.generate() for _ in range(0, 18)]\n         return [{\n             \"xprv\": xprv.to_string(),\n             \"xpub\": xprv.pubkey().to_string(),\n```"
  },
  {
   "t": "2026-06-27T09:08:22Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "test/functional/wallet_taproot.py",
   "commit": "7679d54952b635d2e41f07e3bbadcae6dee82f0c",
   "in_reply_to": null,
   "text": "It's not related to this PR but I noticed this dead code while reviewing. It can be removed here because this file is being touched, I'm not sure if raising a separate PR only for this would be worth a whole review & merge process.\n\n```diff\n--- a/test/functional/wallet_taproot.py\n+++ b/test/functional/wallet_taproot.py\n@@ -64,9 +64,6 @@ class WalletTaprootTest(BitcoinTestFramework):\n     def setup_network(self):\n         self.setup_nodes()\n\n-    def init_wallet(self, *, node):\n-        pass\n-\n     @staticmethod\n     def make_desc(pattern, privmap, keys, pub_only = False):\n         pat = pattern.replace(\"$H\", H_POINT)\n```"
  },
  {
   "t": "2026-06-29T14:19:45Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "test/functional/wallet_taproot.py",
   "commit": "7679d54952b635d2e41f07e3bbadcae6dee82f0c",
   "in_reply_to": 3485731084,
   "text": "@rkrux I'll add a commit here, but it's probably worth its own PR, because it might sit here for a while otherwise."
  },
  {
   "t": "2026-06-29T14:30:08Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "test/functional/wallet_taproot.py",
   "commit": "7679d54952b635d2e41f07e3bbadcae6dee82f0c",
   "in_reply_to": 3485731084,
   "text": "I see, I can raise a separate PR for it then."
  },
  {
   "t": "2026-06-29T14:35:29Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "test/functional/wallet_taproot.py",
   "commit": "7679d54952b635d2e41f07e3bbadcae6dee82f0c",
   "in_reply_to": 3485731084,
   "text": "#35619"
  },
  {
   "t": "2026-06-29T14:38:29Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "707b6132af3713aa40dcda4a9a52c18d68e5e85f"
  },
  {
   "t": "2026-06-29T14:38:35Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #35543 and took advantage of it in the test, see https://github.com/bitcoin/bitcoin/pull/32857#discussion_r3485600298.\n\nAlso added the minor test cleanup suggested in https://github.com/bitcoin/bitcoin/pull/32857#discussion_r3485731084."
  },
  {
   "t": "2026-06-29T14:38:51Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "test/functional/wallet_taproot.py",
   "commit": "7679d54952b635d2e41f07e3bbadcae6dee82f0c",
   "in_reply_to": 3442568953,
   "text": "Done!"
  },
  {
   "t": "2026-08-06T12:38:58Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "dbdf524e480dbf43ea45cd2968ab4aba18133bb0"
  },
  {
   "t": "2026-08-17T12:23:24Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "e730fc4c282876a085c56c28c69103d97772cf85"
  },
  {
   "t": "2026-08-17T12:23:25Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #35852."
  },
  {
   "t": "2026-08-18T11:13:57Z",
   "kind": "review",
   "who": "jeanpablojp",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "e730fc4c282876a085c56c28c69103d97772cf85",
   "text": "tACK e730fc4c282876a085c56c28c69103d97772cf85.\n\nRan the 3 tests this PR touches, all pass. Skipping the fallback script path in the normal flow makes sense. Key path signing still works with the tweak, and script path fields already in the PSBT are left untouched."
  },
  {
   "t": "2026-08-18T11:13:57Z",
   "kind": "review_comment",
   "who": "jeanpablojp",
   "assoc": "CONTRIBUTOR",
   "path": "src/script/sign.cpp",
   "commit": "798522e0489dabe9c65845646375d42b11b6f1ed",
   "in_reply_to": null,
   "text": "This return also blocks finalizing via script path with signatures already in the PSBT, not just signing new ones. With `keypath_only=true` and `finalize=true`, such a PSBT comes back `complete=false`. With the flag off it finalizes, and `finalizepsbt` afterwards also works. Probably a rare case, feel free to ignore."
  },
  {
   "t": "2026-08-18T11:13:57Z",
   "kind": "review_comment",
   "who": "jeanpablojp",
   "assoc": "CONTRIBUTOR",
   "path": "src/wallet/rpc/spend.cpp",
   "commit": "798522e0489dabe9c65845646375d42b11b6f1ed",
   "in_reply_to": null,
   "text": "Small note. This list is shared with fundrawtransaction and walletcreatefundedpsbt, which never sign, so both now accept keypath_only with no effect (before, they rejected it). Intentional?"
  },
  {
   "t": "2026-08-19T12:30:44Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "17c58d79c293a14d168e0a29d3b40336a4781d7c"
  },
  {
   "t": "2026-08-19T12:30:49Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/spend.cpp",
   "commit": "798522e0489dabe9c65845646375d42b11b6f1ed",
   "in_reply_to": 3803512956,
   "text": "I ended up adding support to `walletcreatefundedpsbt`, rather than suppressing the argument.\n\n`fundrawtransaction` now throws if you set it (a legacy method that I prefer to leave alone)"
  },
  {
   "t": "2026-08-19T12:32:14Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/script/sign.cpp",
   "commit": "798522e0489dabe9c65845646375d42b11b6f1ed",
   "in_reply_to": 3803512951,
   "text": "Clarified the documentation and added test coverage.\n\nI see `keypath_only=true` as a privacy / safety feature, so this behavior seems correct, even if surprising.\n\nI looked into having the RPC emit a warning, and also enhance `analyzepsbt`, but that's quite involved: https://github.com/Sjors/bitcoin/commits/2026/08/taproot-spend-path-warning/"
  },
  {
   "t": "2026-08-19T12:53:38Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "c41bc0ee5b0157ee126257a0e748f60977a89958"
  },
  {
   "t": "2026-08-21T07:22:13Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "425f08136000dcf640855388bbe5d558f80e614d"
  },
  {
   "t": "2026-08-21T07:22:15Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #32958."
  },
  {
   "t": "2026-08-21T08:40:55Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "4f30b3b9f5dcfa5c05e889fd82b8517ab992e8ab"
  },
  {
   "t": "2026-08-21T08:41:04Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #34075."
  },
  {
   "t": "2026-08-24T13:53:48Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "798522e0489dabe9c65845646375d42b11b6f1ed"
  },
  {
   "t": "2026-08-24T13:54:02Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #34697"
  },
  {
   "t": "2026-08-25T03:33:14Z",
   "kind": "comment",
   "who": "dangervslash",
   "assoc": "NONE",
   "text": "Resolved"
  }
 ],
 "labels_log": [
  {
   "t": "2025-07-02T14:13:34Z",
   "action": "labeled",
   "label": "Wallet",
   "who": "DrahtBot"
  },
  {
   "t": "2025-07-02T15:53:10Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-07-03T18:18:59Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-07-07T21:18:24Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2025-07-08T08:19:20Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2025-07-29T18:24:34Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2025-07-29T20:48:45Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2025-08-19T11:24:20Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2025-10-16T07:31:10Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2025-11-18T22:59:05Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-01-05T05:40:17Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-01-22T17:48:11Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-03-25T22:05:25Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-03-26T16:16:22Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-03-26T17:34:58Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-19T10:10:47Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-22T09:26:39Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-23T06:14:19Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-29T15:26:40Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-30T10:52:55Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-30T11:08:27Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-09T21:45:45Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-10T15:26:27Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-19T15:49:14Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-26T11:58:08Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-26T23:15:41Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-29T15:38:58Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-14T17:54:46Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-17T16:39:23Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-19T12:54:37Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-19T14:23:36Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-20T21:38:33Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-21T08:43:34Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-24T11:34:25Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-24T15:57:26Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  }
 ],
 "state_log": [
  {
   "t": "2026-05-15T15:36:54Z",
   "kind": "ready_for_review",
   "who": "Sjors"
  }
 ],
 "text_chars": 24526,
 "text_tokens_estimate": 6131,
 "changed_paths": [
  "doc/release-notes-32857.md",
  "src/common/types.h",
  "src/psbt.cpp",
  "src/rpc/client.cpp",
  "src/rpc/rawtransaction.cpp",
  "src/script/sign.cpp",
  "src/script/sign.h",
  "src/wallet/rpc/spend.cpp",
  "src/wallet/wallet.h",
  "test/functional/rpc_psbt.py",
  "test/functional/wallet_fundrawtransaction.py",
  "test/functional/wallet_musig.py",
  "test/functional/wallet_taproot.py"
 ],
 "files": [
  {
   "path": "doc/release-notes-32857.md",
   "add": 8,
   "del": 0
  },
  {
   "path": "src/common/types.h",
   "add": 6,
   "del": 0
  },
  {
   "path": "src/psbt.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/rpc/client.cpp",
   "add": 5,
   "del": 0
  },
  {
   "path": "src/rpc/rawtransaction.cpp",
   "add": 17,
   "del": 4
  },
  {
   "path": "src/script/sign.cpp",
   "add": 8,
   "del": 0
  },
  {
   "path": "src/script/sign.h",
   "add": 3,
   "del": 0
  },
  {
   "path": "src/wallet/rpc/spend.cpp",
   "add": 17,
   "del": 4
  },
  {
   "path": "src/wallet/wallet.h",
   "add": 1,
   "del": 0
  },
  {
   "path": "test/functional/rpc_psbt.py",
   "add": 69,
   "del": 0
  },
  {
   "path": "test/functional/wallet_fundrawtransaction.py",
   "add": 2,
   "del": 0
  },
  {
   "path": "test/functional/wallet_musig.py",
   "add": 32,
   "del": 5
  },
  {
   "path": "test/functional/wallet_taproot.py",
   "add": 74,
   "del": 13
  }
 ],
 "test_lines": 195,
 "git": {
  "head": "798522e0489dabe9c65845646375d42b11b6f1ed",
  "head_matches_backup": true,
  "base": "994c17d6c0a1453a1d7cc44ee2bbc49afa2d1155",
  "commits": [
   {
    "sha": "3ac6077564",
    "subject": "wallet: add option to avoid script path spends",
    "files": 5,
    "add": 19,
    "del": 1
   },
   {
    "sha": "a8734b2101",
    "subject": "rpc: add keypath_only to walletprocesspsbt",
    "files": 2,
    "add": 5,
    "del": 1
   },
   {
    "sha": "c8bfd5da83",
    "subject": "test: cover keypath_only in wallet_taproot.py",
    "files": 1,
    "add": 28,
    "del": 10
   },
   {
    "sha": "f6587dc376",
    "subject": "rpc: add keypath_only to send and sendall",
    "files": 4,
    "add": 49,
    "del": 2
   },
   {
    "sha": "d4501d12f0",
    "subject": "rpc: add keypath_only to walletcreatefundedpsbt",
    "files": 3,
    "add": 16,
    "del": 2
   },
   {
    "sha": "27aa32d46d",
    "subject": "rpc: add keypath_only to descriptorprocesspsbt",
    "files": 3,
    "add": 87,
    "del": 4
   },
   {
    "sha": "203e493f02",
    "subject": "test: cover keypath_only in wallet_musig.py",
    "files": 1,
    "add": 32,
    "del": 5
   },
   {
    "sha": "bad6f06a5c",
    "subject": "doc: add release note for keypath_only",
    "files": 1,
    "add": 8,
    "del": 0
   },
   {
    "sha": "798522e048",
    "subject": "test: remove unused wallet_taproot init_wallet",
    "files": 1,
    "add": 0,
    "del": 3
   }
  ],
  "patch_truncated": false
 },
 "input_hash": "10aac1e62b432a9e",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}