/Users/eugenesiegel/btc/bitcoin/src/node/transaction.cpp
| Line | Count | Source (jump to first uncovered line) | 
| 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 |  | 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()) { | 
| 25 | 0 |         if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { | 
| 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, bool relay, 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); | 
| 40 | 0 |     assert(node.mempool); | 
| 41 | 0 |     assert(node.peerman); | 
| 42 |  |  | 
| 43 | 0 |     std::promise<void> promise; | 
| 44 | 0 |     Txid txid = tx->GetHash(); | 
| 45 | 0 |     Wtxid wtxid = tx->GetWitnessHash(); | 
| 46 | 0 |     bool callback_set = false; | 
| 47 |  | 
 | 
| 48 | 0 |     { | 
| 49 | 0 |         LOCK(cs_main); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 50 |  |  | 
| 51 |  |         // If the transaction is already confirmed in the chain, don't do anything | 
| 52 |  |         // and return early. | 
| 53 | 0 |         CCoinsViewCache &view = node.chainman->ActiveChainstate().CoinsTip(); | 
| 54 | 0 |         for (size_t o = 0; o < tx->vout.size(); o++) { | 
| 55 | 0 |             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 | 0 |             if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_UTXO_SET; | 
| 59 | 0 |         } | 
| 60 |  |  | 
| 61 | 0 |         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 | 0 |             wtxid = mempool_tx->GetWitnessHash(); | 
| 70 | 0 |         } else { | 
| 71 |  |             // Transaction is not already in the mempool. | 
| 72 | 0 |             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 | 0 |                 const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/ true); | 
| 76 | 0 |                 if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { | 
| 77 | 0 |                     return HandleATMPError(result.m_state, err_string); | 
| 78 | 0 |                 } else if (result.m_base_fees.value() > max_tx_fee) { | 
| 79 | 0 |                     return TransactionError::MAX_FEE_EXCEEDED; | 
| 80 | 0 |                 } | 
| 81 | 0 |             } | 
| 82 |  |             // Try to submit the transaction to the mempool. | 
| 83 | 0 |             const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/ false); | 
| 84 | 0 |             if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { | 
| 85 | 0 |                 return HandleATMPError(result.m_state, err_string); | 
| 86 | 0 |             } | 
| 87 |  |  | 
| 88 |  |             // Transaction was accepted to the mempool. | 
| 89 |  |  | 
| 90 | 0 |             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 | 0 |             } | 
| 95 |  | 
 | 
| 96 | 0 |             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 | 0 |                 }); | 
| 108 | 0 |                 callback_set = true; | 
| 109 | 0 |             } | 
| 110 | 0 |         } | 
| 111 | 0 |     } // cs_main | 
| 112 |  |  | 
| 113 | 0 |     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 | 0 |     } | 
| 118 |  | 
 | 
| 119 | 0 |     if (relay) { | 
| 120 | 0 |         node.peerman->RelayTransaction(txid, wtxid); | 
| 121 | 0 |     } | 
| 122 |  | 
 | 
| 123 | 0 |     return TransactionError::OK; | 
| 124 | 0 | } | 
| 125 |  |  | 
| 126 |  | CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const Txid& hash, uint256& hashBlock, const BlockManager& blockman) | 
| 127 | 0 | { | 
| 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 | 0 |             } | 
| 143 | 0 |         } | 
| 144 | 0 |     } | 
| 145 | 0 |     if (block_index) { | 
| 146 | 0 |         CBlock block; | 
| 147 | 0 |         if (blockman.ReadBlock(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 | 0 |                 } | 
| 153 | 0 |             } | 
| 154 | 0 |         } | 
| 155 | 0 |     } | 
| 156 | 0 |     return nullptr; | 
| 157 | 0 | } | 
| 158 |  | } // namespace node |