| 198 | } |
| 199 | |
| 200 | UniValue gettxoutproof(const UniValue& params, bool fHelp) |
| 201 | { |
| 202 | if (fHelp || (params.size() != 1 && params.size() != 2)) |
| 203 | throw runtime_error( |
| 204 | "gettxoutproof [\"txid\",...] ( blockhash )\n" |
| 205 | "\nReturns a hex-encoded proof that \"txid\" was included in a block.\n" |
| 206 | "\nNOTE: By default this function only works sometimes. This is when there is an\n" |
| 207 | "unspent output in the utxo for this transaction. To make it always work,\n" |
| 208 | "you need to maintain a transaction index, using the -txindex command line option or\n" |
| 209 | "specify the block in which the transaction is included in manually (by blockhash).\n" |
| 210 | "\nReturn the raw transaction data.\n" |
| 211 | "\nArguments:\n" |
| 212 | "1. \"txids\" (string) A json array of txids to filter\n" |
| 213 | " [\n" |
| 214 | " \"txid\" (string) A transaction hash\n" |
| 215 | " ,...\n" |
| 216 | " ]\n" |
| 217 | "2. \"block hash\" (string, optional) If specified, looks for txid in the block with this hash\n" |
| 218 | "\nResult:\n" |
| 219 | "\"data\" (string) A string that is a serialized, hex-encoded data for the proof.\n" |
| 220 | ); |
| 221 | |
| 222 | set<uint256> setTxids; |
| 223 | uint256 oneTxid; |
| 224 | UniValue txids = params[0].get_array(); |
| 225 | for (unsigned int idx = 0; idx < txids.size(); idx++) { |
| 226 | const UniValue& txid = txids[idx]; |
| 227 | if (txid.get_str().length() != 64 || !IsHex(txid.get_str())) |
| 228 | throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid txid ")+txid.get_str()); |
| 229 | uint256 hash(uint256S(txid.get_str())); |
| 230 | if (setTxids.count(hash)) |
| 231 | throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated txid: ")+txid.get_str()); |
| 232 | setTxids.insert(hash); |
| 233 | oneTxid = hash; |
| 234 | } |
| 235 | |
| 236 | LOCK(cs_main); |
| 237 | |
| 238 | CBlockIndex* pblockindex = NULL; |
| 239 | |
| 240 | uint256 hashBlock; |
| 241 | if (params.size() > 1) |
| 242 | { |
| 243 | hashBlock = uint256S(params[1].get_str()); |
| 244 | if (!mapBlockIndex.count(hashBlock)) |
| 245 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); |
| 246 | pblockindex = mapBlockIndex[hashBlock]; |
| 247 | } else { |
| 248 | CCoins coins; |
| 249 | if (pcoinsTip->GetCoins(oneTxid, coins) && coins.nHeight > 0 && coins.nHeight <= chainActive.Height()) |
| 250 | pblockindex = chainActive[coins.nHeight]; |
| 251 | } |
| 252 | |
| 253 | if (pblockindex == NULL) |
| 254 | { |
| 255 | CTransaction tx; |
| 256 | if (!GetTransaction(oneTxid, tx, hashBlock, false) || hashBlock.IsNull()) |
| 257 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); |
nothing calls this directly
no test coverage detected