2012-08-21 17:03:38 +02:00
|
|
|
// Copyright (c) 2010 Satoshi Nakamoto
|
2014-12-05 09:25:30 +01:00
|
|
|
// Copyright (c) 2009-2014 The Bitcoin developers
|
2015-03-18 00:06:58 +01:00
|
|
|
// Copyright (c) 2014-2015 The Dash developers
|
2014-11-20 03:19:29 +01:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
2012-08-21 17:03:38 +02:00
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
2014-05-10 14:54:20 +02:00
|
|
|
#include "checkpoints.h"
|
2013-04-13 07:13:08 +02:00
|
|
|
#include "main.h"
|
2014-05-10 14:54:20 +02:00
|
|
|
#include "rpcserver.h"
|
2013-04-13 07:13:08 +02:00
|
|
|
#include "sync.h"
|
Split up util.cpp/h
Split up util.cpp/h into:
- string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach)
- money utilities (parsesmoney, formatmoney)
- time utilities (gettime*, sleep, format date):
- and the rest (logging, argument parsing, config file parsing)
The latter is basically the environment and OS handling,
and is stripped of all utility functions, so we may want to
rename it to something else than util.cpp/h for clarity (Matt suggested
osinterface).
Breaks dependency of sha256.cpp on all the things pulled in by util.
2014-08-21 16:11:09 +02:00
|
|
|
#include "util.h"
|
2013-04-13 07:13:08 +02:00
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
#include "json/json_spirit_value.h"
|
2012-08-21 17:03:38 +02:00
|
|
|
|
|
|
|
using namespace json_spirit;
|
|
|
|
using namespace std;
|
|
|
|
|
2014-11-28 20:32:52 +01:00
|
|
|
extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry);
|
2013-07-15 07:22:10 +02:00
|
|
|
void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex);
|
2013-01-04 22:51:00 +01:00
|
|
|
|
2012-08-21 17:03:38 +02:00
|
|
|
double GetDifficulty(const CBlockIndex* blockindex)
|
|
|
|
{
|
|
|
|
// Floating point number that is a multiple of the minimum difficulty,
|
|
|
|
// minimum difficulty = 1.0.
|
|
|
|
if (blockindex == NULL)
|
|
|
|
{
|
2013-10-10 23:07:44 +02:00
|
|
|
if (chainActive.Tip() == NULL)
|
2012-08-21 17:03:38 +02:00
|
|
|
return 1.0;
|
|
|
|
else
|
2013-10-10 23:07:44 +02:00
|
|
|
blockindex = chainActive.Tip();
|
2012-08-21 17:03:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int nShift = (blockindex->nBits >> 24) & 0xff;
|
|
|
|
|
|
|
|
double dDiff =
|
|
|
|
(double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
|
|
|
|
|
|
|
|
while (nShift < 29)
|
|
|
|
{
|
|
|
|
dDiff *= 256.0;
|
|
|
|
nShift++;
|
|
|
|
}
|
|
|
|
while (nShift > 29)
|
|
|
|
{
|
|
|
|
dDiff /= 256.0;
|
|
|
|
nShift--;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dDiff;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-28 20:32:52 +01:00
|
|
|
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
|
2012-08-21 17:03:38 +02:00
|
|
|
{
|
|
|
|
Object result;
|
|
|
|
result.push_back(Pair("hash", block.GetHash().GetHex()));
|
2014-08-28 17:14:22 +02:00
|
|
|
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));
|
2012-08-21 17:03:38 +02:00
|
|
|
result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
|
|
|
|
result.push_back(Pair("height", blockindex->nHeight));
|
|
|
|
result.push_back(Pair("version", block.nVersion));
|
|
|
|
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
|
|
|
|
Array txs;
|
|
|
|
BOOST_FOREACH(const CTransaction&tx, block.vtx)
|
2014-11-28 20:32:52 +01:00
|
|
|
{
|
|
|
|
if(txDetails)
|
|
|
|
{
|
|
|
|
Object objTx;
|
2014-12-06 19:09:03 +01:00
|
|
|
TxToJSON(tx, uint256(0), objTx);
|
2014-11-28 20:32:52 +01:00
|
|
|
txs.push_back(objTx);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
txs.push_back(tx.GetHash().GetHex());
|
|
|
|
}
|
2012-08-21 17:03:38 +02:00
|
|
|
result.push_back(Pair("tx", txs));
|
2014-05-05 20:08:13 +02:00
|
|
|
result.push_back(Pair("time", block.GetBlockTime()));
|
|
|
|
result.push_back(Pair("nonce", (uint64_t)block.nNonce));
|
2014-06-27 13:28:08 +02:00
|
|
|
result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
|
2012-08-21 17:03:38 +02:00
|
|
|
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
|
2013-07-24 07:58:23 +02:00
|
|
|
result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
|
2012-08-21 17:03:38 +02:00
|
|
|
|
|
|
|
if (blockindex->pprev)
|
|
|
|
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
|
2013-10-10 23:07:44 +02:00
|
|
|
CBlockIndex *pnext = chainActive.Next(blockindex);
|
2013-05-12 15:50:22 +02:00
|
|
|
if (pnext)
|
|
|
|
result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex()));
|
2012-08-21 17:03:38 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-23 18:36:16 +01:00
|
|
|
Object blockHeaderToJSON(const CBlock& block, const CBlockIndex* blockindex)
|
|
|
|
{
|
|
|
|
Object result;
|
|
|
|
result.push_back(Pair("version", block.nVersion));
|
|
|
|
if (blockindex->pprev)
|
|
|
|
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
|
|
|
|
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
|
|
|
|
result.push_back(Pair("time", block.GetBlockTime()));
|
2015-04-03 00:51:08 +02:00
|
|
|
result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
|
2015-03-23 18:36:16 +01:00
|
|
|
result.push_back(Pair("nonce", (uint64_t)block.nNonce));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-21 17:03:38 +02:00
|
|
|
Value getblockcount(const Array& params, bool fHelp)
|
|
|
|
{
|
|
|
|
if (fHelp || params.size() != 0)
|
|
|
|
throw runtime_error(
|
|
|
|
"getblockcount\n"
|
2013-10-29 12:29:44 +01:00
|
|
|
"\nReturns the number of blocks in the longest block chain.\n"
|
|
|
|
"\nResult:\n"
|
|
|
|
"n (numeric) The current block count\n"
|
|
|
|
"\nExamples:\n"
|
|
|
|
+ HelpExampleCli("getblockcount", "")
|
|
|
|
+ HelpExampleRpc("getblockcount", "")
|
|
|
|
);
|
2012-08-21 17:03:38 +02:00
|
|
|
|
2013-10-10 23:07:44 +02:00
|
|
|
return chainActive.Height();
|
2012-08-21 17:03:38 +02:00
|
|
|
}
|
|
|
|
|
2013-07-03 17:02:29 +02:00
|
|
|
Value getbestblockhash(const Array& params, bool fHelp)
|
|
|
|
{
|
|
|
|
if (fHelp || params.size() != 0)
|
|
|
|
throw runtime_error(
|
|
|
|
"getbestblockhash\n"
|
2013-10-29 12:29:44 +01:00
|
|
|
"\nReturns the hash of the best (tip) block in the longest block chain.\n"
|
|
|
|
"\nResult\n"
|
|
|
|
"\"hex\" (string) the block hash hex encoded\n"
|
|
|
|
"\nExamples\n"
|
|
|
|
+ HelpExampleCli("getbestblockhash", "")
|
|
|
|
+ HelpExampleRpc("getbestblockhash", "")
|
|
|
|
);
|
2013-07-03 17:02:29 +02:00
|
|
|
|
2013-10-10 23:07:44 +02:00
|
|
|
return chainActive.Tip()->GetBlockHash().GetHex();
|
2013-07-03 17:02:29 +02:00
|
|
|
}
|
2012-08-21 17:03:38 +02:00
|
|
|
|
|
|
|
Value getdifficulty(const Array& params, bool fHelp)
|
|
|
|
{
|
|
|
|
if (fHelp || params.size() != 0)
|
|
|
|
throw runtime_error(
|
|
|
|
"getdifficulty\n"
|
2013-10-29 12:29:44 +01:00
|
|
|
"\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
|
|
|
|
"\nResult:\n"
|
|
|
|
"n.nnn (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
|
|
|
|
"\nExamples:\n"
|
|
|
|
+ HelpExampleCli("getdifficulty", "")
|
|
|
|
+ HelpExampleRpc("getdifficulty", "")
|
|
|
|
);
|
2012-08-21 17:03:38 +02:00
|
|
|
|
|
|
|
return GetDifficulty();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Value getrawmempool(const Array& params, bool fHelp)
|
|
|
|
{
|
2013-11-11 08:35:14 +01:00
|
|
|
if (fHelp || params.size() > 1)
|
2012-08-21 17:03:38 +02:00
|
|
|
throw runtime_error(
|
2013-11-11 08:35:14 +01:00
|
|
|
"getrawmempool ( verbose )\n"
|
2013-10-29 12:29:44 +01:00
|
|
|
"\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
|
2013-11-11 08:35:14 +01:00
|
|
|
"\nArguments:\n"
|
|
|
|
"1. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n"
|
|
|
|
"\nResult: (for verbose = false):\n"
|
|
|
|
"[ (json array of string)\n"
|
2013-10-29 12:29:44 +01:00
|
|
|
" \"transactionid\" (string) The transaction id\n"
|
|
|
|
" ,...\n"
|
|
|
|
"]\n"
|
2013-11-11 08:35:14 +01:00
|
|
|
"\nResult: (for verbose = true):\n"
|
|
|
|
"{ (json object)\n"
|
|
|
|
" \"transactionid\" : { (json object)\n"
|
|
|
|
" \"size\" : n, (numeric) transaction size in bytes\n"
|
2015-03-19 15:15:08 +01:00
|
|
|
" \"fee\" : n, (numeric) transaction fee in dashs\n"
|
2013-11-11 08:35:14 +01:00
|
|
|
" \"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"
|
|
|
|
" \"currentpriority\" : n, (numeric) transaction priority now\n"
|
|
|
|
" \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
|
|
|
|
" \"transactionid\", (string) parent transaction id\n"
|
|
|
|
" ... ]\n"
|
|
|
|
" }, ...\n"
|
|
|
|
"]\n"
|
2013-10-29 12:29:44 +01:00
|
|
|
"\nExamples\n"
|
2013-11-11 08:35:14 +01:00
|
|
|
+ HelpExampleCli("getrawmempool", "true")
|
|
|
|
+ HelpExampleRpc("getrawmempool", "true")
|
2013-10-29 12:29:44 +01:00
|
|
|
);
|
2012-08-21 17:03:38 +02:00
|
|
|
|
2013-11-11 08:35:14 +01:00
|
|
|
bool fVerbose = false;
|
|
|
|
if (params.size() > 0)
|
|
|
|
fVerbose = params[0].get_bool();
|
2012-08-21 17:03:38 +02:00
|
|
|
|
2013-11-11 08:35:14 +01:00
|
|
|
if (fVerbose)
|
|
|
|
{
|
|
|
|
LOCK(mempool.cs);
|
|
|
|
Object o;
|
|
|
|
BOOST_FOREACH(const PAIRTYPE(uint256, CTxMemPoolEntry)& entry, mempool.mapTx)
|
|
|
|
{
|
|
|
|
const uint256& hash = entry.first;
|
|
|
|
const CTxMemPoolEntry& e = entry.second;
|
|
|
|
Object info;
|
|
|
|
info.push_back(Pair("size", (int)e.GetTxSize()));
|
|
|
|
info.push_back(Pair("fee", ValueFromAmount(e.GetFee())));
|
2014-05-05 20:08:13 +02:00
|
|
|
info.push_back(Pair("time", e.GetTime()));
|
2013-11-11 08:35:14 +01:00
|
|
|
info.push_back(Pair("height", (int)e.GetHeight()));
|
|
|
|
info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight())));
|
|
|
|
info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height())));
|
|
|
|
const CTransaction& tx = e.GetTx();
|
|
|
|
set<string> setDepends;
|
|
|
|
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
|
|
|
{
|
|
|
|
if (mempool.exists(txin.prevout.hash))
|
|
|
|
setDepends.insert(txin.prevout.hash.ToString());
|
|
|
|
}
|
|
|
|
Array depends(setDepends.begin(), setDepends.end());
|
|
|
|
info.push_back(Pair("depends", depends));
|
|
|
|
o.push_back(Pair(hash.ToString(), info));
|
|
|
|
}
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vector<uint256> vtxid;
|
|
|
|
mempool.queryHashes(vtxid);
|
2012-08-21 17:03:38 +02:00
|
|
|
|
2013-11-11 08:35:14 +01:00
|
|
|
Array a;
|
|
|
|
BOOST_FOREACH(const uint256& hash, vtxid)
|
|
|
|
a.push_back(hash.ToString());
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
2012-08-21 17:03:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Value getblockhash(const Array& params, bool fHelp)
|
|
|
|
{
|
|
|
|
if (fHelp || params.size() != 1)
|
|
|
|
throw runtime_error(
|
2013-10-29 12:29:44 +01:00
|
|
|
"getblockhash index\n"
|
|
|
|
"\nReturns hash of block in best-block-chain at index provided.\n"
|
|
|
|
"\nArguments:\n"
|
|
|
|
"1. index (numeric, required) The block index\n"
|
|
|
|
"\nResult:\n"
|
|
|
|
"\"hash\" (string) The block hash\n"
|
|
|
|
"\nExamples:\n"
|
|
|
|
+ HelpExampleCli("getblockhash", "1000")
|
|
|
|
+ HelpExampleRpc("getblockhash", "1000")
|
|
|
|
);
|
2012-08-21 17:03:38 +02:00
|
|
|
|
|
|
|
int nHeight = params[0].get_int();
|
2013-10-10 23:07:44 +02:00
|
|
|
if (nHeight < 0 || nHeight > chainActive.Height())
|
2014-10-24 15:43:40 +02:00
|
|
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
|
2012-08-21 17:03:38 +02:00
|
|
|
|
2013-10-10 23:07:44 +02:00
|
|
|
CBlockIndex* pblockindex = chainActive[nHeight];
|
|
|
|
return pblockindex->GetBlockHash().GetHex();
|
2012-08-21 17:03:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Value getblock(const Array& params, bool fHelp)
|
|
|
|
{
|
2013-06-07 07:23:30 +02:00
|
|
|
if (fHelp || params.size() < 1 || params.size() > 2)
|
2012-08-21 17:03:38 +02:00
|
|
|
throw runtime_error(
|
2013-10-29 12:29:44 +01:00
|
|
|
"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 <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"
|
2014-08-28 17:14:22 +02:00
|
|
|
" \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n"
|
2013-10-29 12:29:44 +01:00
|
|
|
" \"size\" : n, (numeric) The block size\n"
|
|
|
|
" \"height\" : n, (numeric) The block height or index\n"
|
|
|
|
" \"version\" : n, (numeric) The block version\n"
|
|
|
|
" \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
|
|
|
|
" \"tx\" : [ (array of string) The transaction ids\n"
|
|
|
|
" \"transactionid\" (string) The transaction id\n"
|
|
|
|
" ,...\n"
|
|
|
|
" ],\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"
|
2015-03-23 18:57:03 +01:00
|
|
|
+ HelpExampleCli("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"")
|
|
|
|
+ HelpExampleRpc("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"")
|
2013-06-07 07:23:30 +02:00
|
|
|
);
|
2012-08-21 17:03:38 +02:00
|
|
|
|
|
|
|
std::string strHash = params[0].get_str();
|
|
|
|
uint256 hash(strHash);
|
|
|
|
|
2013-06-07 07:23:30 +02:00
|
|
|
bool fVerbose = true;
|
|
|
|
if (params.size() > 1)
|
|
|
|
fVerbose = params[1].get_bool();
|
|
|
|
|
2012-08-21 17:03:38 +02:00
|
|
|
if (mapBlockIndex.count(hash) == 0)
|
2012-10-04 09:34:44 +02:00
|
|
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
|
2012-08-21 17:03:38 +02:00
|
|
|
|
|
|
|
CBlock block;
|
|
|
|
CBlockIndex* pblockindex = mapBlockIndex[hash];
|
2014-07-10 02:37:27 +02:00
|
|
|
|
|
|
|
if(!ReadBlockFromDisk(block, pblockindex))
|
|
|
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
|
2012-08-21 17:03:38 +02:00
|
|
|
|
2013-06-07 07:23:30 +02:00
|
|
|
if (!fVerbose)
|
|
|
|
{
|
|
|
|
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
|
|
|
|
ssBlock << block;
|
|
|
|
std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
|
|
|
|
return strHex;
|
|
|
|
}
|
|
|
|
|
2012-08-21 17:03:38 +02:00
|
|
|
return blockToJSON(block, pblockindex);
|
|
|
|
}
|
|
|
|
|
2015-03-23 18:36:16 +01:00
|
|
|
Value getblockheader(const Array& 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 block 'hash' header.\n"
|
|
|
|
"If verbose is true, returns an Object with information about block <hash> header.\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"
|
|
|
|
" \"version\" : n, (numeric) The block version\n"
|
|
|
|
" \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
|
|
|
|
" \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
|
|
|
|
" \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
|
|
|
|
" \"bits\" : \"1d00ffff\", (string) The bits\n"
|
|
|
|
" \"nonce\" : n, (numeric) The nonce\n"
|
|
|
|
"}\n"
|
|
|
|
"\nResult (for verbose=false):\n"
|
|
|
|
"\"data\" (string) A string that is serialized, hex-encoded data for block 'hash' header.\n"
|
|
|
|
"\nExamples:\n"
|
2015-03-23 18:57:03 +01:00
|
|
|
+ HelpExampleCli("getblockheader", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"")
|
|
|
|
+ HelpExampleRpc("getblockheader", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"")
|
2015-03-23 18:36:16 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
std::string strHash = params[0].get_str();
|
|
|
|
uint256 hash(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");
|
|
|
|
|
|
|
|
CBlock block;
|
|
|
|
CBlockIndex* pblockindex = mapBlockIndex[hash];
|
|
|
|
|
|
|
|
if(!ReadBlockFromDisk(block, pblockindex))
|
|
|
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
|
|
|
|
|
|
|
|
if (!fVerbose)
|
|
|
|
{
|
|
|
|
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
|
|
|
|
ssBlock << block.GetBlockHeader();
|
|
|
|
std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
|
|
|
|
return strHex;
|
|
|
|
}
|
|
|
|
|
|
|
|
return blockHeaderToJSON(block, pblockindex);
|
|
|
|
}
|
|
|
|
|
2012-09-25 23:04:54 +02:00
|
|
|
Value gettxoutsetinfo(const Array& params, bool fHelp)
|
|
|
|
{
|
|
|
|
if (fHelp || params.size() != 0)
|
|
|
|
throw runtime_error(
|
|
|
|
"gettxoutsetinfo\n"
|
2013-10-29 12:29:44 +01:00
|
|
|
"\nReturns statistics about the unspent transaction output set.\n"
|
|
|
|
"Note this call may take some time.\n"
|
|
|
|
"\nResult:\n"
|
|
|
|
"{\n"
|
|
|
|
" \"height\":n, (numeric) The current block height (index)\n"
|
|
|
|
" \"bestblock\": \"hex\", (string) the best block hash hex\n"
|
|
|
|
" \"transactions\": n, (numeric) The number of transactions\n"
|
|
|
|
" \"txouts\": n, (numeric) The number of output transactions\n"
|
|
|
|
" \"bytes_serialized\": n, (numeric) The serialized size\n"
|
|
|
|
" \"hash_serialized\": \"hash\", (string) The serialized hash\n"
|
|
|
|
" \"total_amount\": x.xxx (numeric) The total amount\n"
|
|
|
|
"}\n"
|
|
|
|
"\nExamples:\n"
|
|
|
|
+ HelpExampleCli("gettxoutsetinfo", "")
|
|
|
|
+ HelpExampleRpc("gettxoutsetinfo", "")
|
|
|
|
);
|
2012-09-25 23:04:54 +02:00
|
|
|
|
|
|
|
Object ret;
|
|
|
|
|
|
|
|
CCoinsStats stats;
|
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 11:38:35 +01:00
|
|
|
FlushStateToDisk();
|
2012-09-25 23:04:54 +02:00
|
|
|
if (pcoinsTip->GetStats(stats)) {
|
2014-05-05 20:08:13 +02:00
|
|
|
ret.push_back(Pair("height", (int64_t)stats.nHeight));
|
2013-05-01 16:23:27 +02:00
|
|
|
ret.push_back(Pair("bestblock", stats.hashBlock.GetHex()));
|
2014-05-05 20:08:13 +02:00
|
|
|
ret.push_back(Pair("transactions", (int64_t)stats.nTransactions));
|
|
|
|
ret.push_back(Pair("txouts", (int64_t)stats.nTransactionOutputs));
|
|
|
|
ret.push_back(Pair("bytes_serialized", (int64_t)stats.nSerializedSize));
|
2013-05-01 16:23:27 +02:00
|
|
|
ret.push_back(Pair("hash_serialized", stats.hashSerialized.GetHex()));
|
|
|
|
ret.push_back(Pair("total_amount", ValueFromAmount(stats.nTotalAmount)));
|
2012-09-25 23:04:54 +02:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2012-08-21 17:03:38 +02:00
|
|
|
|
2012-09-25 23:04:54 +02:00
|
|
|
Value gettxout(const Array& params, bool fHelp)
|
|
|
|
{
|
|
|
|
if (fHelp || params.size() < 2 || params.size() > 3)
|
|
|
|
throw runtime_error(
|
2013-10-29 12:29:44 +01:00
|
|
|
"gettxout \"txid\" n ( includemempool )\n"
|
|
|
|
"\nReturns details about an unspent transaction output.\n"
|
|
|
|
"\nArguments:\n"
|
|
|
|
"1. \"txid\" (string, required) The transaction id\n"
|
|
|
|
"2. n (numeric, required) vout value\n"
|
|
|
|
"3. includemempool (boolean, optional) Whether to included the mem pool\n"
|
|
|
|
"\nResult:\n"
|
|
|
|
"{\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"
|
|
|
|
" \"scriptPubKey\" : { (json object)\n"
|
|
|
|
" \"asm\" : \"code\", (string) \n"
|
|
|
|
" \"hex\" : \"hex\", (string) \n"
|
|
|
|
" \"reqSigs\" : n, (numeric) Number of required signatures\n"
|
|
|
|
" \"type\" : \"pubkeyhash\", (string) The type, eg pubkeyhash\n"
|
2015-03-19 15:15:08 +01:00
|
|
|
" \"addresses\" : [ (array of string) array of dash addresses\n"
|
|
|
|
" \"dashaddress\" (string) dash address\n"
|
2013-10-29 12:29:44 +01:00
|
|
|
" ,...\n"
|
|
|
|
" ]\n"
|
|
|
|
" },\n"
|
|
|
|
" \"version\" : n, (numeric) The version\n"
|
|
|
|
" \"coinbase\" : true|false (boolean) Coinbase or not\n"
|
|
|
|
"}\n"
|
|
|
|
|
|
|
|
"\nExamples:\n"
|
|
|
|
"\nGet unspent transactions\n"
|
|
|
|
+ HelpExampleCli("listunspent", "") +
|
|
|
|
"\nView the details\n"
|
|
|
|
+ HelpExampleCli("gettxout", "\"txid\" 1") +
|
|
|
|
"\nAs a json rpc call\n"
|
|
|
|
+ HelpExampleRpc("gettxout", "\"txid\", 1")
|
|
|
|
);
|
2012-08-21 17:03:38 +02:00
|
|
|
|
2012-09-25 23:04:54 +02:00
|
|
|
Object ret;
|
|
|
|
|
|
|
|
std::string strHash = params[0].get_str();
|
|
|
|
uint256 hash(strHash);
|
|
|
|
int n = params[1].get_int();
|
|
|
|
bool fMempool = true;
|
|
|
|
if (params.size() > 2)
|
|
|
|
fMempool = params[2].get_bool();
|
|
|
|
|
|
|
|
CCoins coins;
|
|
|
|
if (fMempool) {
|
|
|
|
LOCK(mempool.cs);
|
2014-09-24 03:19:04 +02:00
|
|
|
CCoinsViewMemPool view(pcoinsTip, mempool);
|
2012-09-25 23:04:54 +02:00
|
|
|
if (!view.GetCoins(hash, coins))
|
|
|
|
return Value::null;
|
|
|
|
mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool
|
|
|
|
} else {
|
|
|
|
if (!pcoinsTip->GetCoins(hash, coins))
|
|
|
|
return Value::null;
|
|
|
|
}
|
|
|
|
if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull())
|
|
|
|
return Value::null;
|
|
|
|
|
2014-09-04 02:02:44 +02:00
|
|
|
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
|
2013-11-05 02:27:39 +01:00
|
|
|
CBlockIndex *pindex = it->second;
|
|
|
|
ret.push_back(Pair("bestblock", pindex->GetBlockHash().GetHex()));
|
2012-09-25 23:04:54 +02:00
|
|
|
if ((unsigned int)coins.nHeight == MEMPOOL_HEIGHT)
|
|
|
|
ret.push_back(Pair("confirmations", 0));
|
|
|
|
else
|
2013-11-05 02:27:39 +01:00
|
|
|
ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1));
|
2013-01-04 22:51:00 +01:00
|
|
|
ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue)));
|
2012-09-25 23:04:54 +02:00
|
|
|
Object o;
|
2013-07-15 07:22:10 +02:00
|
|
|
ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true);
|
2012-09-25 23:04:54 +02:00
|
|
|
ret.push_back(Pair("scriptPubKey", o));
|
|
|
|
ret.push_back(Pair("version", coins.nVersion));
|
|
|
|
ret.push_back(Pair("coinbase", coins.fCoinBase));
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2012-08-21 17:03:38 +02:00
|
|
|
|
2013-06-19 17:53:02 +02:00
|
|
|
Value verifychain(const Array& params, bool fHelp)
|
|
|
|
{
|
|
|
|
if (fHelp || params.size() > 2)
|
|
|
|
throw runtime_error(
|
2013-10-29 12:29:44 +01:00
|
|
|
"verifychain ( checklevel numblocks )\n"
|
|
|
|
"\nVerifies blockchain database.\n"
|
|
|
|
"\nArguments:\n"
|
2014-01-30 14:13:30 +01:00
|
|
|
"1. checklevel (numeric, optional, 0-4, default=3) How thorough the block verification is.\n"
|
|
|
|
"2. numblocks (numeric, optional, default=288, 0=all) The number of blocks to check.\n"
|
2013-10-29 12:29:44 +01:00
|
|
|
"\nResult:\n"
|
|
|
|
"true|false (boolean) Verified or not\n"
|
|
|
|
"\nExamples:\n"
|
|
|
|
+ HelpExampleCli("verifychain", "")
|
|
|
|
+ HelpExampleRpc("verifychain", "")
|
|
|
|
);
|
2013-06-19 17:53:02 +02:00
|
|
|
|
|
|
|
int nCheckLevel = GetArg("-checklevel", 3);
|
|
|
|
int nCheckDepth = GetArg("-checkblocks", 288);
|
|
|
|
if (params.size() > 0)
|
|
|
|
nCheckLevel = params[0].get_int();
|
|
|
|
if (params.size() > 1)
|
|
|
|
nCheckDepth = params[1].get_int();
|
|
|
|
|
2014-08-27 09:20:33 +02:00
|
|
|
return CVerifyDB().VerifyDB(pcoinsTip, nCheckLevel, nCheckDepth);
|
2013-06-19 17:53:02 +02:00
|
|
|
}
|
2012-08-21 17:03:38 +02:00
|
|
|
|
2014-05-05 13:22:28 +02:00
|
|
|
Value getblockchaininfo(const Array& params, bool fHelp)
|
|
|
|
{
|
|
|
|
if (fHelp || params.size() != 0)
|
|
|
|
throw runtime_error(
|
|
|
|
"getblockchaininfo\n"
|
|
|
|
"Returns an object containing various state info regarding block chain processing.\n"
|
|
|
|
"\nResult:\n"
|
|
|
|
"{\n"
|
2014-06-12 14:52:12 +02:00
|
|
|
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
|
2014-05-05 13:22:28 +02:00
|
|
|
" \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
|
2014-07-12 00:03:10 +02:00
|
|
|
" \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n"
|
2014-05-05 13:22:28 +02:00
|
|
|
" \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
|
|
|
|
" \"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"
|
|
|
|
"}\n"
|
|
|
|
"\nExamples:\n"
|
|
|
|
+ HelpExampleCli("getblockchaininfo", "")
|
|
|
|
+ HelpExampleRpc("getblockchaininfo", "")
|
|
|
|
);
|
|
|
|
|
|
|
|
Object obj;
|
2014-06-11 12:23:49 +02:00
|
|
|
obj.push_back(Pair("chain", Params().NetworkIDString()));
|
|
|
|
obj.push_back(Pair("blocks", (int)chainActive.Height()));
|
2014-07-12 00:03:10 +02:00
|
|
|
obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1));
|
2014-06-11 12:23:49 +02:00
|
|
|
obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex()));
|
|
|
|
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
|
|
|
|
obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(chainActive.Tip())));
|
|
|
|
obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
|
2014-05-05 13:22:28 +02:00
|
|
|
return obj;
|
|
|
|
}
|
2014-08-03 18:12:19 +02:00
|
|
|
|
2014-11-20 03:19:29 +01:00
|
|
|
/** Comparison function for sorting the getchaintips heads. */
|
2014-08-03 18:12:19 +02:00
|
|
|
struct CompareBlocksByHeight
|
|
|
|
{
|
|
|
|
bool operator()(const CBlockIndex* a, const CBlockIndex* b) const
|
|
|
|
{
|
|
|
|
/* Make sure that unequal blocks with the same height do not compare
|
2014-10-31 09:36:30 +01:00
|
|
|
equal. Use the pointers themselves to make a distinction. */
|
2014-08-03 18:12:19 +02:00
|
|
|
|
|
|
|
if (a->nHeight != b->nHeight)
|
|
|
|
return (a->nHeight > b->nHeight);
|
|
|
|
|
|
|
|
return a < b;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Value getchaintips(const Array& params, bool fHelp)
|
|
|
|
{
|
|
|
|
if (fHelp || params.size() != 0)
|
|
|
|
throw runtime_error(
|
|
|
|
"getchaintips\n"
|
|
|
|
"Return information about all known tips in the block tree,"
|
|
|
|
" including the main chain as well as orphaned branches.\n"
|
|
|
|
"\nResult:\n"
|
|
|
|
"[\n"
|
|
|
|
" {\n"
|
|
|
|
" \"height\": xxxx, (numeric) height of the chain tip\n"
|
|
|
|
" \"hash\": \"xxxx\", (string) block hash of the tip\n"
|
|
|
|
" \"branchlen\": 0 (numeric) zero for main chain\n"
|
2014-11-27 10:46:55 +01:00
|
|
|
" \"status\": \"active\" (string) \"active\" for the main chain\n"
|
2014-08-03 18:12:19 +02:00
|
|
|
" },\n"
|
|
|
|
" {\n"
|
|
|
|
" \"height\": xxxx,\n"
|
|
|
|
" \"hash\": \"xxxx\",\n"
|
|
|
|
" \"branchlen\": 1 (numeric) length of branch connecting the tip to the main chain\n"
|
2014-11-27 10:46:55 +01:00
|
|
|
" \"status\": \"xxxx\" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid)\n"
|
2014-08-03 18:12:19 +02:00
|
|
|
" }\n"
|
|
|
|
"]\n"
|
2014-12-01 20:48:50 +01:00
|
|
|
"Possible values for status:\n"
|
|
|
|
"1. \"invalid\" This branch contains at least one invalid block\n"
|
|
|
|
"2. \"headers-only\" Not all blocks for this branch are available, but the headers are valid\n"
|
|
|
|
"3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n"
|
|
|
|
"4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n"
|
|
|
|
"5. \"active\" This is the tip of the active main chain, which is certainly valid\n"
|
2014-08-03 18:12:19 +02:00
|
|
|
"\nExamples:\n"
|
|
|
|
+ HelpExampleCli("getchaintips", "")
|
|
|
|
+ HelpExampleRpc("getchaintips", "")
|
|
|
|
);
|
|
|
|
|
|
|
|
/* Build up a list of chain tips. We start with the list of all
|
|
|
|
known blocks, and successively remove blocks that appear as pprev
|
|
|
|
of another block. */
|
|
|
|
std::set<const CBlockIndex*, CompareBlocksByHeight> setTips;
|
|
|
|
BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex)
|
|
|
|
setTips.insert(item.second);
|
|
|
|
BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex)
|
|
|
|
{
|
|
|
|
const CBlockIndex* pprev = item.second->pprev;
|
|
|
|
if (pprev)
|
|
|
|
setTips.erase(pprev);
|
|
|
|
}
|
|
|
|
|
2014-11-27 10:46:55 +01:00
|
|
|
// Always report the currently active tip.
|
|
|
|
setTips.insert(chainActive.Tip());
|
|
|
|
|
2014-08-03 18:12:19 +02:00
|
|
|
/* Construct the output array. */
|
|
|
|
Array res;
|
|
|
|
BOOST_FOREACH(const CBlockIndex* block, setTips)
|
|
|
|
{
|
|
|
|
Object obj;
|
|
|
|
obj.push_back(Pair("height", block->nHeight));
|
|
|
|
obj.push_back(Pair("hash", block->phashBlock->GetHex()));
|
|
|
|
|
|
|
|
const int branchLen = block->nHeight - chainActive.FindFork(block)->nHeight;
|
|
|
|
obj.push_back(Pair("branchlen", branchLen));
|
|
|
|
|
2014-11-27 10:46:55 +01:00
|
|
|
string status;
|
|
|
|
if (chainActive.Contains(block)) {
|
|
|
|
// This block is part of the currently active chain.
|
|
|
|
status = "active";
|
|
|
|
} else if (block->nStatus & BLOCK_FAILED_MASK) {
|
|
|
|
// This block or one of its ancestors is invalid.
|
|
|
|
status = "invalid";
|
|
|
|
} else if (block->nChainTx == 0) {
|
|
|
|
// This block cannot be connected because full block data for it or one of its parents is missing.
|
|
|
|
status = "headers-only";
|
|
|
|
} else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
|
|
|
|
// This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.
|
|
|
|
status = "valid-fork";
|
|
|
|
} else if (block->IsValid(BLOCK_VALID_TREE)) {
|
|
|
|
// The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.
|
|
|
|
status = "valid-headers";
|
|
|
|
} else {
|
|
|
|
// No clue.
|
|
|
|
status = "unknown";
|
|
|
|
}
|
|
|
|
obj.push_back(Pair("status", status));
|
|
|
|
|
2014-08-03 18:12:19 +02:00
|
|
|
res.push_back(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
2014-08-07 05:58:19 +02:00
|
|
|
|
|
|
|
Value getmempoolinfo(const Array& params, bool fHelp)
|
|
|
|
{
|
|
|
|
if (fHelp || params.size() != 0)
|
|
|
|
throw runtime_error(
|
|
|
|
"getmempoolinfo\n"
|
|
|
|
"\nReturns details on the active state of the TX memory pool.\n"
|
|
|
|
"\nResult:\n"
|
|
|
|
"{\n"
|
|
|
|
" \"size\": xxxxx (numeric) Current tx count\n"
|
|
|
|
" \"bytes\": xxxxx (numeric) Sum of all tx sizes\n"
|
|
|
|
"}\n"
|
|
|
|
"\nExamples:\n"
|
|
|
|
+ HelpExampleCli("getmempoolinfo", "")
|
|
|
|
+ HelpExampleRpc("getmempoolinfo", "")
|
|
|
|
);
|
|
|
|
|
|
|
|
Object ret;
|
|
|
|
ret.push_back(Pair("size", (int64_t) mempool.size()));
|
|
|
|
ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize()));
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-11-19 09:39:42 +01:00
|
|
|
Value invalidateblock(const Array& params, bool fHelp)
|
|
|
|
{
|
|
|
|
if (fHelp || params.size() != 1)
|
|
|
|
throw runtime_error(
|
|
|
|
"invalidateblock \"hash\"\n"
|
|
|
|
"\nPermanently marks a block as invalid, as if it violated a consensus rule.\n"
|
|
|
|
"\nArguments:\n"
|
|
|
|
"1. hash (string, required) the hash of the block to mark as invalid\n"
|
|
|
|
"\nResult:\n"
|
|
|
|
"\nExamples:\n"
|
|
|
|
+ HelpExampleCli("invalidateblock", "\"blockhash\"")
|
|
|
|
+ HelpExampleRpc("invalidateblock", "\"blockhash\"")
|
|
|
|
);
|
|
|
|
|
|
|
|
std::string strHash = params[0].get_str();
|
|
|
|
uint256 hash(strHash);
|
|
|
|
CValidationState state;
|
|
|
|
|
|
|
|
{
|
|
|
|
LOCK(cs_main);
|
|
|
|
if (mapBlockIndex.count(hash) == 0)
|
|
|
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
|
|
|
|
|
|
|
|
CBlockIndex* pblockindex = mapBlockIndex[hash];
|
|
|
|
InvalidateBlock(state, pblockindex);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state.IsValid()) {
|
|
|
|
ActivateBestChain(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!state.IsValid()) {
|
|
|
|
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
|
|
|
|
}
|
|
|
|
|
|
|
|
return Value::null;
|
|
|
|
}
|
|
|
|
|
|
|
|
Value reconsiderblock(const Array& params, bool fHelp)
|
|
|
|
{
|
|
|
|
if (fHelp || params.size() != 1)
|
|
|
|
throw runtime_error(
|
|
|
|
"reconsiderblock \"hash\"\n"
|
|
|
|
"\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n"
|
|
|
|
"This can be used to undo the effects of invalidateblock.\n"
|
|
|
|
"\nArguments:\n"
|
|
|
|
"1. hash (string, required) the hash of the block to reconsider\n"
|
|
|
|
"\nResult:\n"
|
|
|
|
"\nExamples:\n"
|
|
|
|
+ HelpExampleCli("reconsiderblock", "\"blockhash\"")
|
|
|
|
+ HelpExampleRpc("reconsiderblock", "\"blockhash\"")
|
|
|
|
);
|
|
|
|
|
|
|
|
std::string strHash = params[0].get_str();
|
|
|
|
uint256 hash(strHash);
|
|
|
|
CValidationState state;
|
|
|
|
|
|
|
|
{
|
|
|
|
LOCK(cs_main);
|
|
|
|
if (mapBlockIndex.count(hash) == 0)
|
|
|
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
|
|
|
|
|
|
|
|
CBlockIndex* pblockindex = mapBlockIndex[hash];
|
|
|
|
ReconsiderBlock(state, pblockindex);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state.IsValid()) {
|
|
|
|
ActivateBestChain(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!state.IsValid()) {
|
|
|
|
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
|
|
|
|
}
|
|
|
|
|
|
|
|
return Value::null;
|
|
|
|
}
|