1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2021 The Limenka 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 static TransactionError HandleATMPError(const TxValidationState& state, std::string& err_string_out)
22 {
23 err_string_out = state.ToString();
24 if (state.IsInvalid()) {
25 if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
26 return TransactionError::MISSING_INPUTS;
27 }
28 return TransactionError::MEMPOOL_REJECTED;
29 } else {
30 return TransactionError::MEMPOOL_ERROR;
31 }
32 }
33 34 TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const std::variant<CAmount, CFeeRate>& max_tx_fee, bool relay, bool wait_callback, const ignore_rejects_type& ignore_rejects)
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 assert(node.chainman);
40 assert(node.mempool);
41 assert(node.peerman);
42 43 std::promise<void> promise;
44 Txid txid = tx->GetHash();
45 uint256 wtxid = tx->GetWitnessHash();
46 bool callback_set = false;
47 48 {
49 LOCK(cs_main);
50 51 // If the transaction is already confirmed in the chain, don't do anything
52 // and return early.
53 CCoinsViewCache &view = node.chainman->ActiveChainstate().CoinsTip();
54 for (size_t o = 0; o < tx->vout.size(); o++) {
55 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 if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_UTXO_SET;
59 }
60 61 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 wtxid = mempool_tx->GetWitnessHash();
70 } else {
71 // Transaction is not already in the mempool.
72 bool max_tx_fee_set{(std::holds_alternative<CAmount>(max_tx_fee) ? std::get<CAmount>(max_tx_fee) : std::get<CFeeRate>(max_tx_fee).GetFeePerK()) > 0};
73 if (ignore_rejects.count("absurdly-high-fee") || ignore_rejects.count("max-fee-exceeded")) {
74 max_tx_fee_set = false;
75 }
76 if (max_tx_fee_set) {
77 // First, call ATMP with test_accept and check the fee. If ATMP
78 // fails here, return error immediately.
79 const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/ true, ignore_rejects);
80 if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
81 return HandleATMPError(result.m_state, err_string);
82 } else {
83 CAmount max_tx_fee_abs;
84 if (std::holds_alternative<CFeeRate>(max_tx_fee)) {
85 max_tx_fee_abs = std::get<CFeeRate>(max_tx_fee).GetFee(*Assert(result.m_vsize));
86 } else {
87 max_tx_fee_abs = std::get<CAmount>(max_tx_fee);
88 }
89 if (result.m_base_fees.value() > max_tx_fee_abs) {
90 return TransactionError::MAX_FEE_EXCEEDED;
91 }
92 }
93 }
94 // Try to submit the transaction to the mempool.
95 const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/ false, ignore_rejects);
96 if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
97 return HandleATMPError(result.m_state, err_string);
98 }
99 100 // Transaction was accepted to the mempool.
101 102 if (relay) {
103 // the mempool tracks locally submitted transactions to make a
104 // best-effort of initial broadcast
105 node.mempool->AddUnbroadcastTx(txid);
106 }
107 108 if (wait_callback && node.validation_signals) {
109 // For transactions broadcast from outside the wallet, make sure
110 // that the wallet has been notified of the transaction before
111 // continuing.
112 //
113 // This prevents a race where a user might call sendrawtransaction
114 // with a transaction to/from their wallet, immediately call some
115 // wallet RPC, and get a stale result because callbacks have not
116 // yet been processed.
117 node.validation_signals->CallFunctionInValidationInterfaceQueue([&promise] {
118 promise.set_value();
119 });
120 callback_set = true;
121 }
122 }
123 } // cs_main
124 125 if (callback_set) {
126 // Wait until Validation Interface clients have been notified of the
127 // transaction entering the mempool.
128 promise.get_future().wait();
129 }
130 131 if (relay) {
132 node.peerman->RelayTransaction(txid, wtxid);
133 }
134 135 return TransactionError::OK;
136 }
137 138 CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, uint256& hashBlock, const BlockManager& blockman)
139 {
140 if (mempool && !block_index) {
141 CTransactionRef ptx = mempool->get(hash);
142 if (ptx) return ptx;
143 }
144 if (g_txindex) {
145 CTransactionRef tx;
146 uint256 block_hash;
147 if (g_txindex->FindTx(hash, block_hash, tx)) {
148 if (!block_index || block_index->GetBlockHash() == block_hash) {
149 // Don't return the transaction if the provided block hash doesn't match.
150 // The case where a transaction appears in multiple blocks (e.g. reorgs or
151 // BIP30) is handled by the block lookup below.
152 hashBlock = block_hash;
153 return tx;
154 }
155 }
156 }
157 if (block_index) {
158 CBlock block;
159 if (blockman.ReadBlock(block, *block_index)) {
160 for (const auto& tx : block.vtx) {
161 if (tx->GetHash() == hash) {
162 hashBlock = block_index->GetBlockHash();
163 return tx;
164 }
165 }
166 }
167 }
168 return nullptr;
169 }
170 } // namespace node
171