Skip to content
Bitcoin Roots

v30.3-roots.1 · Commit 24: [PATCH 24/68] feat(qt): add guarded private key sweep dialog

src/wallet/interfaces.cpp

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

File metadata
index 2f5ce24e3bba68a2da0a00578fdbbf6dedc51664..fe27c0b897c33dd2f5b51857fd891cacd66c0c4e 100644

Download original patch · Release notes

Diff rows 1–65 of 65. 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/interfaces.cpp CHANGED
@@ -29,6 +29,10 @@
29
29
  #include <wallet/spend.h>
30
30
  #include <wallet/wallet.h>
31
31
 
32
+ #include <key_io.h>
33
+ #include <script/solver.h>
34
+ #include <policy/policy.h>
35
+
32
36
  #include <memory>
33
37
  #include <string>
34
38
  #include <utility>
@@ -45,6 +49,7 @@ using interfaces::WalletBalances;
45
49
  using interfaces::WalletLoader;
46
50
  using interfaces::WalletMigrationResult;
47
51
  using interfaces::WalletOrderForm;
52
+ using interfaces::WalletSweepResult;
48
53
  using interfaces::WalletTx;
49
54
  using interfaces::WalletTxOut;
50
55
  using interfaces::WalletTxStatus;
@@ -174,6 +179,48 @@ public:
174
179
  LOCK(m_wallet->cs_wallet);
175
180
  return m_wallet->IsMine(dest);
176
181
  }
182
+ util::Result<WalletSweepResult> sweepPrivateKey(const SecureString& private_key,
183
+ const CTxDestination& destination,
184
+ bool broadcast,
185
+ const std::optional<Txid>& expected_txid) override
186
+ {
187
+ CKey key{DecodeSecret(std::string{private_key.begin(), private_key.end()})};
188
+ if (!key.IsValid()) return util::Error{Untranslated("Invalid private key or wrong network")};
189
+ const CPubKey pubkey{key.GetPubKey()};
190
+ FlatSigningProvider provider;
191
+ provider.keys.emplace(pubkey.GetID(), key);
192
+ provider.pubkeys.emplace(pubkey.GetID(), pubkey);
193
+ std::set<CScript> scan_objects{GetScriptForDestination(PKHash(pubkey))};
194
+ if (pubkey.IsCompressed()) {
195
+ const CScript witness{GetScriptForDestination(WitnessV0KeyHash(pubkey))};
196
+ scan_objects.insert(witness);
197
+ provider.scripts.emplace(CScriptID(witness), witness);
198
+ scan_objects.insert(GetScriptForDestination(ScriptHash(witness)));
199
+ }
200
+ const CScript destination_script{GetScriptForDestination(destination)};
201
+ {
202
+ LOCK(m_wallet->cs_wallet);
203
+ if (m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) || !m_wallet->IsMine(destination_script)) {
204
+ return util::Error{Untranslated("Destination is not controlled by this wallet")};
205
+ }
206
+ }
207
+ std::map<COutPoint, Coin> coins;
208
+ switch (m_wallet->chain().findScriptPubKeys(scan_objects, coins)) {
209
+ case interfaces::ScanResult::SUCCESS: break;
210
+ case interfaces::ScanResult::BUSY: return util::Error{Untranslated("UTXO scan already in progress")};
211
+ case interfaces::ScanResult::ABORTED: return util::Error{Untranslated("UTXO scan aborted")};
212
+ case interfaces::ScanResult::UNAVAILABLE: return util::Error{Untranslated("UTXO scan unavailable")};
213
+ }
214
+ auto swept{CreateSweepTransaction(*m_wallet, provider, coins, destination_script, broadcast ? SweepBroadcastFn{[&, expected_txid](const CTransactionRef& tx, std::string& error) {
215
+ if (expected_txid && tx->GetHash() != *expected_txid) {
216
+ error = "Sweep preview is stale; create a fresh preview";
217
+ return false;
218
+ }
219
+ return m_wallet->chain().broadcastTransaction(tx, m_wallet->m_default_max_tx_fee, /*relay=*/true, error);
220
+ }} : SweepBroadcastFn{})};
221
+ if (!swept) return util::Error{util::ErrorString(swept)};
222
+ return WalletSweepResult{swept->tx, swept->amount, swept->fee, coins.size(), GetVirtualTransactionSize(*swept->tx), broadcast};
223
+ }
177
224
  bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::optional<AddressPurpose>& purpose) override
178
225
  {
179
226
  return m_wallet->SetAddressBook(dest, name, purpose);