From 9bf22dfd35e2058e971565f98c829a36a7862807 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 1 Sep 2022 11:49:57 -0400 Subject: [PATCH] Merge bitcoin/bitcoin#25931: rpc: sort listdescriptors result 50996241f2b0eefeaab4fcd11b9730fa2dc107ae rpc: sort listdescriptors result (Sjors Provoost) Pull request description: This puts receive and change descriptors directly below each other. The change would be simpler if `UniValue` arrays were sortable. ACKs for top commit: achow101: ACK 50996241f2b0eefeaab4fcd11b9730fa2dc107ae S3RK: reACK 50996241f2b0eefeaab4fcd11b9730fa2dc107ae furszy: utACK 50996241 w0xlt: reACK https://github.com/bitcoin/bitcoin/pull/25931/commits/50996241f2b0eefeaab4fcd11b9730fa2dc107ae Tree-SHA512: 71246a48ba6f97c3e7c76ee32ff9e958227a14ca5a6eec638215dbfee57264d4e918ea5837f4d030eddc9c797c93df1791ddd55b5a499522ce2a35bcf380670b --- src/wallet/rpc/backup.cpp | 96 +++++++++++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 24 deletions(-) diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp index 4721e70eaab2..1122a7fa1e5e 100644 --- a/src/wallet/rpc/backup.cpp +++ b/src/wallet/rpc/backup.cpp @@ -2026,51 +2026,99 @@ RPCHelpMan listdescriptors() LOCK(wallet->cs_wallet); - UniValue descriptors(UniValue::VARR); const auto active_spk_mans = wallet->GetActiveScriptPubKeyMans(); + + struct WalletDescInfo { + std::string descriptor; + uint64_t creation_time; + bool active; + std::optional internal; + std::optional> range; + int64_t next_index; + // Dash-specific fields + SecureString mnemonic; + SecureString mnemonic_passphrase; + bool is_coinjoin; + }; + + std::vector wallet_descriptors; for (const auto& spk_man : wallet->GetAllScriptPubKeyMans()) { const auto desc_spk_man = dynamic_cast(spk_man); if (!desc_spk_man) { throw JSONRPCError(RPC_WALLET_ERROR, "Unexpected ScriptPubKey manager type."); } - UniValue spk(UniValue::VOBJ); LOCK(desc_spk_man->cs_desc_man); const auto& wallet_descriptor = desc_spk_man->GetWalletDescriptor(); std::string descriptor; - if (!desc_spk_man->GetDescriptorString(descriptor, priv)) { throw JSONRPCError(RPC_WALLET_ERROR, "Can't get descriptor string."); } - if (priv) { - SecureString mnemonic; - SecureString mnemonic_passphrase; - if (desc_spk_man->GetMnemonicString(mnemonic, mnemonic_passphrase) && !mnemonic.empty()) { - spk.pushKV("mnemonic", mnemonic); - spk.pushKV("mnemonicpassphrase", mnemonic_passphrase); - } - } - spk.pushKV("desc", descriptor); - spk.pushKV("timestamp", wallet_descriptor.creation_time); + const bool is_range = wallet_descriptor.descriptor->IsRange(); const bool active = active_spk_mans.count(desc_spk_man) != 0; - spk.pushKV("active", active); const auto& type = wallet_descriptor.descriptor->GetOutputType(); + + // Compute internal status (Dash uses different method than Bitcoin) + std::optional internal_status; if (active && type != std::nullopt) { - spk.pushKV("internal", wallet->GetScriptPubKeyMan(true) == desc_spk_man); + internal_status = wallet->GetScriptPubKeyMan(true) == desc_spk_man; } + + // Dash-specific: check for CoinJoin descriptor + bool is_cj = false; if (type != std::nullopt) { std::string match = strprintf("/%d'/%s'/4'/0'", BIP32_PURPOSE_FEATURE, Params().ExtCoinType()); - bool is_cj = descriptor.find(match) != std::string::npos; - if (is_cj) { - spk.pushKV("coinjoin", is_cj); - } + is_cj = descriptor.find(match) != std::string::npos; } - if (wallet_descriptor.descriptor->IsRange()) { + + // Dash-specific: get mnemonic if private + SecureString mnemonic; + SecureString mnemonic_passphrase; + if (priv) { + desc_spk_man->GetMnemonicString(mnemonic, mnemonic_passphrase); + } + + wallet_descriptors.push_back({ + descriptor, + wallet_descriptor.creation_time, + active, + internal_status, + is_range ? std::optional(std::make_pair(wallet_descriptor.range_start, wallet_descriptor.range_end)) : std::nullopt, + wallet_descriptor.next_index, + mnemonic, + mnemonic_passphrase, + is_cj + }); + } + + std::sort(wallet_descriptors.begin(), wallet_descriptors.end(), [](const auto& a, const auto& b) { + return a.descriptor < b.descriptor; + }); + + UniValue descriptors(UniValue::VARR); + for (const WalletDescInfo& info : wallet_descriptors) { + UniValue spk(UniValue::VOBJ); + // Dash-specific: output mnemonic first if present + if (!info.mnemonic.empty()) { + spk.pushKV("mnemonic", info.mnemonic); + spk.pushKV("mnemonicpassphrase", info.mnemonic_passphrase); + } + spk.pushKV("desc", info.descriptor); + spk.pushKV("timestamp", info.creation_time); + spk.pushKV("active", info.active); + if (info.internal.has_value()) { + spk.pushKV("internal", info.internal.value()); + } + // Dash-specific: output coinjoin status if true + if (info.is_coinjoin) { + spk.pushKV("coinjoin", info.is_coinjoin); + } + if (info.range.has_value()) { UniValue range(UniValue::VARR); - range.push_back(wallet_descriptor.range_start); - range.push_back(wallet_descriptor.range_end - 1); + range.push_back(info.range->first); + range.push_back(info.range->second - 1); spk.pushKV("range", range); - spk.pushKV("next", wallet_descriptor.next_index); - spk.pushKV("next_index", wallet_descriptor.next_index); + spk.pushKV("next", info.next_index); + spk.pushKV("next_index", info.next_index); // Dash-specific: duplicate field } descriptors.push_back(spk); }