From 7d3b1528971c1573407c55aad92f6520ef5f2a9b Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 16 Mar 2017 11:30:41 -0700 Subject: [PATCH] Closes #2186. RPC getblock now accepts height or hash. --- src/rpcblockchain.cpp | 41 +++++++++++++++++++++++++++++------ src/test/rpc_wallet_tests.cpp | 10 +++++++++ 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 24bff3f4..b0eaea60 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -15,6 +15,8 @@ #include +#include + using namespace std; extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); @@ -362,18 +364,18 @@ UniValue getblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( - "getblock \"hash\" ( verbose )\n" - "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n" - "If verbose is true, returns an Object with information about block .\n" + "getblock \"hash|height\" ( verbose )\n" + "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash|height'.\n" + "If verbose is true, returns an Object with information about block .\n" "\nArguments:\n" - "1. \"hash\" (string, required) The block hash\n" + "1. \"hash|height\" (string, required) The block hash or height\n" "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" "\nResult (for verbose = true):\n" "{\n" - " \"hash\" : \"hash\", (string) the block hash (same as provided)\n" + " \"hash\" : \"hash\", (string) the block hash (same as provided hash)\n" " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" " \"size\" : n, (numeric) The block size\n" - " \"height\" : n, (numeric) The block height or index\n" + " \"height\" : n, (numeric) The block height or index (same as provided height)\n" " \"version\" : n, (numeric) The block version\n" " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" " \"tx\" : [ (array of string) The transaction ids\n" @@ -382,7 +384,7 @@ UniValue getblock(const UniValue& params, bool fHelp) " ],\n" " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"nonce\" : n, (numeric) The nonce\n" - " \"bits\" : \"1d00ffff\", (string) The bits\n" + " \"bits\" : \"1d00ffff\", (string) The bits\n" " \"difficulty\" : x.xxx, (numeric) The difficulty\n" " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n" @@ -392,11 +394,36 @@ UniValue getblock(const UniValue& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") + + HelpExampleCli("getblock", "12800") + + HelpExampleRpc("getblock", "12800") ); LOCK(cs_main); std::string strHash = params[0].get_str(); + + // If height is supplied, find the hash + if (strHash.size() < (2 * sizeof(uint256))) { + // std::stoi allows characters, whereas we want to be strict + regex r("[[:digit:]]+"); + if (!regex_match(strHash, r)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block height parameter"); + } + + int nHeight = -1; + try { + nHeight = std::stoi(strHash); + } + catch (const std::exception &e) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block height parameter"); + } + + if (nHeight < 0 || nHeight > chainActive.Height()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); + } + strHash = chainActive[nHeight]->GetBlockHash().GetHex(); + } + uint256 hash(uint256S(strHash)); bool fVerbose = true; diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index ea74d52f..c7617aa5 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -271,6 +271,16 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) obj = retValue.get_obj(); BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), 3.125); BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 0.0); + + /* + * getblock + */ + BOOST_CHECK_THROW(CallRPC("getblock too many args"), runtime_error); + BOOST_CHECK_THROW(CallRPC("getblock -1"), runtime_error); + BOOST_CHECK_THROW(CallRPC("getblock 2147483647"), runtime_error); // allowed, but > height of active chain tip + BOOST_CHECK_THROW(CallRPC("getblock 2147483648"), runtime_error); // not allowed, > int32 used for nHeight + BOOST_CHECK_THROW(CallRPC("getblock 100badchars"), runtime_error); + BOOST_CHECK_NO_THROW(CallRPC("getblock 0")); } BOOST_AUTO_TEST_CASE(rpc_wallet_getbalance)