Bitcoin Core 32.1.0
P2P Digital Currency
Loading...
Searching...
No Matches
txoutproof.cpp
Go to the documentation of this file.
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 <rpc/register.h> // IWYU pragma: associated
7
8#include <chain.h>
9#include <coins.h>
10#include <crypto/hex_base.h>
11#include <index/txindex.h>
12#include <merkleblock.h>
13#include <node/blockstorage.h>
14#include <node/transaction.h>
15#include <primitives/block.h>
17#include <rpc/blockchain.h>
18#include <rpc/protocol.h>
19#include <rpc/request.h>
20#include <rpc/server.h>
21#include <rpc/server_util.h>
22#include <rpc/util.h>
23#include <streams.h>
24#include <sync.h>
25#include <uint256.h>
26#include <univalue.h>
27#include <validation.h>
28
29#include <memory>
30#include <set>
31#include <span>
32#include <string>
33#include <utility>
34#include <vector>
35
37
39{
40 return RPCMethod{
41 "gettxoutproof",
42 "Returns a hex-encoded proof that \"txid\" was included in a block.\n"
43 "\nNOTE: By default this function only works sometimes. This is when there is an\n"
44 "unspent output in the utxo for this transaction. To make it always work,\n"
45 "you need to maintain a transaction index, using the -txindex command line option or\n"
46 "specify the block in which the transaction is included manually (by blockhash).\n",
47 {
48 {"txids", RPCArg::Type::ARR, RPCArg::Optional::NO, "The txids to filter",
49 {
50 {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A transaction hash"},
51 },
52 },
53 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "If specified, looks for txid in the block with this hash"},
54 },
56 RPCResult::Type::STR, "data", "A string that is a serialized, hex-encoded data for the proof."
57 },
58 RPCExamples{""},
59 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
60 {
61 std::set<Txid> setTxids;
62 UniValue txids = request.params[0].get_array();
63 if (txids.empty()) {
64 throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter 'txids' cannot be empty");
65 }
66 for (unsigned int idx = 0; idx < txids.size(); idx++) {
67 auto ret{setTxids.insert(Txid::FromUint256(ParseHashV(txids[idx], "txid")))};
68 if (!ret.second) {
69 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ") + txids[idx].get_str());
70 }
71 }
72
73 const CBlockIndex* pblockindex = nullptr;
74 uint256 hashBlock;
75 ChainstateManager& chainman = EnsureAnyChainman(request.context);
76 if (!request.params[1].isNull()) {
78 hashBlock = ParseHashV(request.params[1], "blockhash");
79 pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock);
80 if (!pblockindex) {
81 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
82 }
83 } else {
85 Chainstate& active_chainstate = chainman.ActiveChainstate();
86
87 // Loop through txids and try to find which block they're in. Exit loop once a block is found.
88 for (const auto& tx : setTxids) {
89 const Coin& coin{AccessByTxid(active_chainstate.CoinsTip(), tx)};
90 if (!coin.IsSpent()) {
91 pblockindex = active_chainstate.m_chain[coin.nHeight];
92 break;
93 }
94 }
95 }
96
97
98 // Allow txindex to catch up if we need to query it and before we acquire cs_main.
99 if (g_txindex && !pblockindex) {
100 g_txindex->BlockUntilSyncedToCurrentChain();
101 }
102
103 if (pblockindex == nullptr) {
104 const CTransactionRef tx = GetTransaction(/*block_index=*/nullptr, /*mempool=*/nullptr, *setTxids.begin(), chainman.m_blockman, hashBlock);
105 if (!tx || hashBlock.IsNull()) {
106 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block");
107 }
108
109 LOCK(cs_main);
110 pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock);
111 if (!pblockindex) {
112 throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt");
113 }
114 }
115
116 {
117 LOCK(cs_main);
118 CheckBlockDataAvailability(chainman.m_blockman, *pblockindex, /*check_for_undo=*/false);
119 }
120 CBlock block;
121 if (!chainman.m_blockman.ReadBlock(block, *pblockindex)) {
122 throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
123 }
124
125 unsigned int ntxFound = 0;
126 for (const auto& tx : block.vtx) {
127 if (setTxids.contains(tx->GetHash())) {
128 ntxFound++;
129 }
130 }
131 if (ntxFound != setTxids.size()) {
132 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not all transactions found in specified or retrieved block");
133 }
134
135 DataStream ssMB{};
136 CMerkleBlock mb(block, setTxids);
137 ssMB << mb;
138 std::string strHex = HexStr(ssMB);
139 return strHex;
140 },
141 };
142}
143
145{
146 return RPCMethod{
147 "verifytxoutproof",
148 "Verifies that a proof points to a transaction in a block, returning the transaction it commits to\n"
149 "and throwing an RPC error if the block is not in our best chain\n",
150 {
151 {"proof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded proof generated by gettxoutproof"},
152 },
153 RPCResult{
154 RPCResult::Type::ARR, "", "",
155 {
156 {RPCResult::Type::STR_HEX, "txid", "The txid(s) which the proof commits to, or empty array if the proof cannot be validated."},
157 }
158 },
159 RPCExamples{""},
160 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
161 {
162 CMerkleBlock merkleBlock;
163 SpanReader{ParseHexV(request.params[0], "proof")} >> merkleBlock;
164
166
167 std::vector<Txid> vMatch;
168 std::vector<unsigned int> vIndex;
169 if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot)
170 return res;
171
172 ChainstateManager& chainman = EnsureAnyChainman(request.context);
173 LOCK(cs_main);
174
175 const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(merkleBlock.header.GetHash());
176 if (!pindex || !chainman.ActiveChain().Contains(*pindex) || pindex->nTx == 0) {
177 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
178 }
179
180 // Check if proof is valid, only add results if so
181 if (pindex->nTx == merkleBlock.txn.GetNumTransactions()) {
182 for (const auto& txid : vMatch) {
183 res.push_back(txid.GetHex());
184 }
185 }
186
187 return res;
188 },
189 };
190}
191
193{
194 static const CRPCCommand commands[]{
195 {"blockchain", &gettxoutproof},
196 {"blockchain", &verifytxoutproof},
197 };
198 for (const auto& c : commands) {
199 t.appendCommand(c.name, &c);
200 }
201}
int ret
void CheckBlockDataAvailability(BlockManager &blockman, const CBlockIndex &blockindex, bool check_for_undo)
uint256 hashMerkleRoot
Definition block.h:32
uint256 GetHash() const
Definition block.cpp:14
Definition block.h:74
std::vector< CTransactionRef > vtx
Definition block.h:77
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition chain.h:94
unsigned int nTx
Definition chain.h:123
bool Contains(const CBlockIndex &index) const
Efficiently check whether a block is present in this chain.
Definition chain.h:410
Used to relay blocks as header + vector<merkle branch> to filtered nodes.
CBlockHeader header
Public only for unit testing.
CPartialMerkleTree txn
unsigned int GetNumTransactions() const
Get number of transactions the merkle proof is indicating for cross-reference with local blockchain k...
uint256 ExtractMatches(std::vector< Txid > &vMatch, std::vector< unsigned int > &vnIndex)
extract the matching txid's represented by this partial merkle tree and their respective indices with...
RPC command dispatcher.
Definition server.h:89
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition validation.h:550
CChain m_chain
Definition validation.h:630
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition validation.h:694
Interface for managing multiple Chainstate objects, where each chainstate is associated with chainsta...
Definition validation.h:950
Chainstate & ActiveChainstate() const
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
node::BlockManager m_blockman
A UTXO entry.
Definition coins.h:46
bool IsSpent() const
Either this coin never existed (see e.g.
Definition coins.h:94
uint32_t nHeight
at which height this containing transaction was included in the active block chain
Definition coins.h:55
Double ended buffer combining vector and stream-like interfaces.
Definition streams.h:165
Minimal stream for reading from an existing byte array by std::span.
Definition streams.h:83
void push_back(UniValue val)
Definition univalue.cpp:103
size_t size() const
Definition univalue.h:71
bool empty() const
Definition univalue.h:69
constexpr bool IsNull() const
Definition uint256.h:50
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool ReadBlock(CBlock &block, const FlatFilePos &pos, const std::optional< uint256 > &expected_hash) const
Functions for disk access for blocks.
static transaction_identifier FromUint256(const uint256 &id)
256-bit opaque blob.
Definition uint256.h:196
const Coin & AccessByTxid(const CCoinsViewCache &view, const Txid &txid)
Definition coins.cpp:418
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 std::span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition hex_base.cpp:30
const std::string request
CTransactionRef GetTransaction(const CBlockIndex *const block_index, const CTxMemPool *const mempool, const Txid &hash, const BlockManager &blockman, uint256 &hashBlock)
Return transaction with a given hash.
std::shared_ptr< const CTransaction > CTransactionRef
void RegisterTxoutProofRPCCommands(CRPCTable &)
UniValue JSONRPCError(int code, const std::string &message)
Definition request.cpp:75
CTransactionRef GetTransaction(const CBlockIndex *block_index, const CTxMemPool *mempool, const Txid &hash, const BlockManager &blockman, uint256 &hashBlock)
Return transaction with a given hash.
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition protocol.h:69
@ RPC_INTERNAL_ERROR
Definition protocol.h:61
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition protocol.h:67
std::vector< unsigned char > ParseHexV(const UniValue &v, std::string_view name)
Definition util.cpp:135
uint256 ParseHashV(const UniValue &v, std::string_view name)
Utilities: convert hex-encoded Values (throws error if not hex).
Definition util.cpp:122
ChainstateManager & EnsureAnyChainman(const std::any &context)
@ STR_HEX
Special type that is a STR with only hex chars.
Definition util.h:202
@ OMITTED
Optional argument for which the default value is omitted from help text for one of two reasons:
Definition util.h:217
@ NO
Required arg.
Definition util.h:208
@ STR_HEX
Special string with only hex chars.
Definition util.h:317
#define LOCK(cs)
Definition sync.h:268
std::unique_ptr< TxIndex > g_txindex
The global transaction index, used in GetTransaction. May be null.
Definition txindex.cpp:41
static RPCMethod verifytxoutproof()
static RPCMethod gettxoutproof()