Skip to content
Bitcoin Roots

v29.4-roots.3 · Commit 28: [PATCH 28/30] 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. 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>
@@ -44,8 +45,10 @@ TRACEPOINT_SEMAPHORE(coin_selection, aps_create_tx_internal);
44
45
  namespace wallet {
45
46
  util::Result<SweepTransactionResult> CreateSweepTransaction(CWallet& wallet, FlatSigningProvider& provider,
46
47
  const std::map<COutPoint, Coin>& coins,
47
- const CScript& destination, const SweepBroadcastFn& broadcast)
48
+ const CScript& destination, const SweepBroadcastFn& broadcast,
49
+ interfaces::SweepAuthorization& authorization)
48
50
  {
51
+ if (authorization.IsCancelled()) return util::Error{Untranslated("Sweep cancelled")};
49
52
  CAmount amount{0};
50
53
  CMutableTransaction tx;
51
54
  for (const auto& [outpoint, coin] : coins) {
@@ -69,8 +72,12 @@ util::Result<SweepTransactionResult> CreateSweepTransaction(CWallet& wallet, Fla
69
72
  return util::Error{Untranslated("Unable to calculate a stable sweep fee")};
70
73
  }
71
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")};
72
76
  CTransactionRef final_tx{MakeTransactionRef(tx)};
73
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")};
74
81
  std::string error;
75
82
  if (!broadcast(final_tx, error)) return util::Error{Untranslated("Sweep transaction broadcast failed: " + error)};
76
83
  }