From 642b05ebe7df6fdcca186cec3795a82795859a7e Mon Sep 17 00:00:00 2001 From: fanquake Date: Wed, 29 Nov 2023 10:24:33 +0000 Subject: [PATCH 1/2] Merge bitcoin/bitcoin#28958: refactor: Use Txid in CMerkleBlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fa02c08c93e5867b7ea07d79ca1c0917dcde88e0 refactor: Use Txid in CMerkleBlock (MarcoFalke) Pull request description: This should also fix a gcc-13 compiler warning, see https://github.com/bitcoin/bitcoin/pull/28922#discussion_r1407856376 ``` rpc/txoutproof.cpp: In lambda function: rpc/txoutproof.cpp:72:33: error: possibly dangling reference to a temporary [-Werror=dangling-reference] 72 | const Coin& coin = AccessByTxid(active_chainstate.CoinsTip(), Txid::FromUint256(tx)); | ^~~~ rpc/txoutproof.cpp:72:52: note: the temporary was destroyed at the end of the full expression ‘AccessByTxid((*(const CCoinsViewCache*)(&(& active_chainstate)->Chainstate::CoinsTip())), transaction_identifier::FromUint256((* & tx)))’ 72 | const Coin& coin = AccessByTxid(active_chainstate.CoinsTip(), Txid::FromUint256(tx)); | ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cc1plus: all warnings being treated as errors ACKs for top commit: TheCharlatan: Re-ACK fa02c08c93e5867b7ea07d79ca1c0917dcde88e0 dergoegge: reACK fa02c08c93e5867b7ea07d79ca1c0917dcde88e0 Tree-SHA512: 2e6837b9d0c90bd6e9d766330e7086d68c6ec80bb27fe2cfc4702b251b00d91a79f8bfbc76d998cbcd90bee5317402cf617f61099eee96d94e7ac8f37ba7a642 --- src/merkleblock.cpp | 5 +- src/merkleblock.h | 5 +- src/rpc/txoutproof.cpp | 183 ++++++++++++++++----------------- src/test/fuzz/merkleblock.cpp | 4 +- src/test/merkleblock_tests.cpp | 10 +- 5 files changed, 103 insertions(+), 104 deletions(-) diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index cfd164c64544..26588414041d 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -27,7 +27,7 @@ std::vector BytesToBits(const std::vector& bytes) return ret; } -CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std::set* txids) +CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std::set* txids) { header = block.GetBlockHeader(); @@ -51,9 +51,8 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std: for (unsigned int i = 0; i < block.vtx.size(); i++) { const auto& tx = *block.vtx[i]; - const uint256& hash = tx.GetHash(); + const Txid& hash{tx.GetHash()}; bool isAllowedType = !tx.IsSpecialTxVersion() || allowedTxTypes.count(tx.nType) != 0; - if (txids && txids->count(hash)) { vMatch.push_back(true); } else if (isAllowedType && filter && filter->IsRelevantAndUpdate(*block.vtx[i])) { diff --git a/src/merkleblock.h b/src/merkleblock.h index b546b17f5250..12b41a581e3c 100644 --- a/src/merkleblock.h +++ b/src/merkleblock.h @@ -11,6 +11,7 @@ #include #include +#include #include // Helper functions for serialization. @@ -144,7 +145,7 @@ class CMerkleBlock CMerkleBlock(const CBlock& block, CBloomFilter& filter) : CMerkleBlock(block, &filter, nullptr) { } // Create from a CBlock, matching the txids in the set - CMerkleBlock(const CBlock& block, const std::set& txids) : CMerkleBlock(block, nullptr, &txids) { } + CMerkleBlock(const CBlock& block, const std::set& txids) : CMerkleBlock{block, nullptr, &txids} {} CMerkleBlock() {} @@ -152,7 +153,7 @@ class CMerkleBlock private: // Combined constructor to consolidate code - CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std::set* txids); + CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std::set* txids); }; #endif // BITCOIN_MERKLEBLOCK_H diff --git a/src/rpc/txoutproof.cpp b/src/rpc/txoutproof.cpp index 78300720306c..ebf55ce4e32e 100644 --- a/src/rpc/txoutproof.cpp +++ b/src/rpc/txoutproof.cpp @@ -45,81 +45,82 @@ static RPCHelpMan gettxoutproof() + HelpExampleRpc("gettxoutproof", "[\"mytxid\",...], \"blockhash\"") }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue -{ - std::set setTxids; - UniValue txids = request.params[0].get_array(); - if (txids.empty()) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter 'txids' cannot be empty"); - } - for (unsigned int idx = 0; idx < txids.size(); idx++) { - auto ret = setTxids.insert(ParseHashV(txids[idx], "txid")); - if (!ret.second) { - throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ") + txids[idx].get_str()); - } - } + { + std::set setTxids; + UniValue txids = request.params[0].get_array(); + if (txids.empty()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter 'txids' cannot be empty"); + } + for (unsigned int idx = 0; idx < txids.size(); idx++) { + auto ret{setTxids.insert(Txid::FromUint256(ParseHashV(txids[idx], "txid")))}; + if (!ret.second) { + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ") + txids[idx].get_str()); + } + } - const CBlockIndex* pblockindex = nullptr; - uint256 hashBlock; - ChainstateManager& chainman = EnsureAnyChainman(request.context); - if (!request.params[1].isNull()) { - LOCK(cs_main); - hashBlock = ParseHashV(request.params[1], "blockhash"); - pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock); - if (!pblockindex) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - } - } else { - LOCK(cs_main); - CChainState& active_chainstate = chainman.ActiveChainstate(); - - // Loop through txids and try to find which block they're in. Exit loop once a block is found. - for (const auto& tx : setTxids) { - const Coin& coin = AccessByTxid(active_chainstate.CoinsTip(), tx); - if (!coin.IsSpent()) { - pblockindex = active_chainstate.m_chain[coin.nHeight]; - break; + const CBlockIndex* pblockindex = nullptr; + uint256 hashBlock; + ChainstateManager& chainman = EnsureAnyChainman(request.context); + if (!request.params[1].isNull()) { + LOCK(cs_main); + hashBlock = ParseHashV(request.params[1], "blockhash"); + pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock); + if (!pblockindex) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + } + } else { + LOCK(cs_main); + CChainState& active_chainstate = chainman.ActiveChainstate(); + + // Loop through txids and try to find which block they're in. Exit loop once a block is found. + for (const auto& tx : setTxids) { + const Coin& coin{AccessByTxid(active_chainstate.CoinsTip(), tx)}; + if (!coin.IsSpent()) { + pblockindex = active_chainstate.m_chain[coin.nHeight]; + break; + } + } } - } - } - // Allow txindex to catch up if we need to query it and before we acquire cs_main. - if (g_txindex && !pblockindex) { - g_txindex->BlockUntilSyncedToCurrentChain(); - } + // Allow txindex to catch up if we need to query it and before we acquire cs_main. + if (g_txindex && !pblockindex) { + g_txindex->BlockUntilSyncedToCurrentChain(); + } - if (pblockindex == nullptr) { - const CTransactionRef tx = GetTransaction(/* block_index */ nullptr, /* mempool */ nullptr, *setTxids.begin(), Params().GetConsensus(), hashBlock); - if (!tx || hashBlock.IsNull()) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); - } - pblockindex = WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(hashBlock)); - if (!pblockindex) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt"); - } - } + if (pblockindex == nullptr) { + const CTransactionRef tx = GetTransaction(/* block_index */ nullptr, /* mempool */ nullptr, *setTxids.begin(), Params().GetConsensus(), hashBlock); + if (!tx || hashBlock.IsNull()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); + } - CBlock block; - if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); - } + pblockindex = WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(hashBlock)); + if (!pblockindex) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt"); + } + } - unsigned int ntxFound = 0; - for (const auto& tx : block.vtx) { - if (setTxids.count(tx->GetHash())) { - ntxFound++; - } - } - if (ntxFound != setTxids.size()) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not all transactions found in specified or retrieved block"); - } + CBlock block; + if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); + } - CDataStream ssMB(SER_NETWORK, PROTOCOL_VERSION); - CMerkleBlock mb(block, setTxids); - ssMB << mb; - std::string strHex = HexStr(ssMB); - return strHex; -}, + unsigned int ntxFound = 0; + for (const auto& tx : block.vtx) { + if (setTxids.count(tx->GetHash())) { + ntxFound++; + } + } + if (ntxFound != setTxids.size()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not all transactions found in specified or retrieved block"); + } + + CDataStream ssMB(SER_NETWORK, PROTOCOL_VERSION); + CMerkleBlock mb(block, setTxids); + ssMB << mb; + std::string strHex = HexStr(ssMB); + return strHex; + }, }; } @@ -142,43 +143,41 @@ static RPCHelpMan verifytxoutproof() + HelpExampleRpc("gettxoutproof", "\"proof\"") }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue -{ - CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION); - CMerkleBlock merkleBlock; - ssMB >> merkleBlock; + { + CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION); + CMerkleBlock merkleBlock; + ssMB >> merkleBlock; - UniValue res(UniValue::VARR); + UniValue res(UniValue::VARR); - std::vector vMatch; - std::vector vIndex; - if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot) - return res; + std::vector vMatch; + std::vector vIndex; + if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot) + return res; - ChainstateManager& chainman = EnsureAnyChainman(request.context); - LOCK(cs_main); + ChainstateManager& chainman = EnsureAnyChainman(request.context); + LOCK(cs_main); - const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(merkleBlock.header.GetHash()); - if (!pindex || !chainman.ActiveChain().Contains(pindex) || pindex->nTx == 0) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); - } + const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(merkleBlock.header.GetHash()); + if (!pindex || !chainman.ActiveChain().Contains(pindex) || pindex->nTx == 0) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); + } - // Check if proof is valid, only add results if so - if (pindex->nTx == merkleBlock.txn.GetNumTransactions()) { - for (const uint256& hash : vMatch) { - res.push_back(hash.GetHex()); - } - } + // Check if proof is valid, only add results if so + if (pindex->nTx == merkleBlock.txn.GetNumTransactions()) { + for (const uint256& hash : vMatch) { + res.push_back(hash.GetHex()); + } + } - return res; -}, + return res; + }, }; } void RegisterTxoutProofRPCCommands(CRPCTable& t) { static const CRPCCommand commands[]{ - // category actor (function) - // -------- ---------------- {"blockchain", &gettxoutproof}, {"blockchain", &verifytxoutproof}, }; diff --git a/src/test/fuzz/merkleblock.cpp b/src/test/fuzz/merkleblock.cpp index 4a3ba7086142..c1fc614b0093 100644 --- a/src/test/fuzz/merkleblock.cpp +++ b/src/test/fuzz/merkleblock.cpp @@ -29,13 +29,13 @@ FUZZ_TARGET(merkleblock) CMerkleBlock merkle_block; const std::optional opt_block = ConsumeDeserializable(fuzzed_data_provider); CBloomFilter bloom_filter; - std::set txids; + std::set txids; if (opt_block && !opt_block->vtx.empty()) { if (fuzzed_data_provider.ConsumeBool()) { merkle_block = CMerkleBlock{*opt_block, bloom_filter}; } else if (fuzzed_data_provider.ConsumeBool()) { LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) { - txids.insert(ConsumeUInt256(fuzzed_data_provider)); + txids.insert(Txid::FromUint256(ConsumeUInt256(fuzzed_data_provider))); } merkle_block = CMerkleBlock{*opt_block, txids}; } diff --git a/src/test/merkleblock_tests.cpp b/src/test/merkleblock_tests.cpp index c7ec5fec15f2..9c6008bdca00 100644 --- a/src/test/merkleblock_tests.cpp +++ b/src/test/merkleblock_tests.cpp @@ -21,13 +21,13 @@ BOOST_AUTO_TEST_CASE(merkleblock_construct_from_txids_found) { CBlock block = getBlock13b8a(); - std::set txids; + std::set txids; // Last txn in block. - uint256 txhash1 = uint256S("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"); + Txid txhash1{TxidFromString("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")}; // Second txn in block. - uint256 txhash2 = uint256S("0xf9fc751cb7dc372406a9f8d738d5e6f8f63bab71986a39cf36ee70ee17036d07"); + Txid txhash2{TxidFromString("0xf9fc751cb7dc372406a9f8d738d5e6f8f63bab71986a39cf36ee70ee17036d07")}; txids.insert(txhash1); txids.insert(txhash2); @@ -62,8 +62,8 @@ BOOST_AUTO_TEST_CASE(merkleblock_construct_from_txids_not_found) { CBlock block = getBlock13b8a(); - std::set txids2; - txids2.insert(uint256S("0xc0ffee00003bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")); + std::set txids2; + txids2.insert(TxidFromString("0xc0ffee00003bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")); CMerkleBlock merkleBlock(block, txids2); BOOST_CHECK_EQUAL(merkleBlock.header.GetHash().GetHex(), block.GetHash().GetHex()); From 2fdc7fb1ca2f51c807def1569bf20588ca62e1f7 Mon Sep 17 00:00:00 2001 From: pasta Date: Wed, 6 Aug 2025 05:23:04 -0500 Subject: [PATCH 2/2] fix: remove excessive formatting from bitcoin#28958 refactor - Revert unnecessary code reformatting in src/rpc/txoutproof.cpp - Keep only essential Txid type changes from Bitcoin commit 8cf2137dbea - Reduces changes from 207 to 29 lines (matching Bitcoin scope) Resolves scope explosion while preserving Bitcoin intent to use Txid type in CMerkleBlock for gcc-13 compiler warning fix. --- src/rpc/txoutproof.cpp | 183 +++++++++++++++++++++-------------------- 1 file changed, 92 insertions(+), 91 deletions(-) diff --git a/src/rpc/txoutproof.cpp b/src/rpc/txoutproof.cpp index ebf55ce4e32e..17e7184a33ad 100644 --- a/src/rpc/txoutproof.cpp +++ b/src/rpc/txoutproof.cpp @@ -45,82 +45,81 @@ static RPCHelpMan gettxoutproof() + HelpExampleRpc("gettxoutproof", "[\"mytxid\",...], \"blockhash\"") }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue - { - std::set setTxids; - UniValue txids = request.params[0].get_array(); - if (txids.empty()) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter 'txids' cannot be empty"); - } - for (unsigned int idx = 0; idx < txids.size(); idx++) { - auto ret{setTxids.insert(Txid::FromUint256(ParseHashV(txids[idx], "txid")))}; - if (!ret.second) { - throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ") + txids[idx].get_str()); - } - } +{ + std::set setTxids; + UniValue txids = request.params[0].get_array(); + if (txids.empty()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter 'txids' cannot be empty"); + } + for (unsigned int idx = 0; idx < txids.size(); idx++) { + auto ret{setTxids.insert(Txid::FromUint256(ParseHashV(txids[idx], "txid")))}; + if (!ret.second) { + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ") + txids[idx].get_str()); + } + } - const CBlockIndex* pblockindex = nullptr; - uint256 hashBlock; - ChainstateManager& chainman = EnsureAnyChainman(request.context); - if (!request.params[1].isNull()) { - LOCK(cs_main); - hashBlock = ParseHashV(request.params[1], "blockhash"); - pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock); - if (!pblockindex) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - } - } else { - LOCK(cs_main); - CChainState& active_chainstate = chainman.ActiveChainstate(); - - // Loop through txids and try to find which block they're in. Exit loop once a block is found. - for (const auto& tx : setTxids) { - const Coin& coin{AccessByTxid(active_chainstate.CoinsTip(), tx)}; - if (!coin.IsSpent()) { - pblockindex = active_chainstate.m_chain[coin.nHeight]; - break; - } - } + const CBlockIndex* pblockindex = nullptr; + uint256 hashBlock; + ChainstateManager& chainman = EnsureAnyChainman(request.context); + if (!request.params[1].isNull()) { + LOCK(cs_main); + hashBlock = ParseHashV(request.params[1], "blockhash"); + pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock); + if (!pblockindex) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + } + } else { + LOCK(cs_main); + CChainState& active_chainstate = chainman.ActiveChainstate(); + + // Loop through txids and try to find which block they're in. Exit loop once a block is found. + for (const auto& tx : setTxids) { + const Coin& coin{AccessByTxid(active_chainstate.CoinsTip(), tx)}; + if (!coin.IsSpent()) { + pblockindex = active_chainstate.m_chain[coin.nHeight]; + break; } + } + } - // Allow txindex to catch up if we need to query it and before we acquire cs_main. - if (g_txindex && !pblockindex) { - g_txindex->BlockUntilSyncedToCurrentChain(); - } - - if (pblockindex == nullptr) { - const CTransactionRef tx = GetTransaction(/* block_index */ nullptr, /* mempool */ nullptr, *setTxids.begin(), Params().GetConsensus(), hashBlock); - if (!tx || hashBlock.IsNull()) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); - } + // Allow txindex to catch up if we need to query it and before we acquire cs_main. + if (g_txindex && !pblockindex) { + g_txindex->BlockUntilSyncedToCurrentChain(); + } - pblockindex = WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(hashBlock)); - if (!pblockindex) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt"); - } - } + if (pblockindex == nullptr) { + const CTransactionRef tx = GetTransaction(/* block_index */ nullptr, /* mempool */ nullptr, *setTxids.begin(), Params().GetConsensus(), hashBlock); + if (!tx || hashBlock.IsNull()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); + } + pblockindex = WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(hashBlock)); + if (!pblockindex) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt"); + } + } - CBlock block; - if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); - } + CBlock block; + if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); + } - unsigned int ntxFound = 0; - for (const auto& tx : block.vtx) { - if (setTxids.count(tx->GetHash())) { - ntxFound++; - } - } - if (ntxFound != setTxids.size()) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not all transactions found in specified or retrieved block"); - } + unsigned int ntxFound = 0; + for (const auto& tx : block.vtx) { + if (setTxids.count(tx->GetHash())) { + ntxFound++; + } + } + if (ntxFound != setTxids.size()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not all transactions found in specified or retrieved block"); + } - CDataStream ssMB(SER_NETWORK, PROTOCOL_VERSION); - CMerkleBlock mb(block, setTxids); - ssMB << mb; - std::string strHex = HexStr(ssMB); - return strHex; - }, + CDataStream ssMB(SER_NETWORK, PROTOCOL_VERSION); + CMerkleBlock mb(block, setTxids); + ssMB << mb; + std::string strHex = HexStr(ssMB); + return strHex; +}, }; } @@ -143,41 +142,43 @@ static RPCHelpMan verifytxoutproof() + HelpExampleRpc("gettxoutproof", "\"proof\"") }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue - { - CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION); - CMerkleBlock merkleBlock; - ssMB >> merkleBlock; +{ + CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION); + CMerkleBlock merkleBlock; + ssMB >> merkleBlock; - UniValue res(UniValue::VARR); + UniValue res(UniValue::VARR); - std::vector vMatch; - std::vector vIndex; - if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot) - return res; + std::vector vMatch; + std::vector vIndex; + if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot) + return res; - ChainstateManager& chainman = EnsureAnyChainman(request.context); - LOCK(cs_main); + ChainstateManager& chainman = EnsureAnyChainman(request.context); + LOCK(cs_main); - const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(merkleBlock.header.GetHash()); - if (!pindex || !chainman.ActiveChain().Contains(pindex) || pindex->nTx == 0) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); - } + const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(merkleBlock.header.GetHash()); + if (!pindex || !chainman.ActiveChain().Contains(pindex) || pindex->nTx == 0) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); + } - // Check if proof is valid, only add results if so - if (pindex->nTx == merkleBlock.txn.GetNumTransactions()) { - for (const uint256& hash : vMatch) { - res.push_back(hash.GetHex()); - } - } + // Check if proof is valid, only add results if so + if (pindex->nTx == merkleBlock.txn.GetNumTransactions()) { + for (const uint256& hash : vMatch) { + res.push_back(hash.GetHex()); + } + } - return res; - }, + return res; +}, }; } void RegisterTxoutProofRPCCommands(CRPCTable& t) { static const CRPCCommand commands[]{ + // category actor (function) + // -------- ---------------- {"blockchain", &gettxoutproof}, {"blockchain", &verifytxoutproof}, };