Skip to content

Conversation

@Eunovo
Copy link
Contributor

@Eunovo Eunovo commented Jul 14, 2025

This PR is part of integrating silent payments into Bitcoin Core. Status and tracking for the project is managed in #28536
This PR is based on #28201 and will remain in draft until #28201 is merged.

This PR:

  • Adds a Silent Payments descriptor implemenation
  • Adds a SilentPaymentsDescriptorScriptPubKeyMan Impl that is a subclass of DescriptorScriptPubKeyMan
  • Implements Silent Payments scanning for the wallet
  • Updates sending logic to use silent-payments destination for change when sending to silent-payments destination
  • Adds unit and functional tests for silent payments-related functionality

Follow-ups

  • Silent Payments Label functionality is incomplete in this PR and will be added as a follow-up PR.

@DrahtBot
Copy link
Contributor

DrahtBot commented Jul 14, 2025

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

Code Coverage & Benchmarks

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

Reviews

See the guideline for information on the review process.
A summary of reviews will appear here.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #34075 (fees: Introduce Mempool Based Fee Estimation to reduce overestimation by ismaelsadeeq)
  • #33874 (wallet: refactor ProcessDescriptorImport by naiyoma)
  • #33112 (wallet: relax external_signer flag constraints by Sjors)
  • #33034 (wallet: Store transactions in a separate sqlite table by achow101)
  • #32861 (Have createwalletdescriptor auto-detect an unused(KEY) by Sjors)
  • #32763 (wallet: Replace CWalletTx::mapValue and vOrderForm with explicit class members by achow101)
  • #31974 (Drop testnet3 by Sjors)
  • #31260 (scripted-diff: Type-safe settings retrieval by ryanofsky)
  • #30214 (refactor: Improve assumeutxo state representation by ryanofsky)
  • #29136 (wallet: addhdkey RPC to add just keys to wallets via new unused(KEY) descriptor by achow101)
  • #28333 (wallet: Construct ScriptPubKeyMans with all data rather than loaded progressively by achow101)
  • #27865 (wallet: Track no-longer-spendable TXOs separately by achow101)
  • #27260 (Enhanced error messages for invalid network prefix during address parsing. by portlandhodl)

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.

@josibake josibake mentioned this pull request Jul 10, 2025
15 tasks
@DrahtBot
Copy link
Contributor

🚧 At least one of the CI tasks failed.
Task tidy: https://github.com/bitcoin/bitcoin/runs/45909076324
LLM reason (✨ experimental): The CI failure was caused by errors in clang-tidy checks, specifically in descriptor.cpp and walletutil.cpp, which are treated as failures due to warnings-as-errors settings.

Hints

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.

This was referenced Jul 14, 2025
@Sjors
Copy link
Member

Sjors commented Jul 14, 2025

Another thing I noticed while testing using the send RPC, in a wallet with only an sp() descriptor, is that it insists on having a bech32 descriptor for change:

Transaction needs a change address, but we can't generate it. Error: No bech32 addresses available.

It seems safer, for backups, to send change to the same silent payment address.

Wallet created by:

bitcoin rpc createwallet Silent blank=true silent_payments=true
bitcoin rpc importdescriptors '[{"desc": "sp(xprv...,xprv...)",  "timestamp": "now", "active": true]

Also looking forward to have labels back :-)

Copy link
Member

@josibake josibake left a comment

Choose a reason for hiding this comment

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

Did a big overview with @Sjors , leaving the notes from our discussion as a review. In general, I think we should investigate using a custom type for the scan key since a lot of the changes seem to be hacking around the fact we represent the scan key as a private key, but then often need to use it as not a private key.

Still in the process of reviewing, but leaving the initial notes for now

@@ -206,6 +206,8 @@ struct PubkeyProvider
/** Get the descriptor string form including private data (if available in arg). */
virtual bool ToPrivateString(const SigningProvider& arg, std::string& out) const = 0;

virtual std::optional<std::string> ToPrivateString(const CKey& key) const = 0;
Copy link
Member

Choose a reason for hiding this comment

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

While reviewing the PR, it seems a lot of things could be simplified by if we just treated the scan key as something that isn't a CKey, i.e., we introduce a completely new object for holding the scan key. I think that would allow us to drop this commit and simplify other places where we are trying to work around the fact that a scan key isnt really a private key.

I haven't thought this all the way through yet, but in my initial pass on the PR it seems like it should be possible.

Eunovo and others added 6 commits December 1, 2025 08:04
The scan key will be derived while the descriptor is parsed, so
we must pass the master xpriv into `GenerateWalletDescriptor`.

The spend key is expanded later so it is specified
as an xpub and path instead.
In future commits, a Silent Payment enabled wallet will write found SIlentPaymentOutputs to the DB.
Although the XOnlyPubKey can be derived from adding the Spend pubkey and the tweak,
we opt  to save the the found XOnlyPubKey because that removes the need for a CPubkey::TweakAdd() in the codebase
silent_payments wallet needs to scan entire blocks since it doesn't know ahead of time which scriptPubKeys to use in it's fast rescan filter.
@Eunovo Eunovo force-pushed the 2025-implement-bip352-receiving branch from 55485a6 to fcc8b88 Compare December 1, 2025 10:00
Eunovo and others added 12 commits December 1, 2025 11:08
traditionally, the receiving scripts are known to the core wallet
because they are added to the addressbook at the time they are requested.

in silent payments, the outputs are not known until found. its important, however,
to have the found scripts in the addressbook so all of the change accounting can be down
properly.

this commits adds found outputs to the address book if they are not change. the way
change is determined is a bit hacky in that we just check if the found output was
found with a label (since this is the only label currently implemented). in the future,
we should specifically check for a change specific label.
The wallet tries to match change OutputTpe to other outputs to preserve privacy.
Use silent payment change address when sending coins to:
- any silent payment address
- any taproot address
`CreateTransaction` fails if change_type is set to OutputType::SILENT_PAYMENTS
and there are no eligible inputs for the transaction. This commit modifies
`CreateTransaction` logic to make a second attempt to
create a tx without OutputType::SILENT_PAYMENTS change_type
This allows wallets with only sp descs to use sp change destination for transactions.
@DrahtBot
Copy link
Contributor

🐙 This pull request conflicts with the target branch and needs rebase.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants