@@ -28,81 +28,83 @@ static TransactionError HandleATMPError(const TxValidationState& state, std::str
28
28
29
29
TransactionError BroadcastTransaction (NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback)
30
30
{
31
- // BroadcastTransaction can be called by either sendrawtransaction RPC or wallet RPCs .
32
- // node.peerman is assigned both before chain clients and before RPC server is accepting calls,
33
- // and reset after chain clients and RPC sever are stopped. node.peerman should never be null here .
34
- assert (node.peerman );
31
+ // BroadcastTransaction can be called by either sendrawtransaction RPC or the wallet .
32
+ // chainman, mempool and peerman are initialized before the RPC server and wallet are started
33
+ // and reset after the RPC sever and wallet are stopped .
34
+ assert (node.chainman );
35
35
assert (node.mempool );
36
+ assert (node.peerman );
37
+
36
38
std::promise<void > promise;
37
39
uint256 txid = tx->GetHash ();
38
40
uint256 wtxid = tx->GetWitnessHash ();
39
41
bool callback_set = false ;
40
42
41
- { // cs_main scope
42
- assert (node.chainman );
43
- LOCK (cs_main);
44
- // If the transaction is already confirmed in the chain, don't do anything
45
- // and return early.
46
- CCoinsViewCache &view = node.chainman ->ActiveChainstate ().CoinsTip ();
47
- for (size_t o = 0 ; o < tx->vout .size (); o++) {
48
- const Coin& existingCoin = view.AccessCoin (COutPoint (txid, o));
49
- // IsSpent doesn't mean the coin is spent, it means the output doesn't exist.
50
- // So if the output does exist, then this transaction exists in the chain.
51
- if (!existingCoin.IsSpent ()) return TransactionError::ALREADY_IN_CHAIN;
52
- }
53
- if (auto mempool_tx = node.mempool ->get (txid); mempool_tx) {
54
- // There's already a transaction in the mempool with this txid. Don't
55
- // try to submit this transaction to the mempool (since it'll be
56
- // rejected as a TX_CONFLICT), but do attempt to reannounce the mempool
57
- // transaction if relay=true.
58
- //
59
- // The mempool transaction may have the same or different witness (and
60
- // wtxid) as this transaction. Use the mempool's wtxid for reannouncement.
61
- wtxid = mempool_tx->GetWitnessHash ();
62
- } else {
63
- // Transaction is not already in the mempool.
64
- if (max_tx_fee > 0 ) {
65
- // First, call ATMP with test_accept and check the fee. If ATMP
66
- // fails here, return error immediately.
43
+ {
44
+ LOCK (cs_main);
45
+
46
+ // If the transaction is already confirmed in the chain, don't do anything
47
+ // and return early.
48
+ CCoinsViewCache &view = node.chainman ->ActiveChainstate ().CoinsTip ();
49
+ for (size_t o = 0 ; o < tx->vout .size (); o++) {
50
+ const Coin& existingCoin = view.AccessCoin (COutPoint (txid, o));
51
+ // IsSpent doesn't mean the coin is spent, it means the output doesn't exist.
52
+ // So if the output does exist, then this transaction exists in the chain.
53
+ if (!existingCoin.IsSpent ()) return TransactionError::ALREADY_IN_CHAIN;
54
+ }
55
+
56
+ if (auto mempool_tx = node.mempool ->get (txid); mempool_tx) {
57
+ // There's already a transaction in the mempool with this txid. Don't
58
+ // try to submit this transaction to the mempool (since it'll be
59
+ // rejected as a TX_CONFLICT), but do attempt to reannounce the mempool
60
+ // transaction if relay=true.
61
+ //
62
+ // The mempool transaction may have the same or different witness (and
63
+ // wtxid) as this transaction. Use the mempool's wtxid for reannouncement.
64
+ wtxid = mempool_tx->GetWitnessHash ();
65
+ } else {
66
+ // Transaction is not already in the mempool.
67
+ if (max_tx_fee > 0 ) {
68
+ // First, call ATMP with test_accept and check the fee. If ATMP
69
+ // fails here, return error immediately.
70
+ const MempoolAcceptResult result = AcceptToMemoryPool (node.chainman ->ActiveChainstate (), *node.mempool , tx, false /* bypass_limits */ ,
71
+ true /* test_accept */ );
72
+ if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
73
+ return HandleATMPError (result.m_state , err_string);
74
+ } else if (result.m_base_fees .value () > max_tx_fee) {
75
+ return TransactionError::MAX_FEE_EXCEEDED;
76
+ }
77
+ }
78
+ // Try to submit the transaction to the mempool.
67
79
const MempoolAcceptResult result = AcceptToMemoryPool (node.chainman ->ActiveChainstate (), *node.mempool , tx, false /* bypass_limits */ ,
68
- true /* test_accept */ );
80
+ false /* test_accept */ );
69
81
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
70
82
return HandleATMPError (result.m_state , err_string);
71
- } else if (result.m_base_fees .value () > max_tx_fee) {
72
- return TransactionError::MAX_FEE_EXCEEDED;
73
83
}
74
- }
75
- // Try to submit the transaction to the mempool.
76
- const MempoolAcceptResult result = AcceptToMemoryPool (node.chainman ->ActiveChainstate (), *node.mempool , tx, false /* bypass_limits */ ,
77
- false /* test_accept */ );
78
- if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
79
- return HandleATMPError (result.m_state , err_string);
80
- }
81
84
82
- // Transaction was accepted to the mempool.
85
+ // Transaction was accepted to the mempool.
83
86
84
- if (relay) {
85
- // the mempool tracks locally submitted transactions to make a
86
- // best-effort of initial broadcast
87
- node.mempool ->AddUnbroadcastTx (txid);
88
- }
87
+ if (relay) {
88
+ // the mempool tracks locally submitted transactions to make a
89
+ // best-effort of initial broadcast
90
+ node.mempool ->AddUnbroadcastTx (txid);
91
+ }
89
92
90
- if (wait_callback) {
91
- // For transactions broadcast from outside the wallet, make sure
92
- // that the wallet has been notified of the transaction before
93
- // continuing.
94
- //
95
- // This prevents a race where a user might call sendrawtransaction
96
- // with a transaction to/from their wallet, immediately call some
97
- // wallet RPC, and get a stale result because callbacks have not
98
- // yet been processed.
99
- CallFunctionInValidationInterfaceQueue ([&promise] {
100
- promise.set_value ();
101
- });
102
- callback_set = true ;
93
+ if (wait_callback) {
94
+ // For transactions broadcast from outside the wallet, make sure
95
+ // that the wallet has been notified of the transaction before
96
+ // continuing.
97
+ //
98
+ // This prevents a race where a user might call sendrawtransaction
99
+ // with a transaction to/from their wallet, immediately call some
100
+ // wallet RPC, and get a stale result because callbacks have not
101
+ // yet been processed.
102
+ CallFunctionInValidationInterfaceQueue ([&promise] {
103
+ promise.set_value ();
104
+ });
105
+ callback_set = true ;
106
+ }
103
107
}
104
- }
105
-
106
108
} // cs_main
107
109
108
110
if (callback_set) {
0 commit comments