Skip to content

wallet: Add deriveHDKey interface - #36070

Open
PraneethGunas wants to merge 3 commits into
bitcoin:masterfrom
PraneethGunas:derivehdkey-interface
Open

wallet: Add deriveHDKey interface#36070
PraneethGunas wants to merge 3 commits into
bitcoin:masterfrom
PraneethGunas:derivehdkey-interface

Conversation

@PraneethGunas

Copy link
Copy Markdown

This PR adds a wallet interface for derivehdkey.

The motivation is the same as #35436 and #34861. The derivehdkey RPC exists (#32784), but the GUI does not go through RPC, so the logic is currently out of its reach. A dedicated wallet interface makes it available for multisig setup. Alongside the addhdkey interface, this lets the GUI add an HD key and derive a shareable xpub from it. Tracked as the deriveHDKey item in #35645.

Key changes:

  • Move the HD key selection logic from the derivehdkey RPC into CWallet::SelectHDKey().
  • Update derivehdkey RPC to call CWallet::SelectHDKey(), keeping its argument parsing, guards and error codes in the RPC.
  • Return util::Expected<CExtKey, WalletError> from CWallet::SelectHDKey(), using WalletErrorCode::UnlockNeeded for a locked wallet so callers can prompt for a passphrase and retry.
  • Add CWallet::DeriveHDKey(), which selects the HD key and derives it at the requested path.
  • Add interfaces::Wallet::deriveHDKey(), which returns the derived xpub and its key origin. Private key material does not cross the interface.
  • Add unit test coverage for interfaces::Wallet::deriveHDKey().

@DrahtBot DrahtBot changed the title wallet: Add deriveHDKey interface wallet: Add deriveHDKey interface Aug 24, 2026
@DrahtBot

DrahtBot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

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/36070.

Reviews

See the guideline and AI policy for information on the review process.

Type Reviewers
Concept ACK polespinasa, jeanpablojp

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

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #36126 (wallet, rpc: Implements set key label functionality by polespinasa)
  • #36087 (util: Add and use AssertUnreachable by maflcko)
  • #36074 (scripted-diff: [test] Add util/check.h includes for assertions by maflcko)
  • #35998 (wallet: Handle or explicitly ignore WalletBatch write failures by achow101)
  • #35786 (wallet: drop spent parents redundant cache invalidation and notification by furszy)
  • #35752 (wallet: make encryption state updates atomic by l0rinc)
  • #35436 (wallet: Add addHDkey interface by pseudoramdom)
  • #34681 (wallet: move rescan logic into ChainScanner and wallet/scan by Eunovo)
  • #29278 (Wallet: Add maxfeerate wallet startup option by ismaelsadeeq)

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.

@polespinasa

polespinasa commented Aug 25, 2026

Copy link
Copy Markdown
Member

concept ACK

will review soon :)

@jeanpablojp jeanpablojp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Concept ACK

Left some comments.

Comment thread src/wallet/test/wallet_interfaces_tests.cpp Outdated
Comment thread src/wallet/rpc/wallet.cpp Outdated

@polespinasa polespinasa left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

did a first swift review

Comment thread src/wallet/rpc/wallet.cpp Outdated
Comment thread src/wallet/wallet.h Outdated
Comment thread src/wallet/wallet.cpp
return *xprv;
}

util::Expected<std::pair<CExtKey, KeyOriginInfo>, WalletError> CWallet::DeriveHDKey(const std::vector<uint32_t>& path, const std::optional<CExtPubKey>& hdkey) const

@polespinasa polespinasa Aug 28, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

in a1250d2 wallet: Add deriveHDKey interface

All this is duplicated from RPC code. Why not just make both the interface and the RPC rely on the same code? Because of both using different code functions, they both return different error codes for same errors.

Also probably this commit could be split in different commits. First a preparatory commit that creates the DeriveHDKey function + testing, then a commit rebasing the RPC to use it, then a commit creating the interface. You can check #34861 for a commit structure idea :)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done. Split into "Add CWallet::DeriveHDKey" and "Add deriveHDKey interface".

On sharing code with the RPC: it already calls SelectHDKey(). What's left is the watch-only, hardened-path and unlock guards, which pin the error codes wallet_derivehdkey.py asserts (-4, -8, -13).

DeriveHDKey() returns GenericError for every failure, so routing the rest through it would turn "Unable to derive HD key at the requested path" from -8 into -5. Keeping -8 would need a new WalletErrorCode just so one caller can pick a different number, which src/wallet/types.h:48-50 warns against.

The GUI will need to select an HD key without going through the RPC, so move
the selection out of derivehdkey into CWallet::SelectHDKey.

It returns a WalletError so that a caller can tell a locked wallet apart from
the other failures. The RPC checks for a locked wallet before calling it, so
everything it gets back maps to RPC_INVALID_ADDRESS_OR_KEY.

@jeanpablojp jeanpablojp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed again. Left one more comment on the new test.

Comment thread src/wallet/test/wallet_tests.cpp Outdated
@DrahtBot

DrahtBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

🚧 At least one of the CI tasks failed.
Task iwyu: https://github.com/bitcoin/bitcoin/actions/runs/33223334574/job/99831020528
LLM reason (✨ experimental): CI failed because the IWYU (include-what-you-use) check reported include issues and intentionally exited with a failure.

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.

Requiring a hardened step means the parent xpub cannot be used to work out the
sibling keys.
Only the xpub is returned. interfaces::Wallet is not authenticated, so private
keys should not be passed over it.
@hebasto

hebasto commented Sep 2, 2026

Copy link
Copy Markdown
Member

From https://github.com/bitcoin/bitcoin/actions/runs/33532997440/job/100190403622?pr=36070:

--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -34,19 +34,16 @@
 #include <vector>
 
 class ArgsManager;
-class CKeyID;
-class CPubKey;
 class CScript;
 class PartiallySignedTransaction;
 class uint256;
 enum class FeeReason;
 enum class OutputType;
 struct bilingual_str;
+
 namespace wallet {
-struct CreatedTransactionResult;
 class CCoinControl;
 class CWallet;
-enum class AddressPurpose;
 struct CRecipient;
 struct WalletContext;
 } // namespace wallet

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