Skip to content

Commit 5a77abd

Browse files
committed
[style] Clean up BroadcastTransaction()
1 parent 7282d4c commit 5a77abd

File tree

1 file changed

+63
-61
lines changed

1 file changed

+63
-61
lines changed

src/node/transaction.cpp

+63-61
Original file line numberDiff line numberDiff line change
@@ -28,81 +28,83 @@ static TransactionError HandleATMPError(const TxValidationState& state, std::str
2828

2929
TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback)
3030
{
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);
3535
assert(node.mempool);
36+
assert(node.peerman);
37+
3638
std::promise<void> promise;
3739
uint256 txid = tx->GetHash();
3840
uint256 wtxid = tx->GetWitnessHash();
3941
bool callback_set = false;
4042

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.
6779
const MempoolAcceptResult result = AcceptToMemoryPool(node.chainman->ActiveChainstate(), *node.mempool, tx, false /* bypass_limits */,
68-
true /* test_accept */);
80+
false /* test_accept */);
6981
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
7082
return HandleATMPError(result.m_state, err_string);
71-
} else if (result.m_base_fees.value() > max_tx_fee) {
72-
return TransactionError::MAX_FEE_EXCEEDED;
7383
}
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-
}
8184

82-
// Transaction was accepted to the mempool.
85+
// Transaction was accepted to the mempool.
8386

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+
}
8992

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+
}
103107
}
104-
}
105-
106108
} // cs_main
107109

108110
if (callback_set) {

0 commit comments

Comments
 (0)