aboutsummaryrefslogtreecommitdiff
path: root/src/rpcblockchain.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpcblockchain.cpp')
-rw-r--r--src/rpcblockchain.cpp125
1 files changed, 122 insertions, 3 deletions
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 7919fb1a0c..66e86ebace 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -16,6 +16,7 @@
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);
double GetDifficulty(const CBlockIndex* blockindex)
@@ -50,7 +51,7 @@ double GetDifficulty(const CBlockIndex* blockindex)
}
-Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
+Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
{
Object result;
result.push_back(Pair("hash", block.GetHash().GetHex()));
@@ -65,7 +66,16 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
Array txs;
BOOST_FOREACH(const CTransaction&tx, block.vtx)
- txs.push_back(tx.GetHash().GetHex());
+ {
+ if(txDetails)
+ {
+ Object objTx;
+ TxToJSON(tx, uint256(0), objTx);
+ txs.push_back(objTx);
+ }
+ else
+ txs.push_back(tx.GetHash().GetHex());
+ }
result.push_back(Pair("tx", txs));
result.push_back(Pair("time", block.GetBlockTime()));
result.push_back(Pair("nonce", (uint64_t)block.nNonce));
@@ -319,7 +329,7 @@ Value gettxoutsetinfo(const Array& params, bool fHelp)
Object ret;
CCoinsStats stats;
- pcoinsTip->Flush();
+ FlushStateToDisk();
if (pcoinsTip->GetStats(stats)) {
ret.push_back(Pair("height", (int64_t)stats.nHeight));
ret.push_back(Pair("bestblock", stats.hashBlock.GetHex()));
@@ -496,13 +506,21 @@ Value getchaintips(const Array& params, bool fHelp)
" \"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"
+ " \"status\": \"active\" (string) \"active\" for the main chain\n"
" },\n"
" {\n"
" \"height\": xxxx,\n"
" \"hash\": \"xxxx\",\n"
" \"branchlen\": 1 (numeric) length of branch connecting the tip to the main chain\n"
+ " \"status\": \"xxxx\" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid)\n"
" }\n"
"]\n"
+ "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"
"\nExamples:\n"
+ HelpExampleCli("getchaintips", "")
+ HelpExampleRpc("getchaintips", "")
@@ -521,6 +539,9 @@ Value getchaintips(const Array& params, bool fHelp)
setTips.erase(pprev);
}
+ // Always report the currently active tip.
+ setTips.insert(chainActive.Tip());
+
/* Construct the output array. */
Array res;
BOOST_FOREACH(const CBlockIndex* block, setTips)
@@ -532,6 +553,28 @@ Value getchaintips(const Array& params, bool fHelp)
const int branchLen = block->nHeight - chainActive.FindFork(block)->nHeight;
obj.push_back(Pair("branchlen", branchLen));
+ 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));
+
res.push_back(obj);
}
@@ -561,3 +604,79 @@ Value getmempoolinfo(const Array& params, bool fHelp)
return ret;
}
+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;
+}