aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
authorSamuel Dobson <dobsonsa68@gmail.com>2021-08-09 13:37:09 +1200
committerSamuel Dobson <dobsonsa68@gmail.com>2021-08-09 14:09:07 +1200
commit8fa03c4ddf833d767214f147873600e036858d37 (patch)
tree1f6fa5d3dbbfa02dcd8f7d55e14fd00afe560eb5 /src/wallet
parentdb94d74f241410d6577b695d73184740797448e6 (diff)
parentbb822a7af86897a9b6a5d616f193c258e8e76729 (diff)
Merge bitcoin/bitcoin#21500: wallet, rpc: add an option to list private descriptors
bb822a7af86897a9b6a5d616f193c258e8e76729 wallet, rpc: add listdescriptors private option (S3RK) Pull request description: Rationale: make it possible to backup your wallet with `listdescriptors` command * The default behaviour is still to show public version * For private version only the root xprv is returned Example use-case: ``` > bitcoin-cli -regtest -named createwallet wallet_name=old descriptors=true > bitcoin-cli -regtest -rpcwallet=old listdescriptors true | jq '.descriptors' > descriptors.txt > bitcoin-cli -regtest -named createwallet wallet_name=new descriptors=true blank=true > bitcoin-cli -regtest -rpcwallet=new importdescriptors "$(cat descriptors.txt)" ``` In case of watch-only wallet without private keys there will be following output: ``` error code: -4 error message: Can't get descriptor string. ``` ACKs for top commit: achow101: re-ACK bb822a7af86897a9b6a5d616f193c258e8e76729 Rspigler: tACK bb822a7af86897a9b6a5d616f193c258e8e76729 jonatack: ACK bb822a7af86897a9b6a5d616f193c258e8e76729 per `git diff 2854ddc bb822a7` prayank23: tACK https://github.com/bitcoin/bitcoin/pull/21500/commits/bb822a7af86897a9b6a5d616f193c258e8e76729 meshcollider: Code review ACK bb822a7af86897a9b6a5d616f193c258e8e76729 Tree-SHA512: f6dddc72a74e5667071ccd77f8dce578382e8e29e7ed6a0834ac2e114a6d3918b59c2f194f4079b3259e13d9ba3b4f405619940c3ecb7a1a0344615aed47c43d
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/rpcdump.cpp17
-rw-r--r--src/wallet/rpcwallet.cpp2
-rw-r--r--src/wallet/scriptpubkeyman.cpp9
-rw-r--r--src/wallet/scriptpubkeyman.h2
4 files changed, 23 insertions, 7 deletions
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index ac60504419..cccaff9d65 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -1760,8 +1760,10 @@ RPCHelpMan listdescriptors()
{
return RPCHelpMan{
"listdescriptors",
- "\nList descriptors imported into a descriptor-enabled wallet.",
- {},
+ "\nList descriptors imported into a descriptor-enabled wallet.\n",
+ {
+ {"private", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show private descriptors."}
+ },
RPCResult{RPCResult::Type::OBJ, "", "", {
{RPCResult::Type::STR, "wallet_name", "Name of wallet this operation was performed on"},
{RPCResult::Type::ARR, "descriptors", "Array of descriptor objects",
@@ -1781,6 +1783,7 @@ RPCHelpMan listdescriptors()
}},
RPCExamples{
HelpExampleCli("listdescriptors", "") + HelpExampleRpc("listdescriptors", "")
+ + HelpExampleCli("listdescriptors", "true") + HelpExampleRpc("listdescriptors", "true")
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
@@ -1791,6 +1794,11 @@ RPCHelpMan listdescriptors()
throw JSONRPCError(RPC_WALLET_ERROR, "listdescriptors is not available for non-descriptor wallets");
}
+ const bool priv = !request.params[0].isNull() && request.params[0].get_bool();
+ if (priv) {
+ EnsureWalletIsUnlocked(*wallet);
+ }
+
LOCK(wallet->cs_wallet);
UniValue descriptors(UniValue::VARR);
@@ -1804,8 +1812,9 @@ RPCHelpMan listdescriptors()
LOCK(desc_spk_man->cs_desc_man);
const auto& wallet_descriptor = desc_spk_man->GetWalletDescriptor();
std::string descriptor;
- if (!desc_spk_man->GetDescriptorString(descriptor)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Can't get normalized descriptor string.");
+
+ if (!desc_spk_man->GetDescriptorString(descriptor, priv)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Can't get descriptor string.");
}
spk.pushKV("desc", descriptor);
spk.pushKV("timestamp", wallet_descriptor.creation_time);
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 43b67076cd..4b32ff56f4 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -3875,7 +3875,7 @@ RPCHelpMan getaddressinfo()
DescriptorScriptPubKeyMan* desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(pwallet->GetScriptPubKeyMan(scriptPubKey));
if (desc_spk_man) {
std::string desc_str;
- if (desc_spk_man->GetDescriptorString(desc_str)) {
+ if (desc_spk_man->GetDescriptorString(desc_str, /* priv */ false)) {
ret.pushKV("parent_desc", desc_str);
}
}
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index 73433214f1..3c821e5a81 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -2258,13 +2258,20 @@ const std::vector<CScript> DescriptorScriptPubKeyMan::GetScriptPubKeys() const
return script_pub_keys;
}
-bool DescriptorScriptPubKeyMan::GetDescriptorString(std::string& out) const
+bool DescriptorScriptPubKeyMan::GetDescriptorString(std::string& out, const bool priv) const
{
LOCK(cs_desc_man);
FlatSigningProvider provider;
provider.keys = GetKeys();
+ if (priv) {
+ // For the private version, always return the master key to avoid
+ // exposing child private keys. The risk implications of exposing child
+ // private keys together with the parent xpub may be non-obvious for users.
+ return m_wallet_descriptor.descriptor->ToPrivateString(provider, out);
+ }
+
return m_wallet_descriptor.descriptor->ToNormalizedString(provider, out, &m_wallet_descriptor.cache);
}
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index e329e0cf8f..3f203d57b9 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -621,7 +621,7 @@ public:
const WalletDescriptor GetWalletDescriptor() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
const std::vector<CScript> GetScriptPubKeys() const;
- bool GetDescriptorString(std::string& out) const;
+ bool GetDescriptorString(std::string& out, const bool priv) const;
void UpgradeDescriptorCache();
};