Skip to content
Bitcoin Roots

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);