v29.4-roots.4 · Commit 23: [PATCH 23/37] 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);
|