Skip to content
Bitcoin Roots

v30.3-roots.1 · Commit 23: [PATCH 23/68] feat(wallet): add transient private-key sweep RPC

src/wallet/spend.cpp

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

File metadata
index f58d9f27ae022e4594642ffc9c633729e2e4800b..086673b5b21323eaecee546b588b696803eb57c4 100644

Download original patch · Release notes

Diff rows 1–47 of 47. 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
@@ -15,6 +15,7 @@
15
  #include <policy/truc_policy.h>
16
  #include <primitives/transaction.h>
17
  #include <primitives/transaction_identifier.h>
 
18
  #include <script/script.h>
19
  #include <script/signingprovider.h>
20
  #include <script/solver.h>
@@ -43,6 +44,40 @@ TRACEPOINT_SEMAPHORE(coin_selection, attempting_aps_create_tx);
43
  TRACEPOINT_SEMAPHORE(coin_selection, aps_create_tx_internal);
44
 
45
  namespace wallet {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  static constexpr size_t OUTPUT_GROUP_MAX_ENTRIES{100};
47
 
48
  /** Whether the descriptor represents, directly or not, a witness program. */
 
15
  #include <policy/truc_policy.h>
16
  #include <primitives/transaction.h>
17
  #include <primitives/transaction_identifier.h>
18
+ #include <rpc/rawtransaction_util.h>
19
  #include <script/script.h>
20
  #include <script/signingprovider.h>
21
  #include <script/solver.h>
 
44
  TRACEPOINT_SEMAPHORE(coin_selection, aps_create_tx_internal);
45
 
46
  namespace wallet {
47
+ util::Result<SweepTransactionResult> CreateSweepTransaction(CWallet& wallet, FlatSigningProvider& provider,
48
+ const std::map<COutPoint, Coin>& coins,
49
+ const CScript& destination, const SweepBroadcastFn& broadcast)
50
+ {
51
+ CAmount amount{0};
52
+ CMutableTransaction tx;
53
+ for (const auto& [outpoint, coin] : coins) {
54
+ amount += coin.out.nValue;
55
+ tx.vin.emplace_back(outpoint);
56
+ }
57
+ if (coins.empty()) return util::Error{Untranslated("No spendable UTXOs found")};
58
+ tx.vout.emplace_back(amount, destination);
59
+ std::map<int, bilingual_str> errors;
60
+ if (!::SignTransaction(tx, &provider, coins, SIGHASH_DEFAULT, errors)) return util::Error{Untranslated("Unable to sign all swept inputs")};
61
+ CAmount fee{0};
62
+ for (int attempts{0}; attempts < 10; ++attempts) {
63
+ fee = GetMinimumFee(wallet, GetVirtualTransactionSize(CTransaction{tx}), CCoinControl{}, nullptr);
64
+ if (fee >= amount) return util::Error{Untranslated("Fee exceeds swept value")};
65
+ tx.vout[0].nValue = amount - fee;
66
+ errors.clear();
67
+ if (!::SignTransaction(tx, &provider, coins, SIGHASH_DEFAULT, errors)) return util::Error{Untranslated("Unable to sign all swept inputs")};
68
+ if (fee >= GetMinimumFee(wallet, GetVirtualTransactionSize(CTransaction{tx}), CCoinControl{}, nullptr)) break;
69
+ }
70
+ if (fee < GetMinimumFee(wallet, GetVirtualTransactionSize(CTransaction{tx}), CCoinControl{}, nullptr)) {
71
+ return util::Error{Untranslated("Unable to calculate a stable sweep fee")};
72
+ }
73
+ if (IsDust(tx.vout[0], wallet.chain().relayMinFee())) return util::Error{Untranslated("Swept output would be dust")};
74
+ CTransactionRef final_tx{MakeTransactionRef(tx)};
75
+ if (broadcast) {
76
+ std::string error;
77
+ if (!broadcast(final_tx, error)) return util::Error{Untranslated("Sweep transaction broadcast failed: " + error)};
78
+ }
79
+ return SweepTransactionResult{final_tx, amount, fee};
80
+ }
81
  static constexpr size_t OUTPUT_GROUP_MAX_ENTRIES{100};
82
 
83
  /** Whether the descriptor represents, directly or not, a witness program. */