v29.4-roots.4 · Commit 28: [PATCH 28/37] fix(wallet): secure asynchronous sweep cancellation
src/wallet/spend.cpp
Before: src/wallet/spend.cpp · After: src/wallet/spend.cpp
File metadata
index 8d77de3cc7fcde543d596ea40a31e9cda8b4182a..a49f66462ae827ce70d0403bddb1871f9616dc35 100644
Download original patch · Release notes
Diff rows 1–30 of 30. 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/wallet/spend.cpp
CHANGED
|
@@ -9,6 +9,7 @@
|
|
| 9 |
#include <consensus/amount.h>
|
| 10 |
#include <consensus/validation.h>
|
| 11 |
#include <interfaces/chain.h>
|
|
|
|
| 12 |
#include <node/types.h>
|
| 13 |
#include <numeric>
|
| 14 |
#include <policy/policy.h>
|
|
@@ -44,8 +45,10 @@ TRACEPOINT_SEMAPHORE(coin_selection, aps_create_tx_internal);
|
|
| 44 |
namespace wallet {
|
| 45 |
util::Result<SweepTransactionResult> CreateSweepTransaction(CWallet& wallet, FlatSigningProvider& provider,
|
| 46 |
const std::map<COutPoint, Coin>& coins,
|
| 47 |
-
const CScript& destination, const SweepBroadcastFn& broadcast)
|
|
|
|
| 48 |
{
|
|
|
|
| 49 |
CAmount amount{0};
|
| 50 |
CMutableTransaction tx;
|
| 51 |
for (const auto& [outpoint, coin] : coins) {
|
|
@@ -69,8 +72,12 @@ util::Result<SweepTransactionResult> CreateSweepTransaction(CWallet& wallet, Fla
|
|
| 69 |
return util::Error{Untranslated("Unable to calculate a stable sweep fee")};
|
| 70 |
}
|
| 71 |
if (IsDust(tx.vout[0], wallet.chain().relayMinFee())) return util::Error{Untranslated("Swept output would be dust")};
|
|
|
|
| 72 |
CTransactionRef final_tx{MakeTransactionRef(tx)};
|
| 73 |
if (broadcast) {
|
|
|
|
|
|
|
|
|
|
| 74 |
std::string error;
|
| 75 |
if (!broadcast(final_tx, error)) return util::Error{Untranslated("Sweep transaction broadcast failed: " + error)};
|
| 76 |
}
|
|
|
|
| 9 |
#include <consensus/amount.h>
|
| 10 |
#include <consensus/validation.h>
|
| 11 |
#include <interfaces/chain.h>
|
| 12 |
+
#include <interfaces/wallet.h>
|
| 13 |
#include <node/types.h>
|
| 14 |
#include <numeric>
|
| 15 |
#include <policy/policy.h>
|
|
|
|
| 45 |
namespace wallet {
|
| 46 |
util::Result<SweepTransactionResult> CreateSweepTransaction(CWallet& wallet, FlatSigningProvider& provider,
|
| 47 |
const std::map<COutPoint, Coin>& coins,
|
| 48 |
+
const CScript& destination, const SweepBroadcastFn& broadcast,
|
| 49 |
+
interfaces::SweepAuthorization& authorization)
|
| 50 |
{
|
| 51 |
+
if (authorization.IsCancelled()) return util::Error{Untranslated("Sweep cancelled")};
|
| 52 |
CAmount amount{0};
|
| 53 |
CMutableTransaction tx;
|
| 54 |
for (const auto& [outpoint, coin] : coins) {
|
|
|
|
| 72 |
return util::Error{Untranslated("Unable to calculate a stable sweep fee")};
|
| 73 |
}
|
| 74 |
if (IsDust(tx.vout[0], wallet.chain().relayMinFee())) return util::Error{Untranslated("Swept output would be dust")};
|
| 75 |
+
if (authorization.IsCancelled()) return util::Error{Untranslated("Sweep cancelled")};
|
| 76 |
CTransactionRef final_tx{MakeTransactionRef(tx)};
|
| 77 |
if (broadcast) {
|
| 78 |
+
// This is the last safe cancellation point. BeginBroadcast and Cancel
|
| 79 |
+
// use one atomic state transition, so only one of them can succeed.
|
| 80 |
+
if (!authorization.BeginBroadcast()) return util::Error{Untranslated("Sweep cancelled")};
|
| 81 |
std::string error;
|
| 82 |
if (!broadcast(final_tx, error)) return util::Error{Untranslated("Sweep transaction broadcast failed: " + error)};
|
| 83 |
}
|