Skip to content
Bitcoin Roots

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
  }