Bitcoin Core 28.99.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>
13#include <rpc/blockchain.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{
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, "If specified, looks for txid in the block with this hash"},
38 },
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<Txid> 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(Txid::FromUint256(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()) {
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 {
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 if (pblockindex == nullptr) {
88 const CTransactionRef tx = GetTransaction(/*block_index=*/nullptr, /*mempool=*/nullptr, *setTxids.begin(), hashBlock, chainman.m_blockman);
89 if (!tx || hashBlock.IsNull()) {
90 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block");
91 }
92
94 pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock);
95 if (!pblockindex) {
96 throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt");
97 }
98 }
99
100 {
101 LOCK(cs_main);
102 CheckBlockDataAvailability(chainman.m_blockman, *pblockindex, /*check_for_undo=*/false);
103 }
104 CBlock block;
105 if (!chainman.m_blockman.ReadBlockFromDisk(block, *pblockindex)) {
106 throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
107 }
108
109 unsigned int ntxFound = 0;
110 for (const auto& tx : block.vtx) {
111 if (setTxids.count(tx->GetHash())) {
112 ntxFound++;
113 }
114 }
115 if (ntxFound != setTxids.size()) {
116 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not all transactions found in specified or retrieved block");
117 }
118
119 DataStream ssMB{};
120 CMerkleBlock mb(block, setTxids);
121 ssMB << mb;
122 std::string strHex = HexStr(ssMB);
123 return strHex;
124 },
125 };
126}
127
129{
130 return RPCHelpMan{"verifytxoutproof",
131 "\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n"
132 "and throwing an RPC error if the block is not in our best chain\n",
133 {
134 {"proof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded proof generated by gettxoutproof"},
135 },
136 RPCResult{
137 RPCResult::Type::ARR, "", "",
138 {
139 {RPCResult::Type::STR_HEX, "txid", "The txid(s) which the proof commits to, or empty array if the proof cannot be validated."},
140 }
141 },
142 RPCExamples{""},
143 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
144 {
145 DataStream ssMB{ParseHexV(request.params[0], "proof")};
146 CMerkleBlock merkleBlock;
147 ssMB >> merkleBlock;
148
150
151 std::vector<uint256> vMatch;
152 std::vector<unsigned int> vIndex;
153 if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot)
154 return res;
155
156 ChainstateManager& chainman = EnsureAnyChainman(request.context);
157 LOCK(cs_main);
158
159 const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(merkleBlock.header.GetHash());
160 if (!pindex || !chainman.ActiveChain().Contains(pindex) || pindex->nTx == 0) {
161 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
162 }
163
164 // Check if proof is valid, only add results if so
165 if (pindex->nTx == merkleBlock.txn.GetNumTransactions()) {
166 for (const uint256& hash : vMatch) {
167 res.push_back(hash.GetHex());
168 }
169 }
170
171 return res;
172 },
173 };
174}
175
177{
178 static const CRPCCommand commands[]{
179 {"blockchain", &gettxoutproof},
180 {"blockchain", &verifytxoutproof},
181 };
182 for (const auto& c : commands) {
183 t.appendCommand(c.name, &c);
184 }
185}
int ret
void CheckBlockDataAvailability(BlockManager &blockman, const CBlockIndex &blockindex, bool check_for_undo)
Definition: blockchain.cpp:604
uint256 hashMerkleRoot
Definition: block.h:27
uint256 GetHash() const
Definition: block.cpp:11
Definition: block.h:69
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:141
unsigned int nTx
Number of transactions in this block.
Definition: chain.h:170
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
Definition: chain.h:447
Used to relay blocks as header + vector<merkle branch> to filtered nodes.
Definition: merkleblock.h:126
CBlockHeader header
Public only for unit testing.
Definition: merkleblock.h:129
CPartialMerkleTree txn
Definition: merkleblock.h:130
uint256 ExtractMatches(std::vector< uint256 > &vMatch, std::vector< unsigned int > &vnIndex)
extract the matching txid's represented by this partial merkle tree and their respective indices with...
unsigned int GetNumTransactions() const
Get number of transactions the merkle proof is indicating for cross-reference with local blockchain k...
Definition: merkleblock.h:114
RPC command dispatcher.
Definition: server.h:127
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition: validation.h:505
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition: validation.h:585
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:611
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:866
SnapshotCompletionResult MaybeCompleteSnapshotValidation() EXCLUSIVE_LOCKS_REQUIRED(const CBlockIndex *GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(Chainstate ActiveChainstate)() const
Once the background validation chainstate has reached the height which is the base of the UTXO snapsh...
Definition: validation.h:1110
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1111
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1007
A UTXO entry.
Definition: coins.h:33
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:147
void push_back(UniValue val)
Definition: univalue.cpp:104
@ VARR
Definition: univalue.h:24
size_t size() const
Definition: univalue.h:71
bool empty() const
Definition: univalue.h:69
const UniValue & get_array() const
constexpr bool IsNull() const
Definition: uint256.h:48
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos) const
Functions for disk access for blocks.
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
static transaction_identifier FromUint256(const uint256 &id)
256-bit opaque blob.
Definition: uint256.h:190
const Coin & AccessByTxid(const CCoinsViewCache &view, const Txid &txid)
Utility function to find any unspent output with a given txid.
Definition: coins.cpp:351
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:8
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition: hex_base.cpp:29
CTransactionRef GetTransaction(const CBlockIndex *const block_index, const CTxMemPool *const mempool, const uint256 &hash, uint256 &hashBlock, const BlockManager &blockman)
Return transaction with a given hash.
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:423
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:70
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:44
@ RPC_INTERNAL_ERROR
Definition: protocol.h:36
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:42
std::vector< unsigned char > ParseHexV(const UniValue &v, std::string_view name)
Definition: util.cpp:131
uint256 ParseHashV(const UniValue &v, std::string_view name)
Utilities: convert hex-encoded Values (throws error if not hex).
Definition: util.cpp:118
ChainstateManager & EnsureAnyChainman(const std::any &context)
Definition: server_util.cpp:78
@ STR_HEX
Special type that is a STR with only hex chars.
@ OMITTED
Optional argument for which the default value is omitted from help text for one of two reasons:
@ NO
Required arg.
@ STR_HEX
Special string with only hex chars.
#define LOCK(cs)
Definition: sync.h:257
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:176
static RPCHelpMan gettxoutproof()
Definition: txoutproof.cpp:23
static RPCHelpMan verifytxoutproof()
Definition: txoutproof.cpp:128