Bitcoin Core  24.1.0
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 <index/txindex.h>
10 #include <merkleblock.h>
11 #include <node/blockstorage.h>
12 #include <primitives/transaction.h>
13 #include <rpc/server.h>
14 #include <rpc/server_util.h>
15 #include <rpc/util.h>
16 #include <univalue.h>
17 #include <util/strencodings.h>
18 #include <validation.h>
19 
22 
24 {
25  return RPCHelpMan{"gettxoutproof",
26  "\nReturns a hex-encoded proof that \"txid\" was included in a block.\n"
27  "\nNOTE: By default this function only works sometimes. This is when there is an\n"
28  "unspent output in the utxo for this transaction. To make it always work,\n"
29  "you need to maintain a transaction index, using the -txindex command line option or\n"
30  "specify the block in which the transaction is included manually (by blockhash).\n",
31  {
32  {"txids", RPCArg::Type::ARR, RPCArg::Optional::NO, "The txids to filter",
33  {
34  {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A transaction hash"},
35  },
36  },
37  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED_NAMED_ARG, "If specified, looks for txid in the block with this hash"},
38  },
39  RPCResult{
40  RPCResult::Type::STR, "data", "A string that is a serialized, hex-encoded data for the proof."
41  },
42  RPCExamples{""},
43  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
44  {
45  std::set<uint256> setTxids;
46  UniValue txids = request.params[0].get_array();
47  if (txids.empty()) {
48  throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter 'txids' cannot be empty");
49  }
50  for (unsigned int idx = 0; idx < txids.size(); idx++) {
51  auto ret = setTxids.insert(ParseHashV(txids[idx], "txid"));
52  if (!ret.second) {
53  throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ") + txids[idx].get_str());
54  }
55  }
56 
57  const CBlockIndex* pblockindex = nullptr;
58  uint256 hashBlock;
59  ChainstateManager& chainman = EnsureAnyChainman(request.context);
60  if (!request.params[1].isNull()) {
61  LOCK(cs_main);
62  hashBlock = ParseHashV(request.params[1], "blockhash");
63  pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock);
64  if (!pblockindex) {
65  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
66  }
67  } else {
68  LOCK(cs_main);
69  Chainstate& active_chainstate = chainman.ActiveChainstate();
70 
71  // Loop through txids and try to find which block they're in. Exit loop once a block is found.
72  for (const auto& tx : setTxids) {
73  const Coin& coin = AccessByTxid(active_chainstate.CoinsTip(), tx);
74  if (!coin.IsSpent()) {
75  pblockindex = active_chainstate.m_chain[coin.nHeight];
76  break;
77  }
78  }
79  }
80 
81 
82  // Allow txindex to catch up if we need to query it and before we acquire cs_main.
83  if (g_txindex && !pblockindex) {
84  g_txindex->BlockUntilSyncedToCurrentChain();
85  }
86 
87  LOCK(cs_main);
88 
89  if (pblockindex == nullptr) {
90  const CTransactionRef tx = GetTransaction(/*block_index=*/nullptr, /*mempool=*/nullptr, *setTxids.begin(), chainman.GetConsensus(), hashBlock);
91  if (!tx || hashBlock.IsNull()) {
92  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block");
93  }
94  pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock);
95  if (!pblockindex) {
96  throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt");
97  }
98  }
99 
100  CBlock block;
101  if (!ReadBlockFromDisk(block, pblockindex, chainman.GetConsensus())) {
102  throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
103  }
104 
105  unsigned int ntxFound = 0;
106  for (const auto& tx : block.vtx) {
107  if (setTxids.count(tx->GetHash())) {
108  ntxFound++;
109  }
110  }
111  if (ntxFound != setTxids.size()) {
112  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not all transactions found in specified or retrieved block");
113  }
114 
116  CMerkleBlock mb(block, setTxids);
117  ssMB << mb;
118  std::string strHex = HexStr(ssMB);
119  return strHex;
120  },
121  };
122 }
123 
125 {
126  return RPCHelpMan{"verifytxoutproof",
127  "\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n"
128  "and throwing an RPC error if the block is not in our best chain\n",
129  {
130  {"proof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded proof generated by gettxoutproof"},
131  },
132  RPCResult{
133  RPCResult::Type::ARR, "", "",
134  {
135  {RPCResult::Type::STR_HEX, "txid", "The txid(s) which the proof commits to, or empty array if the proof cannot be validated."},
136  }
137  },
138  RPCExamples{""},
139  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
140  {
142  CMerkleBlock merkleBlock;
143  ssMB >> merkleBlock;
144 
146 
147  std::vector<uint256> vMatch;
148  std::vector<unsigned int> vIndex;
149  if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot)
150  return res;
151 
152  ChainstateManager& chainman = EnsureAnyChainman(request.context);
153  LOCK(cs_main);
154 
155  const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(merkleBlock.header.GetHash());
156  if (!pindex || !chainman.ActiveChain().Contains(pindex) || pindex->nTx == 0) {
157  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
158  }
159 
160  // Check if proof is valid, only add results if so
161  if (pindex->nTx == merkleBlock.txn.GetNumTransactions()) {
162  for (const uint256& hash : vMatch) {
163  res.push_back(hash.GetHex());
164  }
165  }
166 
167  return res;
168  },
169  };
170 }
171 
173 {
174  static const CRPCCommand commands[]{
175  {"blockchain", &gettxoutproof},
176  {"blockchain", &verifytxoutproof},
177  };
178  for (const auto& c : commands) {
179  t.appendCommand(c.name, &c);
180  }
181 }
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:414
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:541
const Coin & AccessByTxid(const CCoinsViewCache &view, const uint256 &txid)
Utility function to find any unspent output with a given txid.
Definition: coins.cpp:284
bool IsSpent() const
Either this coin never existed (see e.g.
Definition: coins.h:79
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:898
void push_back(UniValue val)
Definition: univalue.cpp:104
int ret
static RPCHelpMan gettxoutproof()
Definition: txoutproof.cpp:23
static const int SERIALIZE_TRANSACTION_NO_WITNESS
A flag that is ORed into the protocol version to designate that a transaction should be (un)serialize...
Definition: transaction.h:31
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos, const Consensus::Params &consensusParams)
Functions for disk access for blocks.
RPC command dispatcher.
Definition: server.h:125
Required arg.
A UTXO entry.
Definition: coins.h:30
Definition: block.h:68
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:799
std::vector< unsigned char > ParseHexV(const UniValue &v, std::string strName)
Definition: util.cpp:113
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:965
void RegisterTxoutProofRPCCommands(CRPCTable &t)
Definition: txoutproof.cpp:172
const UniValue & get_array() const
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:185
CTransactionRef GetTransaction(const CBlockIndex *const block_index, const CTxMemPool *const mempool, const uint256 &hash, const Consensus::Params &consensusParams, uint256 &hashBlock)
Return transaction with a given hash.
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition: validation.h:519
bool IsNull() const
Definition: uint256.h:34
Invalid, missing or duplicate parameter.
Definition: protocol.h:43
uint32_t nHeight
at which height this containing transaction was included in the active block chain ...
Definition: coins.h:40
Special type that is a STR with only hex chars.
Used to relay blocks as header + vector<merkle branch> to filtered nodes.
Definition: merkleblock.h:124
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:56
Special string with only hex chars.
Chainstate stores and provides an API to update our local knowledge of the current best chain...
Definition: validation.h:437
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
#define LOCK(cs)
Definition: sync.h:261
std::unique_ptr< TxIndex > g_txindex
The global transaction index, used in GetTransaction. May be null.
Definition: txindex.cpp:16
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
Definition: chain.h:453
bool empty() const
Definition: univalue.h:63
const Consensus::Params & GetConsensus() const
Definition: validation.h:879
Invalid address or key.
Definition: protocol.h:41
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Optional arg that is a named argument and has a default value of null.
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded Values (throws error if not hex).
Definition: util.cpp:100
256-bit opaque blob.
Definition: uint256.h:119
Optional argument with default value omitted because they are implicitly clear.
std::vector< CTransactionRef > vtx
Definition: block.h:72
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: chain.h:151
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:12
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
Definition: validation.cpp:121
size_t size() const
Definition: univalue.h:65
Chainstate & ActiveChainstate() const
The most-work chain.
static RPCHelpMan verifytxoutproof()
Definition: txoutproof.cpp:124
ChainstateManager & EnsureAnyChainman(const std::any &context)
Definition: server_util.cpp:63
unsigned int nTx
Number of transactions in this block.
Definition: chain.h:183