wallet: Move listdescriptors retrieving from RPC to CWallet
What changed, and why it matters
This commit is a straightforward internal code cleanup: it moves the logic for listing wallet descriptors from the RPC command code into a reusable wallet helper function. There is no user-facing behavior change, no bug fix, and no security-relevant change visible in the diff.
No security action required. Review as normal code-quality refactor if desired.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change refactors listdescriptors by extracting descriptor collection into a new ExportDescriptors() function in newly created src/wallet/export.cpp/export.h. The RPC handler now calls this helper. The helper uses Assume() instead of CHECK_NONFATAL() for GetDescriptorString, and returns an Expected error rather than throwing directly. These are minor implementation differences, but the overall operation, inputs, outputs, and locking (cs_wallet, cs_desc_man) remain the same.
Changed components
src/wallet/rpc/backup.cppsrc/wallet/export.cppsrc/wallet/export.hsrc/wallet/wallet.hsrc/wallet/CMakeLists.txtInspect captured patch +78 / −31
diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt
index 36fd3ef9..040569f7 100644
--- a/src/wallet/CMakeLists.txt
+++ b/src/wallet/CMakeLists.txt
@@ -10,6 +10,7 @@ add_library(bitcoin_wallet STATIC EXCLUDE_FROM_ALL
crypter.cpp
db.cpp
dump.cpp
+ export.cpp
external_signer_scriptpubkeyman.cpp
feebumper.cpp
fees.cpp
diff --git a/src/wallet/export.cpp b/src/wallet/export.cpp
new file mode 100644
index 00000000..9c042d3b
--- /dev/null
+++ b/src/wallet/export.cpp
@@ -0,0 +1,39 @@
+// Copyright (c) 2026-present The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or https://www.opensource.org/licenses/mit-license.php.
+
+#include <wallet/export.h>
+
+#include <util/expected.h>
+#include <wallet/scriptpubkeyman.h>
+#include <wallet/wallet.h>
+
+namespace wallet {
+util::Expected<std::vector<WalletDescInfo>, std::string> ExportDescriptors(const CWallet& wallet, bool export_private)
+{
+ AssertLockHeld(wallet.cs_wallet);
+ std::vector<WalletDescInfo> wallet_descriptors;
+ for (const auto& spk_man : wallet.GetAllScriptPubKeyMans()) {
+ const auto desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man);
+ if (!desc_spk_man) {
+ return util::Unexpected{"Unexpected ScriptPubKey manager type."};
+ }
+ LOCK(desc_spk_man->cs_desc_man);
+ const auto& wallet_descriptor = desc_spk_man->GetWalletDescriptor();
+ std::string descriptor;
+ if (!Assume(desc_spk_man->GetDescriptorString(descriptor, export_private))) {
+ return util::Unexpected{"Can't get descriptor string."};
+ }
+ const bool is_range = wallet_descriptor.descriptor->IsRange();
+ wallet_descriptors.emplace_back(
+ descriptor,
+ wallet_descriptor.creation_time,
+ wallet.IsActiveScriptPubKeyMan(*desc_spk_man),
+ wallet.IsInternalScriptPubKeyMan(desc_spk_man),
+ is_range ? std::optional(std::make_pair(wallet_descriptor.range_start, wallet_descriptor.range_end)) : std::nullopt,
+ wallet_descriptor.next_index
+ );
+ }
+ return wallet_descriptors;
+}
+} // namespace wallet
diff --git a/src/wallet/export.h b/src/wallet/export.h
new file mode 100644
index 00000000..d83600be
--- /dev/null
+++ b/src/wallet/export.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2026-present The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or https://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_WALLET_EXPORT_H
+#define BITCOIN_WALLET_EXPORT_H
+
+#include <threadsafety.h>
+#include <util/expected.h>
+#include <wallet/wallet.h>
+
+#include <optional>
+#include <vector>
+
+namespace wallet {
+// Struct containing all of the info from WalletDescriptor, except with the descriptor as a string,
+// and without its ID or cache.
+// Used when exporting descriptors from the wallet.
+struct WalletDescInfo {
+ std::string descriptor;
+ uint64_t creation_time;
+ bool active;
+ std::optional<bool> internal;
+ std::optional<std::pair<int64_t,int64_t>> range;
+ int64_t next_index;
+};
+
+//! Export the descriptors from a wallet so that they can be imported elsewhere
+util::Expected<std::vector<WalletDescInfo>, std::string> ExportDescriptors(const CWallet& wallet, bool export_private) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
+} // namespace wallet
+
+#endif // BITCOIN_WALLET_EXPORT_H
diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp
index 396be628..9c58e0fe 100644
--- a/src/wallet/rpc/backup.cpp
+++ b/src/wallet/rpc/backup.cpp
@@ -21,6 +21,7 @@
#include <util/fs.h>
#include <util/time.h>
#include <util/translation.h>
+#include <wallet/export.h>
#include <wallet/rpc/util.h>
#include <wallet/wallet.h>
@@ -526,38 +527,11 @@ RPCMethod listdescriptors()
}
LOCK(wallet->cs_wallet);
-
- const auto active_spk_mans = wallet->GetActiveScriptPubKeyMans();
-
- struct WalletDescInfo {
- std::string descriptor;
- uint64_t creation_time;
- bool active;
- std::optional<bool> internal;
- std::optional<std::pair<int64_t,int64_t>> range;
- int64_t next_index;
- };
-
- std::vector<WalletDescInfo> wallet_descriptors;
- for (const auto& spk_man : wallet->GetAllScriptPubKeyMans()) {
- const auto desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man);
- if (!desc_spk_man) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Unexpected ScriptPubKey manager type.");
- }
- LOCK(desc_spk_man->cs_desc_man);
- const auto& wallet_descriptor = desc_spk_man->GetWalletDescriptor();
- std::string descriptor;
- CHECK_NONFATAL(desc_spk_man->GetDescriptorString(descriptor, priv));
- const bool is_range = wallet_descriptor.descriptor->IsRange();
- wallet_descriptors.push_back({
- descriptor,
- wallet_descriptor.creation_time,
- active_spk_mans.contains(desc_spk_man),
- wallet->IsInternalScriptPubKeyMan(desc_spk_man),
- is_range ? std::optional(std::make_pair(wallet_descriptor.range_start, wallet_descriptor.range_end)) : std::nullopt,
- wallet_descriptor.next_index
- });
+ util::Expected<std::vector<WalletDescInfo>, std::string> exported = ExportDescriptors(*wallet, priv);
+ if (!exported) {
+ throw JSONRPCError(RPC_WALLET_ERROR, exported.error());
}
+ std::vector<WalletDescInfo> wallet_descriptors = *exported;
std::sort(wallet_descriptors.begin(), wallet_descriptors.end(), [](const auto& a, const auto& b) {
return a.descriptor < b.descriptor;
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 47701d7e..9f964e50 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -23,6 +23,7 @@
#include <tinyformat.h>
#include <uint256.h>
#include <util/btcsignals.h>
+#include <util/expected.h>
#include <util/fs.h>
#include <util/hasher.h>
#include <util/log.h>
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.