diff options
Diffstat (limited to 'src/rpcblockchain.cpp')
| -rw-r--r-- | src/rpcblockchain.cpp | 231 |
1 files changed, 188 insertions, 43 deletions
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 79528db2f..80d49490d 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -3,23 +3,29 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "amount.h" +#include "chain.h" +#include "chainparams.h" #include "checkpoints.h" +#include "coins.h" #include "consensus/validation.h" #include "main.h" #include "primitives/transaction.h" #include "rpcserver.h" +#include "streams.h" #include "sync.h" +#include "txmempool.h" #include "util.h" +#include "utilstrencodings.h" #include <stdint.h> -#include "json/json_spirit_value.h" +#include "univalue/univalue.h" -using namespace json_spirit; using namespace std; -extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry); -void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex); +extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); +void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); double GetDifficulty(const CBlockIndex* blockindex) { @@ -52,10 +58,35 @@ double GetDifficulty(const CBlockIndex* blockindex) return dDiff; } +UniValue blockheaderToJSON(const CBlockIndex* blockindex) +{ + UniValue result(UniValue::VOBJ); + result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex())); + int confirmations = -1; + // Only report confirmations if the block is on the main chain + if (chainActive.Contains(blockindex)) + confirmations = chainActive.Height() - blockindex->nHeight + 1; + result.push_back(Pair("confirmations", confirmations)); + result.push_back(Pair("height", blockindex->nHeight)); + result.push_back(Pair("version", blockindex->nVersion)); + result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex())); + result.push_back(Pair("time", (int64_t)blockindex->nTime)); + result.push_back(Pair("nonce", (uint64_t)blockindex->nNonce)); + result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); + result.push_back(Pair("difficulty", GetDifficulty(blockindex))); + result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); -Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) + if (blockindex->pprev) + result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); + CBlockIndex *pnext = chainActive.Next(blockindex); + if (pnext) + result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); + return result; +} + +UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("hash", block.GetHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain @@ -66,12 +97,12 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDe result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); - Array txs; + UniValue txs(UniValue::VARR); BOOST_FOREACH(const CTransaction&tx, block.vtx) { if(txDetails) { - Object objTx; + UniValue objTx(UniValue::VOBJ); TxToJSON(tx, uint256(), objTx); txs.push_back(objTx); } @@ -93,8 +124,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDe return result; } - -Value getblockcount(const Array& params, bool fHelp) +UniValue getblockcount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -111,7 +141,7 @@ Value getblockcount(const Array& params, bool fHelp) return chainActive.Height(); } -Value getbestblockhash(const Array& params, bool fHelp) +UniValue getbestblockhash(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -128,7 +158,7 @@ Value getbestblockhash(const Array& params, bool fHelp) return chainActive.Tip()->GetBlockHash().GetHex(); } -Value getdifficulty(const Array& params, bool fHelp) +UniValue getdifficulty(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -146,7 +176,7 @@ Value getdifficulty(const Array& params, bool fHelp) } -Value getrawmempool(const Array& params, bool fHelp) +UniValue getrawmempool(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( @@ -163,7 +193,7 @@ Value getrawmempool(const Array& params, bool fHelp) "{ (json object)\n" " \"transactionid\" : { (json object)\n" " \"size\" : n, (numeric) transaction size in bytes\n" - " \"fee\" : n, (numeric) transaction fee in bitcoins\n" + " \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n" " \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n" " \"height\" : n, (numeric) block height when transaction entered pool\n" " \"startingpriority\" : n, (numeric) priority when transaction entered pool\n" @@ -187,12 +217,12 @@ Value getrawmempool(const Array& params, bool fHelp) if (fVerbose) { LOCK(mempool.cs); - Object o; + UniValue o(UniValue::VOBJ); BOOST_FOREACH(const PAIRTYPE(uint256, CTxMemPoolEntry)& entry, mempool.mapTx) { const uint256& hash = entry.first; const CTxMemPoolEntry& e = entry.second; - Object info; + UniValue info(UniValue::VOBJ); info.push_back(Pair("size", (int)e.GetTxSize())); info.push_back(Pair("fee", ValueFromAmount(e.GetFee()))); info.push_back(Pair("time", e.GetTime())); @@ -206,7 +236,13 @@ Value getrawmempool(const Array& params, bool fHelp) if (mempool.exists(txin.prevout.hash)) setDepends.insert(txin.prevout.hash.ToString()); } - Array depends(setDepends.begin(), setDepends.end()); + + UniValue depends(UniValue::VARR); + BOOST_FOREACH(const string& dep, setDepends) + { + depends.push_back(dep); + } + info.push_back(Pair("depends", depends)); o.push_back(Pair(hash.ToString(), info)); } @@ -217,7 +253,7 @@ Value getrawmempool(const Array& params, bool fHelp) vector<uint256> vtxid; mempool.queryHashes(vtxid); - Array a; + UniValue a(UniValue::VARR); BOOST_FOREACH(const uint256& hash, vtxid) a.push_back(hash.ToString()); @@ -225,7 +261,7 @@ Value getrawmempool(const Array& params, bool fHelp) } } -Value getblockhash(const Array& params, bool fHelp) +UniValue getblockhash(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -250,7 +286,63 @@ Value getblockhash(const Array& params, bool fHelp) return pblockindex->GetBlockHash().GetHex(); } -Value getblock(const Array& params, bool fHelp) +UniValue getblockheader(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getblockheader \"hash\" ( verbose )\n" + "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n" + "If verbose is true, returns an Object with information about blockheader <hash>.\n" + "\nArguments:\n" + "1. \"hash\" (string, required) The block hash\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" + " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" + " \"height\" : n, (numeric) The block height or index\n" + " \"version\" : n, (numeric) The block version\n" + " \"merkleroot\" : \"xxxx\", (string) The merkle root\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" + " \"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" + "}\n" + "\nResult (for verbose=false):\n" + "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" + "\nExamples:\n" + + HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") + + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") + ); + + LOCK(cs_main); + + std::string strHash = params[0].get_str(); + uint256 hash(uint256S(strHash)); + + bool fVerbose = true; + if (params.size() > 1) + fVerbose = params[1].get_bool(); + + if (mapBlockIndex.count(hash) == 0) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + + CBlockIndex* pblockindex = mapBlockIndex[hash]; + + if (!fVerbose) + { + CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); + ssBlock << pblockindex->GetBlockHeader(); + std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()); + return strHex; + } + + return blockheaderToJSON(pblockindex); +} + +UniValue getblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -318,7 +410,7 @@ Value getblock(const Array& params, bool fHelp) return blockToJSON(block, pblockindex); } -Value gettxoutsetinfo(const Array& params, bool fHelp) +UniValue gettxoutsetinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -340,9 +432,7 @@ Value gettxoutsetinfo(const Array& params, bool fHelp) + HelpExampleRpc("gettxoutsetinfo", "") ); - LOCK(cs_main); - - Object ret; + UniValue ret(UniValue::VOBJ); CCoinsStats stats; FlushStateToDisk(); @@ -358,7 +448,7 @@ Value gettxoutsetinfo(const Array& params, bool fHelp) return ret; } -Value gettxout(const Array& params, bool fHelp) +UniValue gettxout(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 3) throw runtime_error( @@ -372,7 +462,7 @@ Value gettxout(const Array& params, bool fHelp) "{\n" " \"bestblock\" : \"hash\", (string) the block hash\n" " \"confirmations\" : n, (numeric) The number of confirmations\n" - " \"value\" : x.xxx, (numeric) The transaction value in btc\n" + " \"value\" : x.xxx, (numeric) The transaction value in " + CURRENCY_UNIT + "\n" " \"scriptPubKey\" : { (json object)\n" " \"asm\" : \"code\", (string) \n" " \"hex\" : \"hex\", (string) \n" @@ -398,7 +488,7 @@ Value gettxout(const Array& params, bool fHelp) LOCK(cs_main); - Object ret; + UniValue ret(UniValue::VOBJ); std::string strHash = params[0].get_str(); uint256 hash(uint256S(strHash)); @@ -412,14 +502,14 @@ Value gettxout(const Array& params, bool fHelp) LOCK(mempool.cs); CCoinsViewMemPool view(pcoinsTip, mempool); if (!view.GetCoins(hash, coins)) - return Value::null; + return NullUniValue; mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool } else { if (!pcoinsTip->GetCoins(hash, coins)) - return Value::null; + return NullUniValue; } if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull()) - return Value::null; + return NullUniValue; BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); CBlockIndex *pindex = it->second; @@ -429,7 +519,7 @@ Value gettxout(const Array& params, bool fHelp) else ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1)); ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue))); - Object o; + UniValue o(UniValue::VOBJ); ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true); ret.push_back(Pair("scriptPubKey", o)); ret.push_back(Pair("version", coins.nVersion)); @@ -438,7 +528,7 @@ Value gettxout(const Array& params, bool fHelp) return ret; } -Value verifychain(const Array& params, bool fHelp) +UniValue verifychain(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 2) throw runtime_error( @@ -466,7 +556,37 @@ Value verifychain(const Array& params, bool fHelp) return CVerifyDB().VerifyDB(pcoinsTip, nCheckLevel, nCheckDepth); } -Value getblockchaininfo(const Array& params, bool fHelp) +/** Implementation of IsSuperMajority with better feedback */ +static UniValue SoftForkMajorityDesc(int minVersion, CBlockIndex* pindex, int nRequired, const Consensus::Params& consensusParams) +{ + int nFound = 0; + CBlockIndex* pstart = pindex; + for (int i = 0; i < consensusParams.nMajorityWindow && pstart != NULL; i++) + { + if (pstart->nVersion >= minVersion) + ++nFound; + pstart = pstart->pprev; + } + + UniValue rv(UniValue::VOBJ); + rv.push_back(Pair("status", nFound >= nRequired)); + rv.push_back(Pair("found", nFound)); + rv.push_back(Pair("required", nRequired)); + rv.push_back(Pair("window", consensusParams.nMajorityWindow)); + return rv; +} + +static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* pindex, const Consensus::Params& consensusParams) +{ + UniValue rv(UniValue::VOBJ); + rv.push_back(Pair("id", name)); + rv.push_back(Pair("version", version)); + rv.push_back(Pair("enforce", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams))); + rv.push_back(Pair("reject", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityRejectBlockOutdated, consensusParams))); + return rv; +} + +UniValue getblockchaininfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -481,6 +601,21 @@ Value getblockchaininfo(const Array& params, bool fHelp) " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" " \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n" " \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n" + " \"pruned\": xx, (boolean) if the blocks are subject to pruning\n" + " \"pruneheight\": xxxxxx, (numeric) heighest block available\n" + " \"softforks\": [ (array) status of softforks in progress\n" + " {\n" + " \"id\": \"xxxx\", (string) name of softfork\n" + " \"version\": xx, (numeric) block version\n" + " \"enforce\": { (object) progress toward enforcing the softfork rules for new-version blocks\n" + " \"status\": xx, (boolean) true if threshold reached\n" + " \"found\": xx, (numeric) number of blocks with the new version found\n" + " \"required\": xx, (numeric) number of blocks required to trigger\n" + " \"window\": xx, (numeric) maximum size of examined window of recent blocks\n" + " },\n" + " \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n" + " }, ...\n" + " ]\n" "}\n" "\nExamples:\n" + HelpExampleCli("getblockchaininfo", "") @@ -489,7 +624,7 @@ Value getblockchaininfo(const Array& params, bool fHelp) LOCK(cs_main); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("chain", Params().NetworkIDString())); obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1)); @@ -498,6 +633,14 @@ Value getblockchaininfo(const Array& params, bool fHelp) obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip()))); obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex())); obj.push_back(Pair("pruned", fPruneMode)); + + const Consensus::Params& consensusParams = Params().GetConsensus(); + CBlockIndex* tip = chainActive.Tip(); + UniValue softforks(UniValue::VARR); + softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams)); + softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams)); + obj.push_back(Pair("softforks", softforks)); + if (fPruneMode) { CBlockIndex *block = chainActive.Tip(); @@ -524,7 +667,7 @@ struct CompareBlocksByHeight } }; -Value getchaintips(const Array& params, bool fHelp) +UniValue getchaintips(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -576,10 +719,10 @@ Value getchaintips(const Array& params, bool fHelp) setTips.insert(chainActive.Tip()); /* Construct the output array. */ - Array res; + UniValue res(UniValue::VARR); BOOST_FOREACH(const CBlockIndex* block, setTips) { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("height", block->nHeight)); obj.push_back(Pair("hash", block->phashBlock->GetHex())); @@ -614,7 +757,7 @@ Value getchaintips(const Array& params, bool fHelp) return res; } -Value getmempoolinfo(const Array& params, bool fHelp) +UniValue getmempoolinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -624,20 +767,22 @@ Value getmempoolinfo(const Array& params, bool fHelp) "{\n" " \"size\": xxxxx (numeric) Current tx count\n" " \"bytes\": xxxxx (numeric) Sum of all tx sizes\n" + " \"usage\": xxxxx (numeric) Total memory usage for the mempool\n" "}\n" "\nExamples:\n" + HelpExampleCli("getmempoolinfo", "") + HelpExampleRpc("getmempoolinfo", "") ); - Object ret; + UniValue ret(UniValue::VOBJ); ret.push_back(Pair("size", (int64_t) mempool.size())); ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize())); + ret.push_back(Pair("usage", (int64_t) mempool.DynamicMemoryUsage())); return ret; } -Value invalidateblock(const Array& params, bool fHelp) +UniValue invalidateblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -672,10 +817,10 @@ Value invalidateblock(const Array& params, bool fHelp) throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); } - return Value::null; + return NullUniValue; } -Value reconsiderblock(const Array& params, bool fHelp) +UniValue reconsiderblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -711,5 +856,5 @@ Value reconsiderblock(const Array& params, bool fHelp) throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); } - return Value::null; + return NullUniValue; } |