Branch data Line data Source code
1 : : // Copyright (c) 2010 Satoshi Nakamoto
2 : : // Copyright (c) 2009-2021 The Bitcoin Core developers
3 : : // Distributed under the MIT software license, see the accompanying
4 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 : :
6 : : #include <consensus/validation.h>
7 : : #include <index/txindex.h>
8 : : #include <net.h>
9 : : #include <net_processing.h>
10 : : #include <node/blockstorage.h>
11 : : #include <node/context.h>
12 : : #include <node/types.h>
13 : : #include <txmempool.h>
14 : : #include <validation.h>
15 : : #include <validationinterface.h>
16 : : #include <node/transaction.h>
17 : :
18 : : #include <future>
19 : :
20 : : namespace node {
21 : 0 : static TransactionError HandleATMPError(const TxValidationState& state, std::string& err_string_out)
22 : : {
23 : 0 : err_string_out = state.ToString();
24 [ # # ]: 0 : if (state.IsInvalid()) {
25 [ # # ]: 0 : if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
26 : : return TransactionError::MISSING_INPUTS;
27 : : }
28 : 0 : return TransactionError::MEMPOOL_REJECTED;
29 : : } else {
30 : : return TransactionError::MEMPOOL_ERROR;
31 : : }
32 : : }
33 : :
34 : 5 : TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback)
35 : : {
36 : : // BroadcastTransaction can be called by RPC or by the wallet.
37 : : // chainman, mempool and peerman are initialized before the RPC server and wallet are started
38 : : // and reset after the RPC sever and wallet are stopped.
39 [ - + ]: 5 : assert(node.chainman);
40 [ - + ]: 5 : assert(node.mempool);
41 [ - + ]: 5 : assert(node.peerman);
42 : :
43 : 5 : std::promise<void> promise;
44 [ + - ]: 5 : Txid txid = tx->GetHash();
45 : 5 : uint256 wtxid = tx->GetWitnessHash();
46 : 5 : bool callback_set = false;
47 : :
48 : 5 : {
49 [ + - ]: 5 : LOCK(cs_main);
50 : :
51 : : // If the transaction is already confirmed in the chain, don't do anything
52 : : // and return early.
53 [ + - + - ]: 5 : CCoinsViewCache &view = node.chainman->ActiveChainstate().CoinsTip();
54 [ + + ]: 10 : for (size_t o = 0; o < tx->vout.size(); o++) {
55 [ + - ]: 5 : const Coin& existingCoin = view.AccessCoin(COutPoint(txid, o));
56 : : // IsSpent doesn't mean the coin is spent, it means the output doesn't exist.
57 : : // So if the output does exist, then this transaction exists in the chain.
58 [ + - ]: 5 : if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_UTXO_SET;
59 : : }
60 : :
61 [ + - + + ]: 5 : if (auto mempool_tx = node.mempool->get(txid); mempool_tx) {
62 : : // There's already a transaction in the mempool with this txid. Don't
63 : : // try to submit this transaction to the mempool (since it'll be
64 : : // rejected as a TX_CONFLICT), but do attempt to reannounce the mempool
65 : : // transaction if relay=true.
66 : : //
67 : : // The mempool transaction may have the same or different witness (and
68 : : // wtxid) as this transaction. Use the mempool's wtxid for reannouncement.
69 : 3 : wtxid = mempool_tx->GetWitnessHash();
70 : : } else {
71 : : // Transaction is not already in the mempool.
72 [ + - ]: 2 : if (max_tx_fee > 0) {
73 : : // First, call ATMP with test_accept and check the fee. If ATMP
74 : : // fails here, return error immediately.
75 [ + - ]: 2 : const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/ true);
76 [ - + ]: 2 : if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
77 [ # # ]: 0 : return HandleATMPError(result.m_state, err_string);
78 [ + - + - ]: 2 : } else if (result.m_base_fees.value() > max_tx_fee) {
79 : : return TransactionError::MAX_FEE_EXCEEDED;
80 : : }
81 : 2 : }
82 : : // Try to submit the transaction to the mempool.
83 [ + - ]: 2 : const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/ false);
84 [ - + ]: 2 : if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
85 [ # # ]: 0 : return HandleATMPError(result.m_state, err_string);
86 : : }
87 : :
88 : : // Transaction was accepted to the mempool.
89 : :
90 [ - + ]: 2 : if (relay) {
91 : : // the mempool tracks locally submitted transactions to make a
92 : : // best-effort of initial broadcast
93 [ # # ]: 0 : node.mempool->AddUnbroadcastTx(txid);
94 : : }
95 : :
96 [ - + - - ]: 2 : if (wait_callback && node.validation_signals) {
97 : : // For transactions broadcast from outside the wallet, make sure
98 : : // that the wallet has been notified of the transaction before
99 : : // continuing.
100 : : //
101 : : // This prevents a race where a user might call sendrawtransaction
102 : : // with a transaction to/from their wallet, immediately call some
103 : : // wallet RPC, and get a stale result because callbacks have not
104 : : // yet been processed.
105 [ # # ]: 0 : node.validation_signals->CallFunctionInValidationInterfaceQueue([&promise] {
106 : 0 : promise.set_value();
107 : : });
108 : 0 : callback_set = true;
109 : : }
110 [ + - ]: 7 : }
111 : 0 : } // cs_main
112 : :
113 [ - + ]: 5 : if (callback_set) {
114 : : // Wait until Validation Interface clients have been notified of the
115 : : // transaction entering the mempool.
116 [ # # # # ]: 0 : promise.get_future().wait();
117 : : }
118 : :
119 [ - + ]: 5 : if (relay) {
120 [ # # ]: 0 : node.peerman->RelayTransaction(txid, wtxid);
121 : : }
122 : :
123 : : return TransactionError::OK;
124 : 5 : }
125 : :
126 : 0 : CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, uint256& hashBlock, const BlockManager& blockman)
127 : : {
128 [ # # ]: 0 : if (mempool && !block_index) {
129 : 0 : CTransactionRef ptx = mempool->get(hash);
130 [ # # ]: 0 : if (ptx) return ptx;
131 : 0 : }
132 [ # # ]: 0 : if (g_txindex) {
133 : 0 : CTransactionRef tx;
134 : 0 : uint256 block_hash;
135 [ # # # # ]: 0 : if (g_txindex->FindTx(hash, block_hash, tx)) {
136 [ # # # # ]: 0 : if (!block_index || block_index->GetBlockHash() == block_hash) {
137 : : // Don't return the transaction if the provided block hash doesn't match.
138 : : // The case where a transaction appears in multiple blocks (e.g. reorgs or
139 : : // BIP30) is handled by the block lookup below.
140 : 0 : hashBlock = block_hash;
141 [ # # ]: 0 : return tx;
142 : : }
143 : : }
144 : 0 : }
145 [ # # ]: 0 : if (block_index) {
146 : 0 : CBlock block;
147 [ # # # # ]: 0 : if (blockman.ReadBlockFromDisk(block, *block_index)) {
148 [ # # ]: 0 : for (const auto& tx : block.vtx) {
149 [ # # ]: 0 : if (tx->GetHash() == hash) {
150 : 0 : hashBlock = block_index->GetBlockHash();
151 [ # # ]: 0 : return tx;
152 : : }
153 : : }
154 : : }
155 : 0 : }
156 : 0 : return nullptr;
157 : : }
158 : : } // namespace node
|