0diff --git i/src/interfaces/chain.h w/src/interfaces/chain.h
1index 315211ae49..eeb5fef42b 100644
2--- i/src/interfaces/chain.h
3+++ w/src/interfaces/chain.h
4@@ -4,12 +4,13 @@
5
6 #ifndef BITCOIN_INTERFACES_CHAIN_H
7 #define BITCOIN_INTERFACES_CHAIN_H
8
9 #include <blockfilter.h>
10 #include <common/settings.h>
11+#include <node/transaction.h>
12 #include <primitives/transaction.h> // For CTransactionRef
13 #include <util/result.h>
14
15 #include <functional>
16 #include <memory>
17 #include <optional>
18@@ -215,13 +216,13 @@ public:
19 //! [@param](/bitcoin-bitcoin/contributor/param/)[in] broadcast_method Whether to add the transaction to the
20 //! mempool and how/whether to broadcast it.
21 //! [@param](/bitcoin-bitcoin/contributor/param/)[out] err_string Set if an error occurs.
22 //! [@return](/bitcoin-bitcoin/contributor/return/) False if the transaction could not be added due to the fee or for another reason.
23 virtual bool broadcastTransaction(const CTransactionRef& tx,
24 const CAmount& max_tx_fee,
25- TxBroadcastMethod broadcast_method,
26+ node::TxBroadcastMethod broadcast_method,
27 std::string& err_string) = 0;
28
29 //! Calculate mempool ancestor and descendant counts for the given transaction.
30 virtual void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize = nullptr, CAmount* ancestorfees = nullptr) = 0;
31
32 //! For each outpoint, calculate the fee-bumping cost to spend this outpoint at the specified
33diff --git i/src/node/transaction.h w/src/node/transaction.h
34index 75c50bab28..01cdfaf1ff 100644
35--- i/src/node/transaction.h
36+++ w/src/node/transaction.h
37@@ -29,12 +29,26 @@ static const CFeeRate DEFAULT_MAX_RAW_TX_FEE_RATE{COIN / 10};
38 /** Maximum burn value for sendrawtransaction, submitpackage, and testmempoolaccept RPC calls.
39 * By default, a transaction with a burn value higher than this will be rejected
40 * by these RPCs and the GUI. This can be overridden with the maxburnamount argument.
41 */
42 static const CAmount DEFAULT_MAX_BURN_AMOUNT{0};
43
44+/**
45+ * Methods to broadcast a local transaction.
46+ * Used to influence BroadcastTransaction() and its callers.
47+ */
48+enum TxBroadcastMethod : uint8_t {
49+ /// Add the transaction to the mempool and broadcast to all currently connected peers.
50+ ADD_TO_MEMPOOL_AND_BROADCAST_TO_ALL,
51+ /// Add the transaction to the mempool, but don't broadcast to anybody.
52+ ADD_TO_MEMPOOL_NO_BROADCAST,
53+ /// Omit the mempool and directly send the transaction via a few dedicated connections to
54+ /// peers on privacy networks.
55+ NO_MEMPOOL_PRIVATE_BROADCAST,
56+};
57+
58 /**
59 * Submit a transaction to the mempool and (optionally) relay it to all P2P peers.
60 *
61 * Mempool submission can be synchronous (will await mempool entry notification
62 * over the CValidationInterface) or asynchronous (will submit and not wait for
63 * notification), depending on the value of wait_callback. wait_callback MUST
64diff --git i/src/primitives/transaction.h w/src/primitives/transaction.h
65index 2051ebae5a..ccbeb3ec49 100644
66--- i/src/primitives/transaction.h
67+++ w/src/primitives/transaction.h
68@@ -436,21 +436,7 @@ public:
69 bool IsWtxid() const { return m_is_wtxid; }
70 const uint256& GetHash() const LIFETIMEBOUND { return m_hash; }
71 friend bool operator==(const GenTxid& a, const GenTxid& b) { return a.m_is_wtxid == b.m_is_wtxid && a.m_hash == b.m_hash; }
72 friend bool operator<(const GenTxid& a, const GenTxid& b) { return std::tie(a.m_is_wtxid, a.m_hash) < std::tie(b.m_is_wtxid, b.m_hash); }
73 };
74
75-/**
76- * Methods to broadcast a local transaction.
77- * Used to influence BroadcastTransaction() and its callers.
78- */
79-enum TxBroadcastMethod : uint8_t {
80- /// Add the transaction to the mempool and broadcast to all currently connected peers.
81- ADD_TO_MEMPOOL_AND_BROADCAST_TO_ALL,
82- /// Add the transaction to the mempool, but don't broadcast to anybody.
83- ADD_TO_MEMPOOL_NO_BROADCAST,
84- /// Omit the mempool and directly send the transaction via a few dedicated connections to
85- /// peers on privacy networks.
86- NO_MEMPOOL_PRIVATE_BROADCAST,
87-};
88-
89 #endif // BITCOIN_PRIMITIVES_TRANSACTION_H
90diff --git i/src/rpc/mempool.cpp w/src/rpc/mempool.cpp
91index 14d303a0b1..ba69446f36 100644
92--- i/src/rpc/mempool.cpp
93+++ w/src/rpc/mempool.cpp
94@@ -8,12 +8,13 @@
95 #include <kernel/mempool_persist.h>
96
97 #include <chainparams.h>
98 #include <core_io.h>
99 #include <kernel/mempool_entry.h>
100 #include <node/mempool_persist_args.h>
101+#include <node/transaction.h>
102 #include <policy/rbf.h>
103 #include <policy/settings.h>
104 #include <primitives/transaction.h>
105 #include <rpc/server.h>
106 #include <rpc/server_util.h>
107 #include <rpc/util.h>
108@@ -91,13 +92,13 @@ static RPCHelpMan sendrawtransaction()
109 AssertLockNotHeld(cs_main);
110 NodeContext& node = EnsureAnyNodeContext(request.context);
111 const TransactionError err = BroadcastTransaction(node,
112 tx,
113 err_string,
114 max_raw_tx_fee,
115- ADD_TO_MEMPOOL_AND_BROADCAST_TO_ALL,
116+ node::ADD_TO_MEMPOOL_AND_BROADCAST_TO_ALL,
117 /*wait_callback=*/true);
118 if (TransactionError::OK != err) {
119 throw JSONRPCTransactionError(err, err_string);
120 }
121
122 return tx->GetHash().GetHex();
123@@ -953,13 +954,13 @@ static RPCHelpMan submitpackage()
124 // We do not expect an error here; we are only broadcasting things already/still in mempool
125 std::string err_string;
126 const auto err = BroadcastTransaction(node,
127 tx,
128 err_string,
129 /*max_tx_fee=*/0,
130- ADD_TO_MEMPOOL_AND_BROADCAST_TO_ALL,
131+ node::ADD_TO_MEMPOOL_AND_BROADCAST_TO_ALL,
132 /*wait_callback=*/true);
133 if (err != TransactionError::OK) {
134 throw JSONRPCTransactionError(err,
135 strprintf("transaction broadcast failed: %s (%d transactions were broadcast successfully)",
136 err_string, num_broadcast));
137 }
138diff --git i/src/wallet/rpc/backup.cpp w/src/wallet/rpc/backup.cpp
139index fdbd44ffe5..2e61a0e945 100644
140--- i/src/wallet/rpc/backup.cpp
141+++ w/src/wallet/rpc/backup.cpp
142@@ -10,12 +10,13 @@
143 #include <clientversion.h>
144 #include <core_io.h>
145 #include <hash.h>
146 #include <interfaces/chain.h>
147 #include <key_io.h>
148 #include <merkleblock.h>
149+#include <node/transaction.h>
150 #include <rpc/util.h>
151 #include <script/descriptor.h>
152 #include <script/script.h>
153 #include <script/solver.h>
154 #include <sync.h>
155 #include <uint256.h>
156@@ -308,13 +309,13 @@ RPCHelpMan importaddress()
157 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script");
158 }
159 }
160 if (fRescan)
161 {
162 RescanWallet(*pwallet, reserver);
163- pwallet->ResubmitWalletTransactions(ADD_TO_MEMPOOL_NO_BROADCAST, /*force=*/true);
164+ pwallet->ResubmitWalletTransactions(node::ADD_TO_MEMPOOL_NO_BROADCAST, /*force=*/true);
165 }
166
167 return UniValue::VNULL;
168 },
169 };
170 }
171@@ -479,13 +480,13 @@ RPCHelpMan importpubkey()
172
173 pwallet->ImportPubKeys({pubKey.GetID()}, {{pubKey.GetID(), pubKey}} , /*key_origins=*/{}, /*add_keypool=*/false, /*internal=*/false, /*timestamp=*/1);
174 }
175 if (fRescan)
176 {
177 RescanWallet(*pwallet, reserver);
178- pwallet->ResubmitWalletTransactions(ADD_TO_MEMPOOL_NO_BROADCAST, /*force=*/true);
179+ pwallet->ResubmitWalletTransactions(node::ADD_TO_MEMPOOL_NO_BROADCAST, /*force=*/true);
180 }
181
182 return UniValue::VNULL;
183 },
184 };
185 }
186@@ -1400,13 +1401,13 @@ RPCHelpMan importmulti()
187 nLowestTimestamp = timestamp;
188 }
189 }
190 }
191 if (fRescan && fRunScan && requests.size()) {
192 int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver, /*update=*/true);
193- pwallet->ResubmitWalletTransactions(ADD_TO_MEMPOOL_NO_BROADCAST, /*force=*/true);
194+ pwallet->ResubmitWalletTransactions(node::ADD_TO_MEMPOOL_NO_BROADCAST, /*force=*/true);
195
196 if (pwallet->IsAbortingRescan()) {
197 throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted by user.");
198 }
199 if (scannedTime > nLowestTimestamp) {
200 std::vector<UniValue> results = response.getValues();
201@@ -1694,13 +1695,13 @@ RPCHelpMan importdescriptors()
202 pwallet->ConnectScriptPubKeyManNotifiers();
203 }
204
205 // Rescan the blockchain using the lowest timestamp
206 if (rescan) {
207 int64_t scanned_time = pwallet->RescanFromTime(lowest_timestamp, reserver, /*update=*/true);
208- pwallet->ResubmitWalletTransactions(ADD_TO_MEMPOOL_NO_BROADCAST, /*force=*/true);
209+ pwallet->ResubmitWalletTransactions(node::ADD_TO_MEMPOOL_NO_BROADCAST, /*force=*/true);
210
211 if (pwallet->IsAbortingRescan()) {
212 throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted by user.");
213 }
214
215 if (scanned_time > lowest_timestamp) {
216diff --git i/src/wallet/test/wallet_tests.cpp w/src/wallet/test/wallet_tests.cpp
217index 003d1aab29..2377c71e21 100644
218--- i/src/wallet/test/wallet_tests.cpp
219+++ w/src/wallet/test/wallet_tests.cpp
220@@ -10,12 +10,13 @@
221 #include <vector>
222
223 #include <addresstype.h>
224 #include <interfaces/chain.h>
225 #include <key_io.h>
226 #include <node/blockstorage.h>
227+#include <node/transaction.h>
228 #include <policy/policy.h>
229 #include <rpc/server.h>
230 #include <script/solver.h>
231 #include <test/util/logging.h>
232 #include <test/util/random.h>
233 #include <test/util/setup_common.h>
234@@ -819,13 +820,13 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup)
235 });
236 std::string error;
237 m_coinbase_txns.push_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
238 auto block_tx = TestSimpleSpend(*m_coinbase_txns[0], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
239 m_coinbase_txns.push_back(CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
240 auto mempool_tx = TestSimpleSpend(*m_coinbase_txns[1], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
241- BOOST_CHECK(m_node.chain->broadcastTransaction(MakeTransactionRef(mempool_tx), DEFAULT_TRANSACTION_MAXFEE, ADD_TO_MEMPOOL_NO_BROADCAST, error));
242+ BOOST_CHECK(m_node.chain->broadcastTransaction(MakeTransactionRef(mempool_tx), DEFAULT_TRANSACTION_MAXFEE, node::ADD_TO_MEMPOOL_NO_BROADCAST, error));
243
244
245 // Reload wallet and make sure new transactions are detected despite events
246 // being blocked
247 // Loading will also ask for current mempool transactions
248 wallet = TestLoadWallet(context);
249@@ -861,13 +862,13 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup)
250 auto handler = HandleLoadWallet(context, [&](std::unique_ptr<interfaces::Wallet> wallet) {
251 BOOST_CHECK(rescan_completed);
252 m_coinbase_txns.push_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
253 block_tx = TestSimpleSpend(*m_coinbase_txns[2], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
254 m_coinbase_txns.push_back(CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
255 mempool_tx = TestSimpleSpend(*m_coinbase_txns[3], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
256- BOOST_CHECK(m_node.chain->broadcastTransaction(MakeTransactionRef(mempool_tx), DEFAULT_TRANSACTION_MAXFEE, ADD_TO_MEMPOOL_NO_BROADCAST, error));
257+ BOOST_CHECK(m_node.chain->broadcastTransaction(MakeTransactionRef(mempool_tx), DEFAULT_TRANSACTION_MAXFEE, node::ADD_TO_MEMPOOL_NO_BROADCAST, error));
258 m_node.validation_signals->SyncWithValidationInterfaceQueue();
259 });
260 wallet = TestLoadWallet(context);
261 // Since mempool transactions are requested at the end of loading, there will
262 // be 2 additional AddToWallet calls, one from the previous test, and a duplicate for mempool_tx
263 BOOST_CHECK_EQUAL(addtx_count, 2 + 2);
264diff --git i/src/wallet/wallet.cpp w/src/wallet/wallet.cpp
265index 0904399926..2566b2d543 100644
266--- i/src/wallet/wallet.cpp
267+++ w/src/wallet/wallet.cpp
268@@ -24,12 +24,13 @@
269 #include <interfaces/wallet.h>
270 #include <kernel/chain.h>
271 #include <kernel/mempool_removal_reason.h>
272 #include <key.h>
273 #include <key_io.h>
274 #include <logging.h>
275+#include <node/transaction.h>
276 #include <outputtype.h>
277 #include <policy/feerate.h>
278 #include <primitives/block.h>
279 #include <primitives/transaction.h>
280 #include <psbt.h>
281 #include <pubkey.h>
282@@ -1999,13 +2000,13 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
283 }
284 return result;
285 }
286
287 bool CWallet::SubmitTxMemoryPoolAndRelay(CWalletTx& wtx,
288 std::string& err_string,
289- TxBroadcastMethod broadcast_method) const
290+ node::TxBroadcastMethod broadcast_method) const
291 {
292 AssertLockHeld(cs_wallet);
293
294 // Can't relay if wallet is not broadcasting
295 if (!GetBroadcastTransactions()) return false;
296 // Don't relay abandoned transactions
297@@ -2016,19 +2017,19 @@ bool CWallet::SubmitTxMemoryPoolAndRelay(CWalletTx& wtx,
298 // Don't try to submit conflicted or confirmed transactions.
299 if (GetTxDepthInMainChain(wtx) != 0) return false;
300
301 // Submit transaction to mempool for relay
302 const char* what{""};
303 switch (broadcast_method) {
304- case ADD_TO_MEMPOOL_AND_BROADCAST_TO_ALL:
305+ case node::ADD_TO_MEMPOOL_AND_BROADCAST_TO_ALL:
306 what = "to mempool and for broadcast to all peers";
307 break;
308- case ADD_TO_MEMPOOL_NO_BROADCAST:
309+ case node::ADD_TO_MEMPOOL_NO_BROADCAST:
310 what = "to mempool without broadcast";
311 break;
312- case NO_MEMPOOL_PRIVATE_BROADCAST:
313+ case node::NO_MEMPOOL_PRIVATE_BROADCAST:
314 what = "for private broadcast without adding to the mempool";
315 break;
316 }
317 WalletLogPrintf("Submitting wtx %s %s\n", wtx.GetHash().ToString(), what);
318 // We must set TxStateInMempool here. Even though it will also be set later by the
319 // entered-mempool callback, if we did not there would be a race where a
320@@ -2095,13 +2096,13 @@ NodeClock::time_point CWallet::GetDefaultNextResend() { return FastRandomContext
321 // The `force` option results in all unconfirmed transactions being submitted to
322 // the mempool. This does not necessarily result in those transactions being relayed,
323 // that depends on the `broadcast_method` option. Periodic rebroadcast uses the pattern
324 // broadcast_method=ADD_TO_MEMPOOL_AND_BROADCAST_TO_ALL force=false, while loading into
325 // the mempool (on start, or after import) uses
326 // broadcast_method=ADD_TO_MEMPOOL_NO_BROADCAST force=true.
327-void CWallet::ResubmitWalletTransactions(TxBroadcastMethod broadcast_method, bool force)
328+void CWallet::ResubmitWalletTransactions(node::TxBroadcastMethod broadcast_method, bool force)
329 {
330 // Don't attempt to resubmit if the wallet is configured to not broadcast,
331 // even if forcing.
332 if (!fBroadcastTransactions) return;
333
334 int submitted_tx_count = 0;
335@@ -2136,13 +2137,13 @@ void CWallet::ResubmitWalletTransactions(TxBroadcastMethod broadcast_method, boo
336 /** @} */ // end of mapWallet
337
338 void MaybeResendWalletTxs(WalletContext& context)
339 {
340 for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
341 if (!pwallet->ShouldResend()) continue;
342- pwallet->ResubmitWalletTransactions(ADD_TO_MEMPOOL_AND_BROADCAST_TO_ALL, /*force=*/false);
343+ pwallet->ResubmitWalletTransactions(node::ADD_TO_MEMPOOL_AND_BROADCAST_TO_ALL, /*force=*/false);
344 pwallet->SetNextResend();
345 }
346 }
347
348
349 /** [@defgroup](/bitcoin-bitcoin/contributor/defgroup/) Actions
350@@ -2344,13 +2345,13 @@ void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
351 if (!fBroadcastTransactions) {
352 // Don't submit tx to the mempool
353 return;
354 }
355
356 std::string err_string;
357- if (!SubmitTxMemoryPoolAndRelay(*wtx, err_string, ADD_TO_MEMPOOL_AND_BROADCAST_TO_ALL)) {
358+ if (!SubmitTxMemoryPoolAndRelay(*wtx, err_string, node::ADD_TO_MEMPOOL_AND_BROADCAST_TO_ALL)) {
359 WalletLogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string);
360 // TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
361 }
362 }
363
364 DBErrors CWallet::LoadWallet()
365@@ -3389,13 +3390,13 @@ bool CWallet::UpgradeWallet(int version, bilingual_str& error)
366 }
367
368 void CWallet::postInitProcess()
369 {
370 // Add wallet transactions that aren't already in a block to mempool
371 // Do this here as mempool requires genesis block to be loaded
372- ResubmitWalletTransactions(ADD_TO_MEMPOOL_NO_BROADCAST, /*force=*/true);
373+ ResubmitWalletTransactions(node::ADD_TO_MEMPOOL_NO_BROADCAST, /*force=*/true);
374
375 // Update wallet transactions with current mempool transactions.
376 WITH_LOCK(cs_wallet, chain().requestMempoolTransactions(*this));
377 }
378
379 bool CWallet::BackupWallet(const std::string& strDest) const
380diff --git i/src/wallet/wallet.h w/src/wallet/wallet.h
381index 8f9881c304..ceadabf165 100644
382--- i/src/wallet/wallet.h
383+++ w/src/wallet/wallet.h
384@@ -9,12 +9,13 @@
385 #include <addresstype.h>
386 #include <consensus/amount.h>
387 #include <interfaces/chain.h>
388 #include <interfaces/handler.h>
389 #include <kernel/cs_main.h>
390 #include <logging.h>
391+#include <node/transaction.h>
392 #include <outputtype.h>
393 #include <policy/feerate.h>
394 #include <primitives/transaction.h>
395 #include <script/interpreter.h>
396 #include <script/script.h>
397 #include <support/allocators/secure.h>
398@@ -631,13 +632,13 @@ public:
399 ScanResult ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate, const bool save_progress);
400 void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) override;
401 /** Set the next time this wallet should resend transactions to 12-36 hours from now, ~1 day on average. */
402 void SetNextResend() { m_next_resend = GetDefaultNextResend(); }
403 /** Return true if all conditions for periodically resending transactions are met. */
404 bool ShouldResend() const;
405- void ResubmitWalletTransactions(TxBroadcastMethod broadcast_method, bool force);
406+ void ResubmitWalletTransactions(node::TxBroadcastMethod broadcast_method, bool force);
407
408 OutputType TransactionChangeType(const std::optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend) const;
409
410 /** Fetch the inputs and sign with SIGHASH_ALL. */
411 bool SignTransaction(CMutableTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
412 /** Sign the tx given the input coins and sighash. */
413@@ -676,13 +677,13 @@ public:
414 * [@param](/bitcoin-bitcoin/contributor/param/)[in] mapValue key-values to be set on the transaction.
415 * [@param](/bitcoin-bitcoin/contributor/param/)[in] orderForm BIP 70 / BIP 21 order form details to be set on the transaction.
416 */
417 void CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm);
418
419 /** Pass this transaction to node for optional mempool insertion and relay to peers. */
420- bool SubmitTxMemoryPoolAndRelay(CWalletTx& wtx, std::string& err_string, TxBroadcastMethod broadcast_method) const
421+ bool SubmitTxMemoryPoolAndRelay(CWalletTx& wtx, std::string& err_string, node::TxBroadcastMethod broadcast_method) const
422 EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
423
424 bool ImportScripts(const std::set<CScript> scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
425 bool ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
426 bool ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
427 bool ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);