| 298 | } |
| 299 | |
| 300 | static UniValue verifytxoutproof(const JSONRPCRequest& request) |
| 301 | { |
| 302 | if (request.fHelp || request.params.size() != 1) |
| 303 | throw std::runtime_error( |
| 304 | "verifytxoutproof \"proof\"\n" |
| 305 | "\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n" |
| 306 | "and throwing an RPC error if the block is not in our best chain\n" |
| 307 | "\nArguments:\n" |
| 308 | "1. \"proof\" (string, required) The hex-encoded proof generated by gettxoutproof\n" |
| 309 | "\nResult:\n" |
| 310 | "[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof can not be validated.\n" |
| 311 | ); |
| 312 | |
| 313 | CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS); |
| 314 | CMerkleBlock merkleBlock; |
| 315 | ssMB >> merkleBlock; |
| 316 | |
| 317 | UniValue res(UniValue::VARR); |
| 318 | |
| 319 | std::vector<uint256> vMatch; |
| 320 | std::vector<unsigned int> vIndex; |
| 321 | if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot) |
| 322 | return res; |
| 323 | |
| 324 | LOCK(cs_main); |
| 325 | |
| 326 | const CBlockIndex* pindex = LookupBlockIndex(merkleBlock.header.GetHash()); |
| 327 | if (!pindex || !chainActive.Contains(pindex) || pindex->nTx == 0) { |
| 328 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); |
| 329 | } |
| 330 | |
| 331 | // Check if proof is valid, only add results if so |
| 332 | if (pindex->nTx == merkleBlock.txn.GetNumTransactions()) { |
| 333 | for (const uint256& hash : vMatch) { |
| 334 | res.push_back(hash.GetHex()); |
| 335 | } |
| 336 | } |
| 337 | |
| 338 | return res; |
| 339 | } |
| 340 | |
| 341 | CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf) |
| 342 | { |
nothing calls this directly
no test coverage detected