Skip to content
Bitcoin Roots

v29.4-roots.3 · Commit 23: [PATCH 23/30] feat(wallet): add transient private-key sweep RPC

src/rpc/blockchain.cpp

Before: src/rpc/blockchain.cpp · After: src/rpc/blockchain.cpp

File metadata
index edda17d3697a56cf3aa6879a036c63b456a09a39..bb3b92d552625562bb4012691070fc1c4753897f 100644

Download original patch · Release notes

Diff rows 1–118 of 118. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. The two line-number columns refer to before and after.

src/rpc/blockchain.cpp CHANGED
@@ -2116,8 +2116,7 @@ bool FindScriptPubKey(std::atomic<int>& scan_progress, const std::atomic<bool>&
2116
2116
  COutPoint key;
2117
2117
  Coin coin;
2118
2118
  if (!cursor->GetKey(key) || !cursor->GetValue(coin)) return false;
2119
- if (++count % 8192 == 0) {
2120
- interruption_point();
2119
+ if (rpc::scan::CheckInterruption(++count, interruption_point)) {
2121
2120
  if (should_abort) {
2122
2121
  // allow to abort the scan via the abort reference
2123
2122
  return false;
@@ -2139,33 +2138,40 @@ bool FindScriptPubKey(std::atomic<int>& scan_progress, const std::atomic<bool>&
2139
2138
  } // namespace
2140
2139
 
2141
2140
  /** RAII object to prevent concurrency issue when scanning the txout set */
2142
- static std::atomic<int> g_scan_progress;
2143
- static std::atomic<bool> g_scan_in_progress;
2144
- static std::atomic<bool> g_should_abort_scan;
2145
- class CoinsViewScanReserver
2146
- {
2147
- private:
2148
- bool m_could_reserve{false};
2149
- public:
2150
- explicit CoinsViewScanReserver() = default;
2141
+ std::atomic<int> rpc::scan::g_progress;
2142
+ std::atomic<bool> rpc::scan::g_in_progress;
2143
+ std::atomic<bool> rpc::scan::g_should_abort;
2144
+ bool rpc::scan::Reserver::reserve() {
2145
+ CHECK_NONFATAL(!m_reserved);
2146
+ if (g_in_progress.exchange(true)) return false;
2147
+ CHECK_NONFATAL(g_progress == 0);
2148
+ m_reserved = true;
2149
+ return true;
2150
+ }
2151
+ rpc::scan::Reserver::~Reserver() { if (m_reserved) { g_in_progress = false; g_progress = 0; } }
2152
+ bool rpc::scan::CheckInterruption(int64_t count, const std::function<void()>& interruption) { if (count % 8192 != 0) return false; interruption(); return true; }
2153
+ using rpc::scan::Reserver;
2151
2154
 
2152
- bool reserve() {
2153
- CHECK_NONFATAL(!m_could_reserve);
2154
- if (g_scan_in_progress.exchange(true)) {
2155
- return false;
2156
- }
2157
- CHECK_NONFATAL(g_scan_progress == 0);
2158
- m_could_reserve = true;
2159
- return true;
2155
+ interfaces::ScanResult ScanUTXOSet(NodeContext& node, const std::set<CScript>& needles, std::map<COutPoint, Coin>& coins)
2156
+ {
2157
+ Reserver reserver;
2158
+ if (!reserver.reserve()) return interfaces::ScanResult::BUSY;
2159
+ std::unique_ptr<CCoinsViewCursor> cursor;
2160
+ {
2161
+ ChainstateManager& chainman = EnsureChainman(node);
2162
+ LOCK(cs_main);
2163
+ Chainstate& chainstate = chainman.ActiveChainstate();
2164
+ chainstate.ForceFlushStateToDisk();
2165
+ cursor = CHECK_NONFATAL(chainstate.CoinsDB().Cursor());
2160
2166
  }
2161
-
2162
- ~CoinsViewScanReserver() {
2163
- if (m_could_reserve) {
2164
- g_scan_in_progress = false;
2165
- g_scan_progress = 0;
2166
- }
2167
+ rpc::scan::g_should_abort = false;
2168
+ std::atomic<int> progress;
2169
+ int64_t count;
2170
+ if (FindScriptPubKey(progress, rpc::scan::g_should_abort, count, cursor.get(), needles, coins, node.rpc_interruption_point)) {
2171
+ return interfaces::ScanResult::SUCCESS;
2167
2172
  }
2168
- };
2173
+ return rpc::scan::g_should_abort ? interfaces::ScanResult::ABORTED : interfaces::ScanResult::UNAVAILABLE;
2174
+ }
2169
2175
 
2170
2176
  static const auto scan_action_arg_desc = RPCArg{
2171
2177
  "action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n"
@@ -2267,24 +2273,24 @@ static RPCHelpMan scantxoutset()
2267
2273
  UniValue result(UniValue::VOBJ);
2268
2274
  const auto action{self.Arg<std::string>("action")};
2269
2275
  if (action == "status") {
2270
- CoinsViewScanReserver reserver;
2276
+ Reserver reserver;
2271
2277
  if (reserver.reserve()) {
2272
2278
  // no scan in progress
2273
2279
  return UniValue::VNULL;
2274
2280
  }
2275
- result.pushKV("progress", g_scan_progress.load());
2281
+ result.pushKV("progress", rpc::scan::g_progress.load());
2276
2282
  return result;
2277
2283
  } else if (action == "abort") {
2278
- CoinsViewScanReserver reserver;
2284
+ Reserver reserver;
2279
2285
  if (reserver.reserve()) {
2280
2286
  // reserve was possible which means no scan was running
2281
2287
  return false;
2282
2288
  }
2283
2289
  // set the abort flag
2284
- g_should_abort_scan = true;
2290
+ rpc::scan::g_should_abort = true;
2285
2291
  return true;
2286
2292
  } else if (action == "start") {
2287
- CoinsViewScanReserver reserver;
2293
+ Reserver reserver;
2288
2294
  if (!reserver.reserve()) {
2289
2295
  throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
2290
2296
  }
@@ -2312,7 +2318,7 @@ static RPCHelpMan scantxoutset()
2312
2318
  UniValue unspents(UniValue::VARR);
2313
2319
  std::vector<CTxOut> input_txos;
2314
2320
  std::map<COutPoint, Coin> coins;
2315
- g_should_abort_scan = false;
2321
+ rpc::scan::g_should_abort = false;
2316
2322
  int64_t count = 0;
2317
2323
  std::unique_ptr<CCoinsViewCursor> pcursor;
2318
2324
  const CBlockIndex* tip;
@@ -2325,7 +2331,7 @@ static RPCHelpMan scantxoutset()
2325
2331
  pcursor = CHECK_NONFATAL(active_chainstate.CoinsDB().Cursor());
2326
2332
  tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
2327
2333
  }
2328
- bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins, node.rpc_interruption_point);
2334
+ bool res = FindScriptPubKey(rpc::scan::g_progress, rpc::scan::g_should_abort, count, pcursor.get(), needles, coins, node.rpc_interruption_point);
2329
2335
  result.pushKV("success", res);
2330
2336
  result.pushKV("txouts", count);
2331
2337
  result.pushKV("height", tip->nHeight);