Skip to content
Bitcoin Roots

v30.3-roots.1 · Commit 28: [PATCH 28/68] fix(wallet): secure asynchronous sweep cancellation

src/wallet/spend.cpp

Before: src/wallet/spend.cpp · After: src/wallet/spend.cpp

File metadata
index 086673b5b21323eaecee546b588b696803eb57c4..587575b2d2c582aef54b8a865918fe32995bdc5d 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. The two line-number columns refer to before and after.

src/wallet/spend.cpp CHANGED
@@ -9,6 +9,7 @@
9
9
  #include <consensus/amount.h>
10
10
  #include <consensus/validation.h>
11
11
  #include <interfaces/chain.h>
12
+ #include <interfaces/wallet.h>
12
13
  #include <node/types.h>
13
14
  #include <numeric>
14
15
  #include <policy/policy.h>
@@ -46,8 +47,10 @@ TRACEPOINT_SEMAPHORE(coin_selection, aps_create_tx_internal);
46
47
  namespace wallet {
47
48
  util::Result<SweepTransactionResult> CreateSweepTransaction(CWallet& wallet, FlatSigningProvider& provider,
48
49
  const std::map<COutPoint, Coin>& coins,
49
- const CScript& destination, const SweepBroadcastFn& broadcast)
50
+ const CScript& destination, const SweepBroadcastFn& broadcast,
51
+ interfaces::SweepAuthorization& authorization)
50
52
  {
53
+ if (authorization.IsCancelled()) return util::Error{Untranslated("Sweep cancelled")};
51
54
  CAmount amount{0};
52
55
  CMutableTransaction tx;
53
56
  for (const auto& [outpoint, coin] : coins) {
@@ -71,8 +74,12 @@ util::Result<SweepTransactionResult> CreateSweepTransaction(CWallet& wallet, Fla
71
74
  return util::Error{Untranslated("Unable to calculate a stable sweep fee")};
72
75
  }
73
76
  if (IsDust(tx.vout[0], wallet.chain().relayMinFee())) return util::Error{Untranslated("Swept output would be dust")};
77
+ if (authorization.IsCancelled()) return util::Error{Untranslated("Sweep cancelled")};
74
78
  CTransactionRef final_tx{MakeTransactionRef(tx)};
75
79
  if (broadcast) {
80
+ // This is the last safe cancellation point. BeginBroadcast and Cancel
81
+ // use one atomic state transition, so only one of them can succeed.
82
+ if (!authorization.BeginBroadcast()) return util::Error{Untranslated("Sweep cancelled")};
76
83
  std::string error;
77
84
  if (!broadcast(final_tx, error)) return util::Error{Untranslated("Sweep transaction broadcast failed: " + error)};
78
85
  }