transaction.cpp raw

   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          return node.peerman->InitiateTxBroadcastPrivate(tx);
 137      }
 138  
 139      return TransactionError::OK;
 140  }
 141  
 142  CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const Txid& hash, const BlockManager& blockman, uint256& hashBlock)
 143  {
 144      if (mempool && !block_index) {
 145          CTransactionRef ptx = mempool->get(hash);
 146          if (ptx) return ptx;
 147      }
 148      if (g_txindex) {
 149          CTransactionRef tx;
 150          uint256 block_hash;
 151          if (g_txindex->FindTx(hash, block_hash, tx)) {
 152              if (!block_index || block_index->GetBlockHash() == block_hash) {
 153                  // Don't return the transaction if the provided block hash doesn't match.
 154                  // The case where a transaction appears in multiple blocks (e.g. reorgs or
 155                  // BIP30) is handled by the block lookup below.
 156                  hashBlock = block_hash;
 157                  return tx;
 158              }
 159          }
 160      }
 161      if (block_index) {
 162          CBlock block;
 163          if (blockman.ReadBlock(block, *block_index)) {
 164              for (const auto& tx : block.vtx) {
 165                  if (tx->GetHash() == hash) {
 166                      hashBlock = block_index->GetBlockHash();
 167                      return tx;
 168                  }
 169              }
 170          }
 171      }
 172      return nullptr;
 173  }
 174  } // namespace node
 175