Bitcoin ABC 0.30.5
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>
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 },
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()) {
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 {
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) {
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 {
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:699
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition: validation.h:808
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:834
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:1219
SnapshotCompletionResult MaybeCompleteSnapshotValidation(std::function< void(bilingual_str)> shutdown_fnc=[](bilingual_str msg) { AbortNode(msg.original, msg);}) EXCLUSIVE_LOCKS_REQUIRED(Chainstate & ActiveChainstate() const
Once the background validation chainstate has reached the height which is the base of the UTXO snapsh...
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1429
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1351
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
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
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:11