Skip to content

Commit fb62f12

Browse files
jnewberyAntoine Riard
authored andcommitted
Tidy up BroadcastTransaction()
1 parent b8eecf8 commit fb62f12

File tree

2 files changed

+30
-16
lines changed

2 files changed

+30
-16
lines changed

src/node/transaction.cpp

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,17 @@ TransactionError BroadcastTransaction(const CTransactionRef tx, std::string& err
2323

2424
{ // cs_main scope
2525
LOCK(cs_main);
26+
// If the transaction is already confirmed in the chain, don't do anything
27+
// and return early.
2628
CCoinsViewCache &view = *pcoinsTip;
27-
bool fHaveChain = false;
28-
for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {
29+
for (size_t o = 0; o < tx->vout.size(); o++) {
2930
const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
30-
fHaveChain = !existingCoin.IsSpent();
31+
// IsSpent doesnt mean the coin is spent, it means the output doesnt' exist.
32+
// So if the output does exist, then this transaction exists in the chain.
33+
if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_CHAIN;
3134
}
32-
bool fHaveMempool = mempool.exists(hashTx);
33-
if (!fHaveMempool && !fHaveChain) {
34-
// push to local node and sync with wallets
35+
if (!mempool.exists(hashTx)) {
36+
// Transaction is not already in the mempool. Submit it.
3537
CValidationState state;
3638
bool fMissingInputs;
3739
if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs,
@@ -46,24 +48,31 @@ TransactionError BroadcastTransaction(const CTransactionRef tx, std::string& err
4648
err_string = FormatStateMessage(state);
4749
return TransactionError::MEMPOOL_ERROR;
4850
}
49-
} else if (wait_callback) {
50-
// If wallet is enabled, ensure that the wallet has been made aware
51-
// of the new transaction prior to returning. This prevents a race
52-
// where a user might call sendrawtransaction with a transaction
53-
// to/from their wallet, immediately call some wallet RPC, and get
54-
// a stale result because callbacks have not yet been processed.
51+
}
52+
53+
// Transaction was accepted to the mempool.
54+
55+
if (wait_callback) {
56+
// For transactions broadcast from outside the wallet, make sure
57+
// that the wallet has been notified of the transaction before
58+
// continuing.
59+
//
60+
// This prevents a race where a user might call sendrawtransaction
61+
// with a transaction to/from their wallet, immediately call some
62+
// wallet RPC, and get a stale result because callbacks have not
63+
// yet been processed.
5564
CallFunctionInValidationInterfaceQueue([&promise] {
5665
promise.set_value();
5766
});
5867
callback_set = true;
5968
}
60-
} else if (fHaveChain) {
61-
return TransactionError::ALREADY_IN_CHAIN;
6269
}
6370

6471
} // cs_main
6572

6673
if (callback_set) {
74+
// Wait until Validation Interface clients have been notified of the
75+
// transaction entering the mempool.
6776
promise.get_future().wait();
6877
}
6978

src/node/transaction.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,19 @@
1111
#include <util/error.h>
1212

1313
/**
14-
* Broadcast a transaction
14+
* Submit a transaction to the mempool and (optionally) relay it to all P2P peers.
15+
*
16+
* Mempool submission can be synchronous (will await mempool entry notification
17+
* over the CValidationInterface) or asynchronous (will submit and not wait for
18+
* notification), depending on the value of wait_callback. wait_callback MUST
19+
* NOT be set while cs_main, cs_mempool or cs_wallet are held to avoid
20+
* deadlock.
1521
*
1622
* @param[in] tx the transaction to broadcast
1723
* @param[out] &err_string reference to std::string to fill with error string if available
1824
* @param[in] max_tx_fee reject txs with fees higher than this (if 0, accept any fee)
1925
* @param[in] relay flag if both mempool insertion and p2p relay are requested
2026
* @param[in] wait_callback, wait until callbacks have been processed to avoid stale result due to a sequentially RPC.
21-
* It MUST NOT be set while cs_main, cs_mempool or cs_wallet are held to avoid deadlock
2227
* return error
2328
*/
2429
NODISCARD TransactionError BroadcastTransaction(CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback);

0 commit comments

Comments
 (0)