Skip to content

Deprecate wallet-owned signing APIs#505

Draft
noahjoeris wants to merge 2 commits into
bitcoindevkit:masterfrom
noahjoeris:feat/sign-psbt-migration
Draft

Deprecate wallet-owned signing APIs#505
noahjoeris wants to merge 2 commits into
bitcoindevkit:masterfrom
noahjoeris:feat/sign-psbt-migration

Conversation

@noahjoeris

@noahjoeris noahjoeris commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Description

Partially addresses #70

Deprecates wallet-owned signing APIs, migrating examples, tests, and documentation toward caller-owned keys using bitcoin::Psbt::sign and Wallet::sign_with_signers.

Depends on:

Notes to the reviewers

  • I migrated examples, docs and tests to use bitcoin::Psbt::sign where possible. And used Wallet::sign_with_signers if we need SignOptions.

Changelog notice

  • Deprecated Wallet::{add_signer, set_keymap, set_keymaps, get_signers, sign}, CreateParams::keymap, and LoadParams::{keymap, extract_keys} in favor of caller-owned keys and bitcoin::Psbt::sign and Wallet::sign_with_signers.
  • Deprecated FullyNodedExport::export_wallet; use FullyNodedExport::export_wallet_with_keymaps to supply keymaps explicitly.

Before submitting

@codecov

codecov Bot commented Jun 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.13%. Comparing base (58fe631) to head (c810938).
⚠️ Report is 12 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #505      +/-   ##
==========================================
+ Coverage   80.96%   81.13%   +0.16%     
==========================================
  Files          24       24              
  Lines        5489     5501      +12     
  Branches      247      247              
==========================================
+ Hits         4444     4463      +19     
+ Misses        968      958      -10     
- Partials       77       80       +3     
Flag Coverage Δ
rust 81.13% <100.00%> (+0.16%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@noahjoeris noahjoeris changed the title refactor: deprecate wallet-owned signing APIs Deprecate wallet-owned signing APIs Jun 23, 2026
@oleonardolima oleonardolima added this to the Wallet 3.2.0 milestone Jun 23, 2026
@oleonardolima oleonardolima moved this to In Progress in BDK Wallet Jun 23, 2026
@noahjoeris
noahjoeris force-pushed the feat/sign-psbt-migration branch 3 times, most recently from 44a49b6 to 769b782 Compare June 25, 2026 13:24
@thunderbiscuit thunderbiscuit mentioned this pull request Jun 26, 2026
4 tasks
@noahjoeris
noahjoeris force-pushed the feat/sign-psbt-migration branch from 769b782 to 8857be6 Compare June 26, 2026 11:20

@oleonardolima oleonardolima left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overall it's looking good, it's best if you fix the first commit and let the last one just adding the deprecation notice. let's us know when it's ready for final review.

Comment thread examples/electrum.rs Outdated
Comment thread tests/psbt.rs Outdated
Prefer bitcoin::Psbt::sign or Wallet::sign_with_signers in docs,
examples, and tests instead of relying on wallet-owned signer state.

Add FullyNodedExport::export_wallet_with_keymaps so private descriptor
material can be supplied explicitly during export.
Mark Wallet::sign, signer/keymap accessors, keymap load/create
helpers, and FullyNodedExport::export_wallet as deprecated.

The replacement path is to keep KeyMaps/Xprivs outside Wallet, use
bitcoin::Psbt::sign with wallet.secp_ctx(), or pass caller-owned
SignersContainers to Wallet::sign_with_signers when SignOptions are needed.
@noahjoeris
noahjoeris force-pushed the feat/sign-psbt-migration branch from 8857be6 to c810938 Compare July 1, 2026 08:17
@noahjoeris

Copy link
Copy Markdown
Contributor Author

Thanks for spotting this. It seems I added the change to the last commit and not the first, my bad. I cleaned up the commits.

@oleonardolima oleonardolima left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK c810938

@noahjoeris

noahjoeris commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

I still need to look into Wallet::policies and Wallet::create_tx and what to do with them. They also use self.signers

@noahjoeris

Copy link
Copy Markdown
Contributor Author

For Wallet::policies(), I suggest deprecating it and adding something like Wallet::policies_with_signers(keychain, signers).

One tricky part is TxBuilder::finish() -> Wallet::create_tx(). It currently extracts policies with the wallet signers.

A possible migration path is adding TxBuilder::policy(policy, keychain). Then callers that use policies_with_signers(...) can pass the resulting policy into the builder. Existing callers can keep the current fallback behavior of using wallet-owned signers during the deprecation window.

Downside: policy-path users get one more builder call, and Policy becomes more directly part of the API. Maybe that's acceptable with our intention of slowly moving away from TxBuilder.

@vera945

vera945 commented Jul 7, 2026

Copy link
Copy Markdown

Neither policies nor create_tx needs deprecation. Here's the reasoning:

create_tx calls extract_policy only to invoke requires_path() and get_condition(). Both methods operate entirely on the descriptor's structural tree — SatisfiableItem — and never read the contribution field, which is the only output that depends on the signers container. So passing SignersContainer::default() is valid without changing the behavior. This is verifiable by creating a wallet from xpub descriptors and calling build_tx normally.

policies similarly behaves this way for watch-only wallets. The contribution field will be Satisfaction::None for all leaves, which correctly describes a wallet that holds no signing keys. If a caller wants to evaluate what their external signing keys can contribute, the right answer is wallet.public_descriptor(keychain).extract_policy(their_signers, ...), which is already the pattern #505 is establishing.

@noahjoeris

Copy link
Copy Markdown
Contributor Author

No, passing empty signers won't work. It can create different Policy IDs, and policy_path relies on those IDs.

A path built from Wallet::policies() can fail when create_tx() re-extracts with empty signers, because get_condition() looks up selections by self.id.

@noahjoeris

noahjoeris commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

So after some discussion with @thunderbiscuit and @notmandatory we concluded that we cannot remove the signers fields unless we update TxBuilder to accept a spending policy to be passed in. If we don't want to update it (from what I heard) then the wallet signer removal is coupled to the TxBuilder removal. And it might make sense to deprecate both at the same time once we integrated create_psbt.

Comment thread examples/electrum.rs

let mut psbt = tx_builder.finish()?;
let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
psbt.sign(&signer, wallet.secp_ctx())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@noahjoeris Just curious, is there any reason we call secp from the wallet wallet.secp_ctx() instead of just creating one? Does wallet add anything special to Secp256k1 ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We simply reuse it to avoid initializing another one. nothing special is added, creating and using your own context is equivalent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

4 participants