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 <txmempool.h> 12 : #include <validation.h> 13 : #include <validationinterface.h> 14 : #include <node/context.h> 15 : #include <node/transaction.h> 16 : #include <util/translation.h> 17 : 18 : #include <future> 19 : 20 : namespace node { 21 0 : static TransactionError HandleATMPError(const TxValidationState& state, std::string& err_string_out) { 22 0 : err_string_out = state.ToString(); 23 0 : if (state.IsInvalid()) { 24 0 : if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { 25 0 : return TransactionError::MISSING_INPUTS; 26 : } 27 0 : return TransactionError::MEMPOOL_REJECTED; 28 : } else { 29 0 : return TransactionError::MEMPOOL_ERROR; 30 : } 31 0 : } 32 : 33 2 : TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, bilingual_str& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback, bool bypass_limits) 34 : { 35 : // BroadcastTransaction can be called by RPC or by the wallet. 36 : // chainman, mempool and peerman are initialized before the RPC server and wallet are started 37 : // and reset after the RPC sever and wallet are stopped. 38 2 : assert(node.chainman); 39 2 : assert(node.mempool); 40 2 : assert(node.peerman); 41 : 42 2 : std::promise<void> promise; 43 2 : uint256 txid = tx->GetHash(); 44 2 : bool callback_set = false; 45 : 46 : { 47 2 : LOCK(cs_main); 48 : 49 : // If the transaction is already confirmed in the chain, don't do anything 50 : // and return early. 51 2 : CCoinsViewCache &view = node.chainman->ActiveChainstate().CoinsTip(); 52 4 : for (size_t o = 0; o < tx->vout.size(); o++) { 53 2 : const Coin& existingCoin = view.AccessCoin(COutPoint(txid, o)); 54 : // IsSpent does not mean the coin is spent, it means the output does not exist. 55 : // So if the output does exist, then this transaction exists in the chain. 56 2 : if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_CHAIN; 57 2 : } 58 4 : if (auto mempool_tx = node.mempool->get(txid); mempool_tx) { 59 : // There's already a transaction in the mempool with this txid. Don't 60 : // try to submit this transaction to the mempool (since it'll be 61 : // rejected as a TX_CONFLICT), but do attempt to reannounce the mempool 62 : // transaction if relay=true. 63 : // 64 0 : } else { 65 : // Transaction is not already in the mempool. 66 2 : if (max_tx_fee > 0) { 67 : // First, call ATMP with test_accept and check the fee. If ATMP 68 : // fails here, return error immediately. 69 2 : const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/true, bypass_limits); 70 2 : if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { 71 0 : return HandleATMPError(result.m_state, err_string.original); 72 2 : } else if (result.m_base_fees.value() > max_tx_fee) { 73 0 : return TransactionError::MAX_FEE_EXCEEDED; 74 : } 75 2 : } 76 : // Try to submit the transaction to the mempool. 77 2 : const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/false, bypass_limits); 78 2 : if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { 79 0 : return HandleATMPError(result.m_state, err_string.original); 80 : } 81 : 82 : // Transaction was accepted to the mempool. 83 : 84 2 : if (relay) { 85 : // the mempool tracks locally submitted transactions to make a 86 : // best-effort of initial broadcast 87 0 : node.mempool->AddUnbroadcastTx(txid); 88 0 : } 89 : 90 2 : 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 0 : CallFunctionInValidationInterfaceQueue([&promise] { 100 0 : promise.set_value(); 101 0 : }); 102 0 : callback_set = true; 103 0 : } 104 2 : } 105 2 : } // cs_main 106 : 107 2 : if (callback_set) { 108 : // Wait until Validation Interface clients have been notified of the 109 : // transaction entering the mempool. 110 0 : promise.get_future().wait(); 111 0 : } 112 : 113 2 : if (relay) { 114 0 : node.peerman->RelayTransaction(txid); 115 0 : } 116 : 117 2 : return TransactionError::OK; 118 2 : } 119 : 120 180 : CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, const Consensus::Params& consensusParams, uint256& hashBlock) 121 : { 122 180 : if (mempool && !block_index) { 123 180 : CTransactionRef ptx = mempool->get(hash); 124 180 : if (ptx) return ptx; 125 360 : } 126 180 : if (g_txindex) { 127 180 : CTransactionRef tx; 128 180 : uint256 block_hash; 129 180 : if (g_txindex->FindTx(hash, block_hash, tx)) { 130 180 : if (!block_index || block_index->GetBlockHash() == block_hash) { 131 : // Don't return the transaction if the provided block hash doesn't match. 132 : // The case where a transaction appears in multiple blocks (e.g. reorgs or 133 : // BIP30) is handled by the block lookup below. 134 180 : hashBlock = block_hash; 135 180 : return tx; 136 : } 137 0 : } 138 180 : } 139 0 : if (block_index) { 140 0 : CBlock block; 141 0 : if (ReadBlockFromDisk(block, block_index, consensusParams)) { 142 0 : for (const auto& tx : block.vtx) { 143 0 : if (tx->GetHash() == hash) { 144 0 : hashBlock = block_index->GetBlockHash(); 145 0 : return tx; 146 : } 147 : } 148 0 : } 149 0 : } 150 0 : return nullptr; 151 180 : } 152 : } // namespace node