From 55a82eaf91d252a04a0cc8ad7d948d956c6cb24f Mon Sep 17 00:00:00 2001 From: Antoine Poinsot Date: Wed, 29 Jun 2022 18:13:51 +0200 Subject: [PATCH 1/5] wallet: allow to fetch the wallet descriptors for a given Script We currently expose a method to get the signing providers, which allows to infer a descriptor from the scriptPubKey. But in order to identify "on" what descriptor a coin was received, we need access to the descriptors that were imported to the wallet. --- src/wallet/wallet.cpp | 12 ++++++++++++ src/wallet/wallet.h | 3 +++ 2 files changed, 15 insertions(+) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 475627c76c7..18ca6303122 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3311,6 +3311,18 @@ std::unique_ptr CWallet::GetSolvingProvider(const CScript& scri return nullptr; } +std::vector CWallet::GetWalletDescriptors(const CScript& script) const +{ + std::vector descs; + for (const auto spk_man: GetScriptPubKeyMans(script)) { + if (const auto desc_spk_man = dynamic_cast(spk_man)) { + LOCK(desc_spk_man->cs_desc_man); + descs.push_back(desc_spk_man->GetWalletDescriptor()); + } + } + return descs; +} + LegacyScriptPubKeyMan* CWallet::GetLegacyScriptPubKeyMan() const { if (IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index e2c3d76438f..b08b491ef1a 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -839,6 +839,9 @@ public: std::unique_ptr GetSolvingProvider(const CScript& script) const; std::unique_ptr GetSolvingProvider(const CScript& script, SignatureData& sigdata) const; + //! Get the wallet descriptors for a script. + std::vector GetWalletDescriptors(const CScript& script) const; + //! Get the LegacyScriptPubKeyMan which is used for all types, internal, and external. LegacyScriptPubKeyMan* GetLegacyScriptPubKeyMan() const; LegacyScriptPubKeyMan* GetOrCreateLegacyScriptPubKeyMan(); From b724476158a7dfeef9edfda3f519dfd6f93202a8 Mon Sep 17 00:00:00 2001 From: Antoine Poinsot Date: Wed, 29 Jun 2022 19:04:48 +0200 Subject: [PATCH 2/5] rpc: output wallet descriptors for received entries in listsinceblock The descriptor wallets allow an application to track coins of multiple descriptors in a single wallet. However, such an application would not previously be able to (easily) tell what received coin "belongs" to what descriptor. This commit tackles this issues by adding a "wallet_desc" entry to the entries for received coins in 'listsinceblock'. --- src/wallet/rpc/transactions.cpp | 10 +++++- src/wallet/rpc/util.cpp | 9 ++++++ src/wallet/rpc/util.h | 4 +++ test/functional/wallet_listsinceblock.py | 41 ++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp index 0b52dcc0010..db44ee7a4cb 100644 --- a/src/wallet/rpc/transactions.cpp +++ b/src/wallet/rpc/transactions.cpp @@ -367,6 +367,7 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM entry.pushKV("involvesWatchonly", true); } MaybePushAddress(entry, r.destination); + PushParentDescriptors(wallet, wtx.tx->vout.at(r.vout).scriptPubKey, entry); if (wtx.IsCoinBase()) { if (wallet.GetTxDepthInMainChain(wtx) < 1) @@ -418,7 +419,11 @@ static const std::vector TransactionDescriptionString() {RPCResult::Type::NUM_TIME, "timereceived", "The time received expressed in " + UNIX_EPOCH_TIME + "."}, {RPCResult::Type::STR, "comment", /*optional=*/true, "If a comment is associated with the transaction, only present if not empty."}, {RPCResult::Type::STR, "bip125-replaceable", "(\"yes|no|unknown\") Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n" - "may be unknown for unconfirmed transactions not in the mempool."}}; + "may be unknown for unconfirmed transactions not in the mempool."}, + {RPCResult::Type::ARR, "parent_descs", /*optional=*/true, "Only if 'category' is 'received'. List of parent descriptors for the scriptPubKey of this coin.", { + {RPCResult::Type::STR, "desc", "The descriptor string."}, + }}, + }; } RPCHelpMan listtransactions() @@ -709,6 +714,9 @@ RPCHelpMan gettransaction() "'send' category of transactions."}, {RPCResult::Type::BOOL, "abandoned", /*optional=*/true, "'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n" "'send' category of transactions."}, + {RPCResult::Type::ARR, "parent_descs", /*optional=*/true, "Only if 'category' is 'received'. List of parent descriptors for the scriptPubKey of this coin.", { + {RPCResult::Type::STR, "desc", "The descriptor string."}, + }}, }}, }}, {RPCResult::Type::STR_HEX, "hex", "Raw data for transaction"}, diff --git a/src/wallet/rpc/util.cpp b/src/wallet/rpc/util.cpp index 4fcb393226f..16305d44652 100644 --- a/src/wallet/rpc/util.cpp +++ b/src/wallet/rpc/util.cpp @@ -123,6 +123,15 @@ std::string LabelFromValue(const UniValue& value) return label; } +void PushParentDescriptors(const CWallet& wallet, const CScript& script_pubkey, UniValue& entry) +{ + UniValue parent_descs(UniValue::VARR); + for (const auto& desc: wallet.GetWalletDescriptors(script_pubkey)) { + parent_descs.push_back(desc.descriptor->ToString()); + } + entry.pushKV("parent_descs", parent_descs); +} + void HandleWalletError(const std::shared_ptr wallet, DatabaseStatus& status, bilingual_str& error) { if (!wallet) { diff --git a/src/wallet/rpc/util.h b/src/wallet/rpc/util.h index 7b810eb06e7..2ca28914e7f 100644 --- a/src/wallet/rpc/util.h +++ b/src/wallet/rpc/util.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_WALLET_RPC_UTIL_H #define BITCOIN_WALLET_RPC_UTIL_H +#include