Bitcoin ABC  0.26.3
P2P Digital Currency
txoutproof.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2022 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 <chain.h>
7 #include <chainparams.h>
8 #include <coins.h>
9 #include <config.h>
10 #include <index/txindex.h>
11 #include <merkleblock.h>
12 #include <node/blockstorage.h>
13 #include <primitives/transaction.h>
14 #include <rpc/server.h>
15 #include <rpc/server_util.h>
16 #include <rpc/util.h>
17 #include <univalue.h>
18 #include <util/strencodings.h>
19 #include <validation.h>
20 
22 
24  return RPCHelpMan{
25  "gettxoutproof",
26  "Returns a hex-encoded proof that \"txid\" was included in a block.\n"
27  "\nNOTE: By default this function only works sometimes. "
28  "This is when there is an\n"
29  "unspent output in the utxo for this transaction. To make it always "
30  "work,\n"
31  "you need to maintain a transaction index, using the -txindex command "
32  "line option or\n"
33  "specify the block in which the transaction is included manually (by "
34  "blockhash).\n",
35  {
36  {
37  "txids",
40  "The txids to filter",
41  {
43  "A transaction hash"},
44  },
45  },
46  {"blockhash", RPCArg::Type::STR_HEX,
48  "If specified, looks for txid in the block with this hash"},
49  },
50  RPCResult{
51  RPCResult::Type::STR, "data",
52  "A string that is a serialized, hex-encoded data for the proof."},
53  RPCExamples{""},
54  [&](const RPCHelpMan &self, const Config &config,
55  const JSONRPCRequest &request) -> UniValue {
56  std::set<TxId> setTxIds;
57  TxId oneTxId;
58  UniValue txids = request.params[0].get_array();
59  for (unsigned int idx = 0; idx < txids.size(); idx++) {
60  const UniValue &utxid = txids[idx];
61  TxId txid(ParseHashV(utxid, "txid"));
62  if (setTxIds.count(txid)) {
63  throw JSONRPCError(
65  std::string("Invalid parameter, duplicated txid: ") +
66  utxid.get_str());
67  }
68 
69  setTxIds.insert(txid);
70  oneTxId = txid;
71  }
72 
73  const CBlockIndex *pblockindex = nullptr;
74 
75  BlockHash hashBlock;
76  ChainstateManager &chainman = EnsureAnyChainman(request.context);
77  if (!request.params[1].isNull()) {
78  LOCK(cs_main);
79  hashBlock =
80  BlockHash(ParseHashV(request.params[1], "blockhash"));
81  pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock);
82  if (!pblockindex) {
84  "Block not found");
85  }
86  } else {
87  LOCK(cs_main);
88  Chainstate &active_chainstate = chainman.ActiveChainstate();
89  // Loop through txids and try to find which block they're in.
90  // Exit loop once a block is found.
91  for (const auto &txid : setTxIds) {
92  const Coin &coin =
93  AccessByTxid(active_chainstate.CoinsTip(), txid);
94  if (!coin.IsSpent()) {
95  pblockindex =
96  active_chainstate.m_chain[coin.GetHeight()];
97  break;
98  }
99  }
100  }
101 
102  // Allow txindex to catch up if we need to query it and before we
103  // acquire cs_main.
104  if (g_txindex && !pblockindex) {
105  g_txindex->BlockUntilSyncedToCurrentChain();
106  }
107 
108  if (pblockindex == nullptr) {
109  const CTransactionRef tx = GetTransaction(
110  /* block_index */ nullptr,
111  /* mempool */ nullptr, oneTxId, hashBlock,
112  chainman.m_blockman);
113  if (!tx || hashBlock.IsNull()) {
115  "Transaction not yet in block");
116  }
117 
118  LOCK(cs_main);
119  pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock);
120  if (!pblockindex) {
122  "Transaction index corrupt");
123  }
124  }
125 
126  CBlock block;
127  if (!chainman.m_blockman.ReadBlockFromDisk(block, *pblockindex)) {
129  "Can't read block from disk");
130  }
131 
132  unsigned int ntxFound = 0;
133  for (const auto &tx : block.vtx) {
134  if (setTxIds.count(tx->GetId())) {
135  ntxFound++;
136  }
137  }
138 
139  if (ntxFound != setTxIds.size()) {
141  "Not all transactions found in specified or "
142  "retrieved block");
143  }
144 
146  CMerkleBlock mb(block, setTxIds);
147  ssMB << mb;
148  std::string strHex = HexStr(ssMB);
149  return strHex;
150  },
151  };
152 }
153 
155  return RPCHelpMan{
156  "verifytxoutproof",
157  "Verifies that a proof points to a transaction in a block, returning "
158  "the transaction it commits to\n"
159  "and throwing an RPC error if the block is not in our best chain\n",
160  {
162  "The hex-encoded proof generated by gettxoutproof"},
163  },
165  "",
166  "",
167  {
168  {RPCResult::Type::STR_HEX, "txid",
169  "The txid(s) which the proof commits to, or empty array "
170  "if the proof can not be validated."},
171  }},
172  RPCExamples{""},
173  [&](const RPCHelpMan &self, const Config &config,
174  const JSONRPCRequest &request) -> UniValue {
175  CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK,
177  CMerkleBlock merkleBlock;
178  ssMB >> merkleBlock;
179 
181 
182  std::vector<uint256> vMatch;
183  std::vector<size_t> vIndex;
184  if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) !=
185  merkleBlock.header.hashMerkleRoot) {
186  return res;
187  }
188 
189  ChainstateManager &chainman = EnsureAnyChainman(request.context);
190  LOCK(cs_main);
191 
192  const CBlockIndex *pindex = chainman.m_blockman.LookupBlockIndex(
193  merkleBlock.header.GetHash());
194  if (!pindex || !chainman.ActiveChain().Contains(pindex) ||
195  pindex->nTx == 0) {
197  "Block not found in chain");
198  }
199 
200  // Check if proof is valid, only add results if so
201  if (pindex->nTx == merkleBlock.txn.GetNumTransactions()) {
202  for (const uint256 &hash : vMatch) {
203  res.push_back(hash.GetHex());
204  }
205  }
206 
207  return res;
208  },
209  };
210 }
211 
213  static const CRPCCommand commands[]{
214  // category actor (function)
215  // -------- ----------------
216  {"blockchain", gettxoutproof},
217  {"blockchain", verifytxoutproof},
218  };
219  for (const auto &c : commands) {
220  t.appendCommand(c.name, &c);
221  }
222 }
BlockHash GetHash() const
Definition: block.cpp:11
uint256 hashMerkleRoot
Definition: block.h:28
Definition: block.h:60
std::vector< CTransactionRef > vtx
Definition: block.h:63
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: blockindex.h:25
unsigned int nTx
Number of transactions in this block.
Definition: blockindex.h:60
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
Definition: chain.h:166
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:177
Used to create a Merkle proof (usually from a subset of transactions), which consists of a block head...
Definition: merkleblock.h:147
CBlockHeader header
Public only for unit testing.
Definition: merkleblock.h:150
CPartialMerkleTree txn
Definition: merkleblock.h:151
uint32_t GetNumTransactions() const
Get number of transactions the merkle proof is indicating for cross-reference with local blockchain k...
Definition: merkleblock.h:132
uint256 ExtractMatches(std::vector< uint256 > &vMatch, std::vector< size_t > &vnIndex)
Extract the matching txid's represented by this partial merkle tree and their respective indices with...
RPC command dispatcher.
Definition: server.h:194
void appendCommand(const std::string &name, const CRPCCommand *pcmd)
Appends a CRPCCommand to the dispatch table.
Definition: server.cpp:327
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition: validation.h:630
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition: validation.h:739
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:765
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:1153
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1363
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1285
A UTXO entry.
Definition: coins.h:28
uint32_t GetHeight() const
Definition: coins.h:45
bool IsSpent() const
Definition: coins.h:47
Definition: config.h:19
void push_back(UniValue val)
Definition: univalue.cpp:96
const std::string & get_str() const
@ VARR
Definition: univalue.h:32
size_t size() const
Definition: univalue.h:92
const UniValue & get_array() const
bool IsNull() const
Definition: uint256.h:32
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos) const
Functions for disk access for blocks.
CBlockIndex * LookupBlockIndex(const BlockHash &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
256-bit opaque blob.
Definition: uint256.h:129
const Coin & AccessByTxid(const CCoinsViewCache &view, const TxId &txid)
Utility function to find any unspent output with a given txid.
Definition: coins.cpp:397
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:7
CTransactionRef GetTransaction(const CBlockIndex *const block_index, const CTxMemPool *const mempool, const TxId &txid, BlockHash &hashBlock, const BlockManager &blockman)
Return transaction with a given txid.
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:315
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:58
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:46
@ RPC_INTERNAL_ERROR
Definition: protocol.h:33
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:42
std::vector< uint8_t > ParseHexV(const UniValue &v, std::string strName)
Definition: util.cpp:94
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded values (throws error if not hex).
Definition: util.cpp:73
@ SER_NETWORK
Definition: serialize.h:152
ChainstateManager & EnsureAnyChainman(const std::any &context)
Definition: server_util.cpp:59
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
A BlockHash is a unqiue identifier for a block.
Definition: blockhash.h:13
@ STR_HEX
Special type that is a STR with only hex chars.
@ OMITTED
The arg is optional for one of two reasons:
@ NO
Required arg.
@ STR_HEX
Special string with only hex chars.
A TxId is the identifier of a transaction.
Definition: txid.h:14
#define LOCK(cs)
Definition: sync.h:306
std::unique_ptr< TxIndex > g_txindex
The global transaction index, used in GetTransaction. May be null.
Definition: txindex.cpp:16
void RegisterTxoutProofRPCCommands(CRPCTable &t)
Definition: txoutproof.cpp:212
static RPCHelpMan gettxoutproof()
Definition: txoutproof.cpp:23
static RPCHelpMan verifytxoutproof()
Definition: txoutproof.cpp:154
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:11