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