Bitcoin ABC  0.26.3
P2P Digital Currency
transaction.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2018 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 <node/transaction.h>
7 
8 #include <config.h>
9 #include <consensus/validation.h>
10 #include <index/txindex.h>
11 #include <net.h>
12 #include <net_processing.h>
13 #include <node/blockstorage.h>
14 #include <node/context.h>
15 #include <primitives/blockhash.h>
16 #include <primitives/txid.h>
17 #include <txmempool.h>
18 #include <validation.h>
19 #include <validationinterface.h>
20 
21 #include <future>
22 
23 namespace node {
25  std::string &err_string_out) {
26  err_string_out = state.ToString();
27  if (state.IsInvalid()) {
30  }
32  } else {
34  }
35 }
36 
38  const CTransactionRef tx,
39  std::string &err_string,
40  const Amount max_tx_fee, bool relay,
41  bool wait_callback) {
42  // BroadcastTransaction can be called by either sendrawtransaction RPC or
43  // the wallet. chainman, mempool and peerman are initialized before the RPC
44  // server and wallet are started and reset after the RPC server and wallet
45  // are stopped.
46  assert(node.chainman);
47  assert(node.mempool);
48  assert(node.peerman);
49 
50  std::promise<void> promise;
51  TxId txid = tx->GetId();
52  bool callback_set = false;
53 
54  {
55  LOCK(cs_main);
56 
57  // If the transaction is already confirmed in the chain, don't do
58  // anything and return early.
59  CCoinsViewCache &view = node.chainman->ActiveChainstate().CoinsTip();
60  for (size_t o = 0; o < tx->vout.size(); o++) {
61  const Coin &existingCoin = view.AccessCoin(COutPoint(txid, o));
62  // IsSpent doesn't mean the coin is spent, it means the output
63  // doesn't exist. So if the output does exist, then this transaction
64  // exists in the chain.
65  if (!existingCoin.IsSpent()) {
67  }
68  }
69 
70  if (!node.mempool->exists(txid)) {
71  // Transaction is not already in the mempool.
72  if (max_tx_fee > Amount::zero()) {
73  // First, call ATMP with test_accept and check the fee. If ATMP
74  // fails here, return error immediately.
75  const MempoolAcceptResult result =
76  node.chainman->ProcessTransaction(tx, /*test_accept=*/true);
77  if (result.m_result_type !=
79  return HandleATMPError(result.m_state, err_string);
80  } else if (result.m_base_fees.value() > max_tx_fee) {
82  }
83  }
84  // Try to submit the transaction to the mempool.
85  const MempoolAcceptResult result =
86  node.chainman->ProcessTransaction(tx, /*test_accept=*/false);
87  if (result.m_result_type !=
89  return HandleATMPError(result.m_state, err_string);
90  }
91 
92  // Transaction was accepted to the mempool.
93 
94  if (relay) {
95  // the mempool tracks locally submitted transactions to make a
96  // best-effort of initial broadcast
97  node.mempool->AddUnbroadcastTx(txid);
98  }
99 
100  if (wait_callback) {
101  // For transactions broadcast from outside the wallet, make sure
102  // that the wallet has been notified of the transaction before
103  // continuing.
104  //
105  // This prevents a race where a user might call
106  // sendrawtransaction with a transaction to/from their wallet,
107  // immediately call some wallet RPC, and get a stale result
108  // because callbacks have not yet been processed.
110  [&promise] { promise.set_value(); });
111  callback_set = true;
112  }
113  }
114  } // cs_main
115 
116  if (callback_set) {
117  // Wait until Validation Interface clients have been notified of the
118  // transaction entering the mempool.
119  promise.get_future().wait();
120  }
121 
122  if (relay) {
123  node.peerman->RelayTransaction(txid);
124  }
125 
126  return TransactionError::OK;
127 }
128 
129 CTransactionRef GetTransaction(const CBlockIndex *const block_index,
130  const CTxMemPool *const mempool,
131  const TxId &txid,
132  const Consensus::Params &consensusParams,
133  BlockHash &hashBlock) {
134  if (mempool && !block_index) {
135  CTransactionRef ptx = mempool->get(txid);
136  if (ptx) {
137  return ptx;
138  }
139  }
140  if (g_txindex) {
141  CTransactionRef tx;
142  BlockHash block_hash;
143  if (g_txindex->FindTx(txid, block_hash, tx)) {
144  if (!block_index || block_index->GetBlockHash() == block_hash) {
145  // Don't return the transaction if the provided block hash
146  // doesn't match.
147  // The case where a transaction appears in multiple blocks
148  // (e.g. reorgs or BIP30) is handled by the block lookup below.
149  hashBlock = block_hash;
150  return tx;
151  }
152  }
153  }
154  if (block_index) {
155  CBlock block;
156  if (ReadBlockFromDisk(block, block_index, consensusParams)) {
157  for (const auto &tx : block.vtx) {
158  if (tx->GetId() == txid) {
159  hashBlock = block_index->GetBlockHash();
160  return tx;
161  }
162  }
163  }
164  }
165  return nullptr;
166 }
167 } // namespace node
RecursiveMutex cs_main
Global state.
Definition: validation.cpp:111
Definition: block.h:55
std::vector< CTransactionRef > vtx
Definition: block.h:58
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: blockindex.h:26
BlockHash GetBlockHash() const
Definition: blockindex.h:147
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:203
const Coin & AccessCoin(const COutPoint &output) const
Return a reference to Coin in the cache, or coinEmpty if not found.
Definition: coins.cpp:192
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:22
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:435
CTransactionRef get(const TxId &txid) const
Definition: txmempool.cpp:992
A UTXO entry.
Definition: coins.h:27
bool IsSpent() const
Definition: coins.h:46
Definition: config.h:17
Result GetResult() const
Definition: validation.h:123
std::string ToString() const
Definition: validation.h:126
bool IsInvalid() const
Definition: validation.h:121
@ TX_MISSING_INPUTS
transaction was missing some of its inputs
TransactionError
Definition: error.h:22
Definition: init.h:28
TransactionError BroadcastTransaction(NodeContext &node, const Config &config, const CTransactionRef tx, std::string &err_string, const Amount max_tx_fee, bool relay, bool wait_callback)
Submit a transaction to the mempool and (optionally) relay it to all P2P peers.
Definition: transaction.cpp:37
CTransactionRef GetTransaction(const CBlockIndex *const block_index, const CTxMemPool *const mempool, const TxId &txid, const Consensus::Params &consensusParams, BlockHash &hashBlock)
Return transaction with a given txid.
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos, const Consensus::Params &params)
Functions for disk access for blocks.
static TransactionError HandleATMPError(const TxValidationState &state, std::string &err_string_out)
Definition: transaction.cpp:24
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:319
Definition: amount.h:19
static constexpr Amount zero()
Definition: amount.h:42
A BlockHash is a unqiue identifier for a block.
Definition: blockhash.h:13
Parameters that influence chain consensus.
Definition: params.h:76
Validation result for a single transaction mempool acceptance.
Definition: validation.h:218
const ResultType m_result_type
Definition: validation.h:228
const TxValidationState m_state
Definition: validation.h:229
@ VALID
Fully validated, valid.
const std::optional< Amount > m_base_fees
Raw base fees in satoshis.
Definition: validation.h:239
A TxId is the identifier of a transaction.
Definition: txid.h:14
NodeContext struct containing references to chain state and connection state.
Definition: context.h:38
#define LOCK(cs)
Definition: sync.h:243
std::unique_ptr< TxIndex > g_txindex
The global transaction index, used in GetTransaction. May be null.
Definition: txindex.cpp:17
assert(!tx.IsCoinBase())
void CallFunctionInValidationInterfaceQueue(std::function< void()> func)
Pushes a function to callback onto the notification queue, guaranteeing any callbacks generated prior...