mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-09 11:27:28 -03:00
wallet: Add scan_utxo option to getbalances RPC
Add the option to getbalances by scanning the utxo set
This commit is contained in:
parent
d752349029
commit
b210d3b134
6 changed files with 69 additions and 4 deletions
|
@ -188,6 +188,9 @@ public:
|
|||
//! populates the values.
|
||||
virtual void findCoins(std::map<COutPoint, Coin>& coins) = 0;
|
||||
|
||||
//! Scan UTXO set from coins belonging to the output_scripts
|
||||
virtual void getCoinsByScript(std::set<CScript>& output_scripts, std::map<COutPoint, Coin>& coins) = 0;
|
||||
|
||||
//! Estimate fraction of total transactions verified if blocks up to
|
||||
//! the specified block hash are verified.
|
||||
virtual double guessVerificationProgress(const uint256& block_hash) = 0;
|
||||
|
|
|
@ -23,4 +23,21 @@ void FindCoins(const NodeContext& node, std::map<COutPoint, Coin>& coins)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GetCoins(const NodeContext& node, std::set<CScript>& output_scripts, std::map<COutPoint, Coin>& coins)
|
||||
{
|
||||
assert(node.chainman);
|
||||
LOCK(cs_main);
|
||||
std::unique_ptr<CCoinsViewCursor> cursor = node.chainman->ActiveChainstate().CoinsDB().Cursor();
|
||||
while (cursor->Valid()) {
|
||||
COutPoint key;
|
||||
Coin coin;
|
||||
if (cursor->GetKey(key) && cursor->GetValue(coin)) {
|
||||
if (output_scripts.count(coin.out.scriptPubKey)) {
|
||||
coins.emplace(key, coin);
|
||||
}
|
||||
}
|
||||
cursor->Next();
|
||||
}
|
||||
}
|
||||
} // namespace node
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
#define BITCOIN_NODE_COIN_H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
class COutPoint;
|
||||
class Coin;
|
||||
class CScript;
|
||||
|
||||
namespace node {
|
||||
struct NodeContext;
|
||||
|
@ -22,6 +24,15 @@ struct NodeContext;
|
|||
* @param[in,out] coins map to fill
|
||||
*/
|
||||
void FindCoins(const node::NodeContext& node, std::map<COutPoint, Coin>& coins);
|
||||
|
||||
/**
|
||||
* Scans the UTXO set for coins belonging to output_scripts.
|
||||
*
|
||||
* @param[in] node The node context to use for lookup
|
||||
* @param[in] output_scripts The scripts to scan for coins
|
||||
* @param[in,out] coins map to fill
|
||||
*/
|
||||
void GetCoins(const NodeContext& node, std::set<CScript>& output_scripts, std::map<COutPoint, Coin>& coins);
|
||||
} // namespace node
|
||||
|
||||
#endif // BITCOIN_NODE_COIN_H
|
||||
|
|
|
@ -610,6 +610,10 @@ public:
|
|||
int{FillBlock(block2, block2_out, lock, active, chainman().m_blockman)};
|
||||
}
|
||||
void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); }
|
||||
void getCoinsByScript(std::set<CScript>& output_scripts, std::map<COutPoint, Coin>& coins) override
|
||||
{
|
||||
return GetCoins(m_node, output_scripts, coins);
|
||||
}
|
||||
double guessVerificationProgress(const uint256& block_hash) override
|
||||
{
|
||||
LOCK(::cs_main);
|
||||
|
|
|
@ -185,6 +185,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||
{ "lockunspent", 0, "unlock" },
|
||||
{ "lockunspent", 1, "transactions" },
|
||||
{ "lockunspent", 2, "persistent" },
|
||||
{ "getbalances", 0, "scan_utxoset" },
|
||||
{ "send", 0, "outputs" },
|
||||
{ "send", 1, "conf_target" },
|
||||
{ "send", 3, "fee_rate"},
|
||||
|
|
|
@ -432,7 +432,9 @@ RPCHelpMan getbalances()
|
|||
return RPCHelpMan{
|
||||
"getbalances",
|
||||
"Returns an object with all balances in " + CURRENCY_UNIT + ".\n",
|
||||
{},
|
||||
{
|
||||
{"scan_utxoset", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to scan (true) or not to scan (false) the unspent transactions output set"},
|
||||
},
|
||||
RPCResult{
|
||||
RPCResult::Type::OBJ, "", "",
|
||||
{
|
||||
|
@ -453,8 +455,10 @@ RPCHelpMan getbalances()
|
|||
}
|
||||
},
|
||||
RPCExamples{
|
||||
HelpExampleCli("getbalances", "") +
|
||||
HelpExampleRpc("getbalances", "")},
|
||||
HelpExampleCli("getbalances", "")
|
||||
+ HelpExampleRpc("getbalances", "")
|
||||
+ HelpExampleCli("getbalances", "true")
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
const std::shared_ptr<const CWallet> rpc_wallet = GetWalletForJSONRPCRequest(request);
|
||||
|
@ -468,10 +472,35 @@ RPCHelpMan getbalances()
|
|||
LOCK(wallet.cs_wallet);
|
||||
|
||||
const auto bal = GetBalance(wallet);
|
||||
|
||||
CAmount utxo_balance = 0;
|
||||
|
||||
bool scan_utxoset = false;
|
||||
if (!request.params[0].isNull()) {
|
||||
scan_utxoset = request.params[0].get_bool();
|
||||
}
|
||||
if (scan_utxoset) {
|
||||
std::set<CScript> output_scripts;
|
||||
for (const auto spkm : wallet.GetAllScriptPubKeyMans()) {
|
||||
for (const auto& script : spkm->GetScriptPubKeys()) {
|
||||
output_scripts.emplace(script);
|
||||
}
|
||||
}
|
||||
|
||||
// Get coins belonging to wallet scripts from utxo set
|
||||
std::map<COutPoint, Coin> coins;
|
||||
wallet.chain().getCoinsByScript(output_scripts, coins);
|
||||
|
||||
for (const auto& it : coins) {
|
||||
const Coin& coin = it.second;
|
||||
utxo_balance += coin.out.nValue;
|
||||
}
|
||||
}
|
||||
|
||||
UniValue balances{UniValue::VOBJ};
|
||||
{
|
||||
UniValue balances_mine{UniValue::VOBJ};
|
||||
balances_mine.pushKV("trusted", ValueFromAmount(bal.m_mine_trusted));
|
||||
balances_mine.pushKV("trusted", ValueFromAmount(scan_utxoset ? utxo_balance : bal.m_mine_trusted));
|
||||
balances_mine.pushKV("untrusted_pending", ValueFromAmount(bal.m_mine_untrusted_pending));
|
||||
balances_mine.pushKV("immature", ValueFromAmount(bal.m_mine_immature));
|
||||
if (wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
|
||||
|
|
Loading…
Reference in a new issue