From eb78a45a0ce9a0bcc877a0131b94f4f56d650d30 Mon Sep 17 00:00:00 2001 From: Peter Pratscher Date: Sat, 17 Mar 2018 19:06:05 +0100 Subject: [PATCH 1/3] Backported Bitcoin PR #8704 to optionally return full tx details in the getblock rpc call --- src/rpcblockchain.cpp | 37 +++++++++++++++++++++++++------------ src/rpcserver.cpp | 2 ++ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 2ef75a70a..5599073ae 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -395,12 +395,15 @@ UniValue getblock(const UniValue& params, bool fHelp) if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "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" + "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n" + "If verbosity is 1, returns an Object with information about block .\n" + "If verbosity is 2, returns an Object with information about block and information about each transaction. \n" "\nArguments:\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" + "1. \"blockhash\" (string, required) The block hash\n" + "2. verbosity (numeric, optional, default=1) 0 for hex encoded data, 1 for a json object, and 2 for json object with transaction data\n" + "\nResult (for verbosity = 0):\n" + "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" + "\nResult (for verbosity = 1):\n" "{\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" @@ -419,8 +422,14 @@ UniValue getblock(const UniValue& params, bool fHelp) " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n" "}\n" - "\nResult (for verbose=false):\n" - "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" + "\nResult (for verbosity = 2):\n" + "{\n" + " ..., Same output as verbosity = 1.\n" + " \"tx\" : [ (array of Objects) The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result.\n" + " ,...\n" + " ],\n" + " ,... Same output as verbosity = 1.\n" + "}\n" "\nExamples:\n" + HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") @@ -456,9 +465,13 @@ UniValue getblock(const UniValue& params, bool fHelp) uint256 hash(uint256S(strHash)); - bool fVerbose = true; - if (params.size() > 1) - fVerbose = params[1].get_bool(); + int verbosity = 1; + if (params.size() > 1) { + if(params[1].isNum()) + verbosity = params[1].get_int(); + else + verbosity = params[1].get_bool() ? 1 : 0; + } if (mapBlockIndex.count(hash) == 0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); @@ -472,7 +485,7 @@ UniValue getblock(const UniValue& params, bool fHelp) if(!ReadBlockFromDisk(block, pblockindex)) throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); - if (!fVerbose) + if (verbosity <= 0) { CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); ssBlock << block; @@ -480,7 +493,7 @@ UniValue getblock(const UniValue& params, bool fHelp) return strHex; } - return blockToJSON(block, pblockindex); + return blockToJSON(block, pblockindex, verbosity >= 2); } UniValue gettxoutsetinfo(const UniValue& params, bool fHelp) diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 86e27867e..ca4cfc9b2 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -27,6 +27,8 @@ #include #include #include // for to_upper() +#include +#include using namespace RPCServer; using namespace std; From bf911b3038fdcf39c4b7e7250fafc4dff9400b84 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 30 Apr 2018 09:24:41 -0700 Subject: [PATCH 2/3] Tweaks to d0a1d83 to complete backport of Bitcoin PR #8704 --- src/rpcblockchain.cpp | 4 ++-- src/rpcserver.cpp | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 5599073ae..d8b75f0ce 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -394,12 +394,12 @@ UniValue getblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( - "getblock \"hash|height\" ( verbose )\n" + "getblock \"hash|height\" ( verbosity )\n" "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n" "If verbosity is 1, returns an Object with information about block .\n" "If verbosity is 2, returns an Object with information about block and information about each transaction. \n" "\nArguments:\n" - "1. \"blockhash\" (string, required) The block hash\n" + "1. \"hash|height\" (string, required) The block hash or height\n" "2. verbosity (numeric, optional, default=1) 0 for hex encoded data, 1 for a json object, and 2 for json object with transaction data\n" "\nResult (for verbosity = 0):\n" "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index ca4cfc9b2..86e27867e 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -27,8 +27,6 @@ #include #include #include // for to_upper() -#include -#include using namespace RPCServer; using namespace std; From 9bd8f092c637c6c9368a15174d338668be617747 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 30 Apr 2018 11:51:59 -0700 Subject: [PATCH 3/3] Closes #3178 by adding verbosity level improvements to getblock RPC. This is a follow-up commit for d0a1d833520d120bb5a2ac4cf4192047af6afe24 found in PR #3095 in order to fix nits and add a test. --- qa/rpc-tests/merkle_blocks.py | 9 +++++++++ src/rpcblockchain.cpp | 23 ++++++++++++++--------- src/test/rpc_wallet_tests.cpp | 5 +++++ 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/qa/rpc-tests/merkle_blocks.py b/qa/rpc-tests/merkle_blocks.py index 2c0fcd203..13b98e140 100755 --- a/qa/rpc-tests/merkle_blocks.py +++ b/qa/rpc-tests/merkle_blocks.py @@ -7,6 +7,7 @@ # Test merkleblock fetch/validation # +import string from test_framework.test_framework import BitcoinTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, assert_raises, \ @@ -86,5 +87,13 @@ class MerkleBlockTest(BitcoinTestFramework): # ...or if we have a -txindex assert_equal(self.nodes[2].verifytxoutproof(self.nodes[3].gettxoutproof([txid_spent])), [txid_spent]) + # Quick test of getblock using blockhash and different levels of verbosity + result = self.nodes[0].getblock(blockhash, 2) + coinbase_txid = result["tx"][0]["txid"] + result = self.nodes[0].getblock(blockhash, 1) + assert_equal(coinbase_txid, result["tx"][0]) # verbosity 1 only lists txids + result = self.nodes[0].getblock(blockhash, 0) + assert(c in string.hexdigits for c in result) # verbosity 0 returns raw hex + if __name__ == '__main__': MerkleBlockTest().main() diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index d8b75f0ce..c0565a8fc 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -395,14 +395,14 @@ UniValue getblock(const UniValue& params, bool fHelp) if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "getblock \"hash|height\" ( verbosity )\n" - "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n" - "If verbosity is 1, returns an Object with information about block .\n" - "If verbosity is 2, returns an Object with information about block and information about each transaction. \n" + "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for the block.\n" + "If verbosity is 1, returns an Object with information about the block.\n" + "If verbosity is 2, returns an Object with information about the block and information about each transaction. \n" "\nArguments:\n" "1. \"hash|height\" (string, required) The block hash or height\n" "2. verbosity (numeric, optional, default=1) 0 for hex encoded data, 1 for a json object, and 2 for json object with transaction data\n" "\nResult (for verbosity = 0):\n" - "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" + "\"data\" (string) A string that is serialized, hex-encoded data for the block.\n" "\nResult (for verbosity = 1):\n" "{\n" " \"hash\" : \"hash\", (string) the block hash (same as provided hash)\n" @@ -431,8 +431,8 @@ UniValue getblock(const UniValue& params, bool fHelp) " ,... Same output as verbosity = 1.\n" "}\n" "\nExamples:\n" - + HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") - + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") + + HelpExampleCli("getblock", "\"00000000febc373a1da2bd9f887b105ad79ddc26ac26c2b28652d64e5207c5b5\"") + + HelpExampleRpc("getblock", "\"00000000febc373a1da2bd9f887b105ad79ddc26ac26c2b28652d64e5207c5b5\"") + HelpExampleCli("getblock", "12800") + HelpExampleRpc("getblock", "12800") ); @@ -467,10 +467,15 @@ UniValue getblock(const UniValue& params, bool fHelp) int verbosity = 1; if (params.size() > 1) { - if(params[1].isNum()) + if(params[1].isNum()) { verbosity = params[1].get_int(); - else + } else { verbosity = params[1].get_bool() ? 1 : 0; + } + } + + if (verbosity < 0 || verbosity > 2) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Verbosity must be in range from 0 to 2"); } if (mapBlockIndex.count(hash) == 0) @@ -485,7 +490,7 @@ UniValue getblock(const UniValue& params, bool fHelp) if(!ReadBlockFromDisk(block, pblockindex)) throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); - if (verbosity <= 0) + if (verbosity == 0) { CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); ssBlock << block; diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index ce2da60c1..81d8e3a62 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -291,6 +291,11 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) 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_CHECK_NO_THROW(CallRPC("getblock 0 0")); + BOOST_CHECK_NO_THROW(CallRPC("getblock 0 1")); + BOOST_CHECK_NO_THROW(CallRPC("getblock 0 2")); + BOOST_CHECK_THROW(CallRPC("getblock 0 -1"), runtime_error); // bad verbosity + BOOST_CHECK_THROW(CallRPC("getblock 0 3"), runtime_error); // bad verbosity } BOOST_AUTO_TEST_CASE(rpc_wallet_getbalance)