v30.3-roots.1 · Commit 23: [PATCH 23/68] 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 a20affafee7400fc9f0fed4f56690eefafb60a3c..b6c5e442293b508c4245b07d47d3a2f2499f4f76 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
|
@@ -2165,8 +2165,7 @@ bool FindScriptPubKey(std::atomic<int>& scan_progress, const std::atomic<bool>&
|
|
|
2165
2165
|
COutPoint key;
|
|
2166
2166
|
Coin coin;
|
|
2167
2167
|
if (!cursor->GetKey(key) || !cursor->GetValue(coin)) return false;
|
|
2168
|
-
if (++count % 8192 == 0) {
|
|
2169
|
-
interruption_point();
|
|
2168
|
+
if (rpc::scan::CheckInterruption(++count, interruption_point)) {
|
|
2170
2169
|
if (should_abort) {
|
|
2171
2170
|
// allow to abort the scan via the abort reference
|
|
2172
2171
|
return false;
|
|
@@ -2188,33 +2187,40 @@ bool FindScriptPubKey(std::atomic<int>& scan_progress, const std::atomic<bool>&
|
|
|
2188
2187
|
} // namespace
|
|
2189
2188
|
|
|
2190
2189
|
/** RAII object to prevent concurrency issue when scanning the txout set */
|
|
2191
|
-
static std::atomic<int> g_scan_progress;
|
|
2192
|
-
static std::atomic<bool> g_scan_in_progress;
|
|
2193
|
-
static std::atomic<bool> g_should_abort_scan;
|
|
2194
|
-
class CoinsViewScanReserver
|
|
2195
|
-
{
|
|
2196
|
-
private:
|
|
2197
|
-
bool m_could_reserve{false};
|
|
2198
|
-
public:
|
|
2199
|
-
explicit CoinsViewScanReserver() = default;
|
|
2190
|
+
std::atomic<int> rpc::scan::g_progress;
|
|
2191
|
+
std::atomic<bool> rpc::scan::g_in_progress;
|
|
2192
|
+
std::atomic<bool> rpc::scan::g_should_abort;
|
|
2193
|
+
bool rpc::scan::Reserver::reserve() {
|
|
2194
|
+
CHECK_NONFATAL(!m_reserved);
|
|
2195
|
+
if (g_in_progress.exchange(true)) return false;
|
|
2196
|
+
CHECK_NONFATAL(g_progress == 0);
|
|
2197
|
+
m_reserved = true;
|
|
2198
|
+
return true;
|
|
2199
|
+
}
|
|
2200
|
+
rpc::scan::Reserver::~Reserver() { if (m_reserved) { g_in_progress = false; g_progress = 0; } }
|
|
2201
|
+
bool rpc::scan::CheckInterruption(int64_t count, const std::function<void()>& interruption) { if (count % 8192 != 0) return false; interruption(); return true; }
|
|
2202
|
+
using rpc::scan::Reserver;
|
|
2200
2203
|
|
|
2201
|
-
bool reserve() {
|
|
2202
|
-
CHECK_NONFATAL(!m_could_reserve);
|
|
2203
|
-
if (g_scan_in_progress.exchange(true)) {
|
|
2204
|
-
return false;
|
|
2205
|
-
}
|
|
2206
|
-
CHECK_NONFATAL(g_scan_progress == 0);
|
|
2207
|
-
m_could_reserve = true;
|
|
2208
|
-
return true;
|
|
2204
|
+
interfaces::ScanResult ScanUTXOSet(NodeContext& node, const std::set<CScript>& needles, std::map<COutPoint, Coin>& coins)
|
|
2205
|
+
{
|
|
2206
|
+
Reserver reserver;
|
|
2207
|
+
if (!reserver.reserve()) return interfaces::ScanResult::BUSY;
|
|
2208
|
+
std::unique_ptr<CCoinsViewCursor> cursor;
|
|
2209
|
+
{
|
|
2210
|
+
ChainstateManager& chainman = EnsureChainman(node);
|
|
2211
|
+
LOCK(cs_main);
|
|
2212
|
+
Chainstate& chainstate = chainman.ActiveChainstate();
|
|
2213
|
+
chainstate.ForceFlushStateToDisk();
|
|
2214
|
+
cursor = CHECK_NONFATAL(chainstate.CoinsDB().Cursor());
|
|
2209
2215
|
}
|
|
2210
|
-
|
|
2211
|
-
~CoinsViewScanReserver() {
|
|
2212
|
-
if (m_could_reserve) {
|
|
2213
|
-
g_scan_in_progress = false;
|
|
2214
|
-
g_scan_progress = 0;
|
|
2215
|
-
}
|
|
2216
|
+
rpc::scan::g_should_abort = false;
|
|
2217
|
+
std::atomic<int> progress;
|
|
2218
|
+
int64_t count;
|
|
2219
|
+
if (FindScriptPubKey(progress, rpc::scan::g_should_abort, count, cursor.get(), needles, coins, node.rpc_interruption_point)) {
|
|
2220
|
+
return interfaces::ScanResult::SUCCESS;
|
|
2216
2221
|
}
|
|
2217
|
-
};
|
|
2222
|
+
return rpc::scan::g_should_abort ? interfaces::ScanResult::ABORTED : interfaces::ScanResult::UNAVAILABLE;
|
|
2223
|
+
}
|
|
2218
2224
|
|
|
2219
2225
|
static const auto scan_action_arg_desc = RPCArg{
|
|
2220
2226
|
"action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n"
|
|
@@ -2321,24 +2327,24 @@ static RPCHelpMan scantxoutset()
|
|
|
2321
2327
|
UniValue result(UniValue::VOBJ);
|
|
2322
2328
|
const auto action{self.Arg<std::string>("action")};
|
|
2323
2329
|
if (action == "status") {
|
|
2324
|
-
CoinsViewScanReserver reserver;
|
|
2330
|
+
Reserver reserver;
|
|
2325
2331
|
if (reserver.reserve()) {
|
|
2326
2332
|
// no scan in progress
|
|
2327
2333
|
return UniValue::VNULL;
|
|
2328
2334
|
}
|
|
2329
|
-
result.pushKV("progress", g_scan_progress.load());
|
|
2335
|
+
result.pushKV("progress", rpc::scan::g_progress.load());
|
|
2330
2336
|
return result;
|
|
2331
2337
|
} else if (action == "abort") {
|
|
2332
|
-
CoinsViewScanReserver reserver;
|
|
2338
|
+
Reserver reserver;
|
|
2333
2339
|
if (reserver.reserve()) {
|
|
2334
2340
|
// reserve was possible which means no scan was running
|
|
2335
2341
|
return false;
|
|
2336
2342
|
}
|
|
2337
2343
|
// set the abort flag
|
|
2338
|
-
g_should_abort_scan = true;
|
|
2344
|
+
rpc::scan::g_should_abort = true;
|
|
2339
2345
|
return true;
|
|
2340
2346
|
} else if (action == "start") {
|
|
2341
|
-
CoinsViewScanReserver reserver;
|
|
2347
|
+
Reserver reserver;
|
|
2342
2348
|
if (!reserver.reserve()) {
|
|
2343
2349
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
|
|
2344
2350
|
}
|
|
@@ -2366,7 +2372,7 @@ static RPCHelpMan scantxoutset()
|
|
|
2366
2372
|
UniValue unspents(UniValue::VARR);
|
|
2367
2373
|
std::vector<CTxOut> input_txos;
|
|
2368
2374
|
std::map<COutPoint, Coin> coins;
|
|
2369
|
-
g_should_abort_scan = false;
|
|
2375
|
+
rpc::scan::g_should_abort = false;
|
|
2370
2376
|
int64_t count = 0;
|
|
2371
2377
|
std::unique_ptr<CCoinsViewCursor> pcursor;
|
|
2372
2378
|
const CBlockIndex* tip;
|
|
@@ -2379,7 +2385,7 @@ static RPCHelpMan scantxoutset()
|
|
|
2379
2385
|
pcursor = CHECK_NONFATAL(active_chainstate.CoinsDB().Cursor());
|
|
2380
2386
|
tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
|
|
2381
2387
|
}
|
|
2382
|
-
bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins, node.rpc_interruption_point);
|
|
2388
|
+
bool res = FindScriptPubKey(rpc::scan::g_progress, rpc::scan::g_should_abort, count, pcursor.get(), needles, coins, node.rpc_interruption_point);
|
|
2383
2389
|
result.pushKV("success", res);
|
|
2384
2390
|
result.pushKV("txouts", count);
|
|
2385
2391
|
result.pushKV("height", tip->nHeight);
|