v31.1-roots.1 · Commit 6: [PATCH 06/17] feat(wallet): preserve Roots signing and spend controls on v31
src/rpc/blockchain.cpp
Before: src/rpc/blockchain.cpp · After: src/rpc/blockchain.cpp
File metadata
index c631a93674aa296f74871ff7c3db3b1aa12ea741..c9fff1f49e43e26fa54047e13365e54f1fb5ed11 100644
Download original patch · Release notes
Diff rows 1–130 of 130. Line numbers refer to the original before/after files.
+ Added− RemovedUnmarked lines are context.
Scroll the code area horizontally to read long lines. Before is on the left; after is on the right. Unified view fits narrow screens more easily.
src/rpc/blockchain.cpp
CHANGED
|
@@ -2194,7 +2194,7 @@ static RPCHelpMan getblockstats()
|
|
| 2194 |
|
| 2195 |
namespace {
|
| 2196 |
//! Search for a given set of pubkey scripts
|
| 2197 |
-
bool FindScriptPubKey(std::atomic<int>& scan_progress, const std::atomic<bool>& should_abort, int64_t& count, CCoinsViewCursor* cursor, const std::set<CScript>& needles, std::map<COutPoint, Coin>& out_results, std::function<void()>& interruption_point)
|
| 2198 |
{
|
| 2199 |
scan_progress = 0;
|
| 2200 |
count = 0;
|
|
@@ -2202,9 +2202,8 @@ bool FindScriptPubKey(std::atomic<int>& scan_progress, const std::atomic<bool>&
|
|
| 2202 |
COutPoint key;
|
| 2203 |
Coin coin;
|
| 2204 |
if (!cursor->GetKey(key) || !cursor->GetValue(coin)) return false;
|
| 2205 |
-
if (++count % 8192 == 0) {
|
| 2206 |
-
interruption_point();
|
| 2207 |
-
if (should_abort) {
|
| 2208 |
// allow to abort the scan via the abort reference
|
| 2209 |
return false;
|
| 2210 |
}
|
|
@@ -2225,33 +2224,42 @@ bool FindScriptPubKey(std::atomic<int>& scan_progress, const std::atomic<bool>&
|
|
| 2225 |
} // namespace
|
| 2226 |
|
| 2227 |
/** RAII object to prevent concurrency issue when scanning the txout set */
|
| 2228 |
-
static std::atomic<int> g_scan_progress;
|
| 2229 |
-
static std::atomic<bool> g_scan_in_progress;
|
| 2230 |
-
static std::atomic<bool> g_should_abort_scan;
|
| 2231 |
-
class CoinsViewScanReserver
|
| 2232 |
-
{
|
| 2233 |
-
private:
|
| 2234 |
-
bool m_could_reserve{false};
|
| 2235 |
-
public:
|
| 2236 |
-
explicit CoinsViewScanReserver() = default;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2237 |
|
| 2238 |
-
bool reserve() {
|
| 2239 |
-
CHECK_NONFATAL(!m_could_reserve);
|
| 2240 |
-
if (g_scan_in_progress.exchange(true)) {
|
| 2241 |
-
return false;
|
| 2242 |
-
}
|
| 2243 |
-
CHECK_NONFATAL(g_scan_progress == 0);
|
| 2244 |
-
m_could_reserve = true;
|
| 2245 |
-
return true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2246 |
}
|
| 2247 |
-
|
| 2248 |
-
~CoinsViewScanReserver() {
|
| 2249 |
-
if (m_could_reserve) {
|
| 2250 |
-
g_scan_in_progress = false;
|
| 2251 |
-
g_scan_progress = 0;
|
| 2252 |
-
}
|
| 2253 |
}
|
| 2254 |
-
};
|
|
|
|
| 2255 |
|
| 2256 |
static const auto scan_action_arg_desc = RPCArg{
|
| 2257 |
"action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n"
|
|
@@ -2358,24 +2366,24 @@ static RPCHelpMan scantxoutset()
|
|
| 2358 |
UniValue result(UniValue::VOBJ);
|
| 2359 |
const auto action{self.Arg<std::string_view>("action")};
|
| 2360 |
if (action == "status") {
|
| 2361 |
-
CoinsViewScanReserver reserver;
|
| 2362 |
if (reserver.reserve()) {
|
| 2363 |
// no scan in progress
|
| 2364 |
return UniValue::VNULL;
|
| 2365 |
}
|
| 2366 |
-
result.pushKV("progress", g_scan_progress.load());
|
| 2367 |
return result;
|
| 2368 |
} else if (action == "abort") {
|
| 2369 |
-
CoinsViewScanReserver reserver;
|
| 2370 |
if (reserver.reserve()) {
|
| 2371 |
// reserve was possible which means no scan was running
|
| 2372 |
return false;
|
| 2373 |
}
|
| 2374 |
// set the abort flag
|
| 2375 |
-
g_should_abort_scan = true;
|
| 2376 |
return true;
|
| 2377 |
} else if (action == "start") {
|
| 2378 |
-
CoinsViewScanReserver reserver;
|
| 2379 |
if (!reserver.reserve()) {
|
| 2380 |
throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
|
| 2381 |
}
|
|
@@ -2403,7 +2411,7 @@ static RPCHelpMan scantxoutset()
|
|
| 2403 |
UniValue unspents(UniValue::VARR);
|
| 2404 |
std::vector<CTxOut> input_txos;
|
| 2405 |
std::map<COutPoint, Coin> coins;
|
| 2406 |
-
g_should_abort_scan = false;
|
| 2407 |
int64_t count = 0;
|
| 2408 |
std::unique_ptr<CCoinsViewCursor> pcursor;
|
| 2409 |
const CBlockIndex* tip;
|
|
@@ -2416,7 +2424,7 @@ static RPCHelpMan scantxoutset()
|
|
| 2416 |
pcursor = CHECK_NONFATAL(active_chainstate.CoinsDB().Cursor());
|
| 2417 |
tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
|
| 2418 |
}
|
| 2419 |
-
bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins, node.rpc_interruption_point);
|
| 2420 |
result.pushKV("success", res);
|
| 2421 |
result.pushKV("txouts", count);
|
| 2422 |
result.pushKV("height", tip->nHeight);
|
|
|
|
| 2194 |
|
| 2195 |
namespace {
|
| 2196 |
//! Search for a given set of pubkey scripts
|
| 2197 |
+
bool FindScriptPubKey(std::atomic<int>& scan_progress, const std::atomic<bool>& should_abort, int64_t& count, CCoinsViewCursor* cursor, const std::set<CScript>& needles, std::map<COutPoint, Coin>& out_results, std::function<void()>& interruption_point, const std::function<bool()>& local_should_abort = {})
|
| 2198 |
{
|
| 2199 |
scan_progress = 0;
|
| 2200 |
count = 0;
|
|
|
|
| 2202 |
COutPoint key;
|
| 2203 |
Coin coin;
|
| 2204 |
if (!cursor->GetKey(key) || !cursor->GetValue(coin)) return false;
|
| 2205 |
+
if (rpc::scan::CheckInterruption(++count, interruption_point)) {
|
| 2206 |
+
if (should_abort || (local_should_abort && local_should_abort())) {
|
|
|
|
| 2207 |
// allow to abort the scan via the abort reference
|
| 2208 |
return false;
|
| 2209 |
}
|
|
|
|
| 2224 |
} // namespace
|
| 2225 |
|
| 2226 |
/** RAII object to prevent concurrency issue when scanning the txout set */
|
| 2227 |
+
std::atomic<int> rpc::scan::g_progress;
|
| 2228 |
+
std::atomic<bool> rpc::scan::g_in_progress;
|
| 2229 |
+
std::atomic<bool> rpc::scan::g_should_abort;
|
| 2230 |
+
bool rpc::scan::Reserver::reserve() {
|
| 2231 |
+
CHECK_NONFATAL(!m_reserved);
|
| 2232 |
+
if (g_in_progress.exchange(true)) return false;
|
| 2233 |
+
CHECK_NONFATAL(g_progress == 0);
|
| 2234 |
+
m_reserved = true;
|
| 2235 |
+
return true;
|
| 2236 |
+
}
|
| 2237 |
+
rpc::scan::Reserver::~Reserver() { if (m_reserved) { g_progress = 0; g_in_progress = false; } }
|
| 2238 |
+
bool rpc::scan::CheckInterruption(int64_t count, const std::function<void()>& interruption) { if (count % 8192 != 0) return false; interruption(); return true; }
|
| 2239 |
+
using rpc::scan::Reserver;
|
| 2240 |
|
| 2241 |
+
interfaces::ScanResult ScanUTXOSet(NodeContext& node, const std::set<CScript>& needles, std::map<COutPoint, Coin>& coins,
|
| 2242 |
+
const std::function<bool()>& should_abort)
|
| 2243 |
+
{
|
| 2244 |
+
Reserver reserver;
|
| 2245 |
+
if (!reserver.reserve()) return interfaces::ScanResult::BUSY;
|
| 2246 |
+
if (should_abort && should_abort()) return interfaces::ScanResult::ABORTED;
|
| 2247 |
+
std::unique_ptr<CCoinsViewCursor> cursor;
|
| 2248 |
+
{
|
| 2249 |
+
ChainstateManager& chainman = EnsureChainman(node);
|
| 2250 |
+
LOCK(cs_main);
|
| 2251 |
+
Chainstate& chainstate = chainman.ActiveChainstate();
|
| 2252 |
+
chainstate.ForceFlushStateToDisk(/*wipe_cache=*/false);
|
| 2253 |
+
cursor = CHECK_NONFATAL(chainstate.CoinsDB().Cursor());
|
| 2254 |
}
|
| 2255 |
+
rpc::scan::g_should_abort = false;
|
| 2256 |
+
std::atomic<int> progress;
|
| 2257 |
+
int64_t count;
|
| 2258 |
+
if (FindScriptPubKey(progress, rpc::scan::g_should_abort, count, cursor.get(), needles, coins, node.rpc_interruption_point, should_abort)) {
|
| 2259 |
+
return interfaces::ScanResult::SUCCESS;
|
|
|
|
| 2260 |
}
|
| 2261 |
+
return rpc::scan::g_should_abort || (should_abort && should_abort()) ? interfaces::ScanResult::ABORTED : interfaces::ScanResult::UNAVAILABLE;
|
| 2262 |
+
}
|
| 2263 |
|
| 2264 |
static const auto scan_action_arg_desc = RPCArg{
|
| 2265 |
"action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n"
|
|
|
|
| 2366 |
UniValue result(UniValue::VOBJ);
|
| 2367 |
const auto action{self.Arg<std::string_view>("action")};
|
| 2368 |
if (action == "status") {
|
| 2369 |
+
Reserver reserver;
|
| 2370 |
if (reserver.reserve()) {
|
| 2371 |
// no scan in progress
|
| 2372 |
return UniValue::VNULL;
|
| 2373 |
}
|
| 2374 |
+
result.pushKV("progress", rpc::scan::g_progress.load());
|
| 2375 |
return result;
|
| 2376 |
} else if (action == "abort") {
|
| 2377 |
+
Reserver reserver;
|
| 2378 |
if (reserver.reserve()) {
|
| 2379 |
// reserve was possible which means no scan was running
|
| 2380 |
return false;
|
| 2381 |
}
|
| 2382 |
// set the abort flag
|
| 2383 |
+
rpc::scan::g_should_abort = true;
|
| 2384 |
return true;
|
| 2385 |
} else if (action == "start") {
|
| 2386 |
+
Reserver reserver;
|
| 2387 |
if (!reserver.reserve()) {
|
| 2388 |
throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
|
| 2389 |
}
|
|
|
|
| 2411 |
UniValue unspents(UniValue::VARR);
|
| 2412 |
std::vector<CTxOut> input_txos;
|
| 2413 |
std::map<COutPoint, Coin> coins;
|
| 2414 |
+
rpc::scan::g_should_abort = false;
|
| 2415 |
int64_t count = 0;
|
| 2416 |
std::unique_ptr<CCoinsViewCursor> pcursor;
|
| 2417 |
const CBlockIndex* tip;
|
|
|
|
| 2424 |
pcursor = CHECK_NONFATAL(active_chainstate.CoinsDB().Cursor());
|
| 2425 |
tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
|
| 2426 |
}
|
| 2427 |
+
bool res = FindScriptPubKey(rpc::scan::g_progress, rpc::scan::g_should_abort, count, pcursor.get(), needles, coins, node.rpc_interruption_point);
|
| 2428 |
result.pushKV("success", res);
|
| 2429 |
result.pushKV("txouts", count);
|
| 2430 |
result.pushKV("height", tip->nHeight);
|