transaction.cpp
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 <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 namespace node { 19 static TransactionError HandleATMPError(const TxValidationState& state, std::string& err_string_out) 20 { 21 err_string_out = state.ToString(); 22 if (state.IsInvalid()) { 23 if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { 24 return TransactionError::MISSING_INPUTS; 25 } 26 return TransactionError::MEMPOOL_REJECTED; 27 } else { 28 return TransactionError::MEMPOOL_ERROR; 29 } 30 } 31 32 TransactionError BroadcastTransaction(NodeContext& node, 33 const CTransactionRef tx, 34 std::string& err_string, 35 const CAmount& max_tx_fee, 36 TxBroadcast broadcast_method, 37 bool wait_callback) 38 { 39 // BroadcastTransaction can be called by RPC or by the wallet. 40 // chainman, mempool and peerman are initialized before the RPC server and wallet are started 41 // and reset after the RPC sever and wallet are stopped. 42 assert(node.chainman); 43 assert(node.mempool); 44 assert(node.peerman); 45 46 Txid txid = tx->GetHash(); 47 Wtxid wtxid = tx->GetWitnessHash(); 48 bool callback_set = false; 49 50 { 51 LOCK(cs_main); 52 53 // If the transaction is already confirmed in the chain, don't do anything 54 // and return early. 55 CCoinsViewCache &view = node.chainman->ActiveChainstate().CoinsTip(); 56 for (size_t o = 0; o < tx->vout.size(); o++) { 57 const Coin& existingCoin = view.AccessCoin(COutPoint(txid, o)); 58 // IsSpent doesn't mean the coin is spent, it means the output doesn't exist. 59 // So if the output does exist, then this transaction exists in the chain. 60 if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_UTXO_SET; 61 } 62 63 if (auto mempool_tx = node.mempool->get(txid); mempool_tx) { 64 // There's already a transaction in the mempool with this txid. Don't 65 // try to submit this transaction to the mempool (since it'll be 66 // rejected as a TX_CONFLICT), but do attempt to reannounce the mempool 67 // transaction if broadcast_method is not TxBroadcast::MEMPOOL_NO_BROADCAST. 68 // 69 // The mempool transaction may have the same or different witness (and 70 // wtxid) as this transaction. Use the mempool's wtxid for reannouncement. 71 wtxid = mempool_tx->GetWitnessHash(); 72 } else { 73 // Transaction is not already in the mempool. 74 const bool check_max_fee{max_tx_fee > 0}; 75 if (check_max_fee || broadcast_method == TxBroadcast::NO_MEMPOOL_PRIVATE_BROADCAST) { 76 // First, call ATMP with test_accept and check the fee. If ATMP 77 // fails here, return error immediately. 78 const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/ true); 79 if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { 80 return HandleATMPError(result.m_state, err_string); 81 } else if (check_max_fee && result.m_base_fees.value() > max_tx_fee) { 82 return TransactionError::MAX_FEE_EXCEEDED; 83 } 84 } 85 86 switch (broadcast_method) { 87 case TxBroadcast::MEMPOOL_NO_BROADCAST: 88 case TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL: 89 // Try to submit the transaction to the mempool. 90 { 91 const MempoolAcceptResult result = 92 node.chainman->ProcessTransaction(tx, /*test_accept=*/false); 93 if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { 94 return HandleATMPError(result.m_state, err_string); 95 } 96 } 97 // Transaction was accepted to the mempool. 98 99 if (broadcast_method == TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL) { 100 // the mempool tracks locally submitted transactions to make a 101 // best-effort of initial broadcast 102 node.mempool->AddUnbroadcastTx(txid); 103 } 104 break; 105 case TxBroadcast::NO_MEMPOOL_PRIVATE_BROADCAST: 106 break; 107 } 108 109 if (wait_callback && node.validation_signals) { 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 callback_set = true; 119 } 120 } 121 } // cs_main 122 123 if (callback_set) { 124 // Wait until Validation Interface clients have been notified of the 125 // transaction entering the mempool. 126 node.validation_signals->SyncWithValidationInterfaceQueue(); 127 } 128 129 switch (broadcast_method) { 130 case TxBroadcast::MEMPOOL_NO_BROADCAST: 131 break; 132 case TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL: 133 node.peerman->InitiateTxBroadcastToAll(txid, wtxid); 134 break; 135 case TxBroadcast::NO_MEMPOOL_PRIVATE_BROADCAST: 136 node.peerman->InitiateTxBroadcastPrivate(tx); 137 break; 138 } 139 140 return TransactionError::OK; 141 } 142 143 CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const Txid& hash, const BlockManager& blockman, uint256& hashBlock) 144 { 145 if (mempool && !block_index) { 146 CTransactionRef ptx = mempool->get(hash); 147 if (ptx) return ptx; 148 } 149 if (g_txindex) { 150 CTransactionRef tx; 151 uint256 block_hash; 152 if (g_txindex->FindTx(hash, block_hash, tx)) { 153 if (!block_index || block_index->GetBlockHash() == block_hash) { 154 // Don't return the transaction if the provided block hash doesn't match. 155 // The case where a transaction appears in multiple blocks (e.g. reorgs or 156 // BIP30) is handled by the block lookup below. 157 hashBlock = block_hash; 158 return tx; 159 } 160 } 161 } 162 if (block_index) { 163 CBlock block; 164 if (blockman.ReadBlock(block, *block_index)) { 165 for (const auto& tx : block.vtx) { 166 if (tx->GetHash() == hash) { 167 hashBlock = block_index->GetBlockHash(); 168 return tx; 169 } 170 } 171 } 172 } 173 return nullptr; 174 } 175 } // namespace node