aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Kraft <d@domob.eu>2014-08-03 18:12:19 +0200
committerDaniel Kraft <d@domob.eu>2014-08-03 18:12:19 +0200
commitb33bd7a3be1cbcc8d255178307976b7762125b18 (patch)
tree7d1af753944e5813f0ef541efb0a28edf5a283e2
parent6278bd57c662e29b07df9db50c47095c0bb44a82 (diff)
Implement "getchaintips" RPC command to monitor blockchain forks.
Port over https://github.com/chronokings/huntercoin/pull/19 from Huntercoin: This implements a new RPC command "getchaintips" that can be used to find all currently active chain heads. This is similar to the -printblocktree startup option, but it can be used without restarting just via the RPC interface on a running daemon.
-rwxr-xr-xqa/rpc-tests/getchaintips.py24
-rw-r--r--src/main.cpp6
-rw-r--r--src/main.h2
-rw-r--r--src/rpcblockchain.cpp70
-rw-r--r--src/rpcserver.cpp1
-rw-r--r--src/rpcserver.h1
6 files changed, 100 insertions, 4 deletions
diff --git a/qa/rpc-tests/getchaintips.py b/qa/rpc-tests/getchaintips.py
new file mode 100755
index 0000000000..a83c499743
--- /dev/null
+++ b/qa/rpc-tests/getchaintips.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 The Bitcoin Core developers
+# Distributed under the MIT/X11 software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+# Exercise the getchaintips API.
+
+# Since the test framework does not generate orphan blocks, we can
+# unfortunately not check for them!
+
+from test_framework import BitcoinTestFramework
+from util import assert_equal
+
+class GetChainTipsTest (BitcoinTestFramework):
+
+ def run_test (self, nodes):
+ res = nodes[0].getchaintips ()
+ assert_equal (len (res), 1)
+ res = res[0]
+ assert_equal (res['branchlen'], 0)
+ assert_equal (res['height'], 200)
+
+if __name__ == '__main__':
+ GetChainTipsTest ().main ()
diff --git a/src/main.cpp b/src/main.cpp
index 353cde0bd7..cf9318fedf 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -444,7 +444,7 @@ CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const {
return Genesis();
}
-CBlockIndex *CChain::FindFork(CBlockIndex *pindex) const {
+const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const {
if (pindex->nHeight > Height())
pindex = pindex->GetAncestor(Height());
while (pindex && !Contains(pindex))
@@ -2067,8 +2067,8 @@ static CBlockIndex* FindMostWorkChain() {
static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork) {
AssertLockHeld(cs_main);
bool fInvalidFound = false;
- CBlockIndex *pindexOldTip = chainActive.Tip();
- CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
+ const CBlockIndex *pindexOldTip = chainActive.Tip();
+ const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
// Disconnect active blocks which are no longer in the best chain.
while (chainActive.Tip() && chainActive.Tip() != pindexFork) {
diff --git a/src/main.h b/src/main.h
index 48ec86f6a8..a27020459a 100644
--- a/src/main.h
+++ b/src/main.h
@@ -1068,7 +1068,7 @@ public:
CBlockIndex *FindFork(const CBlockLocator &locator) const;
/** Find the last common block between this chain and a block index entry. */
- CBlockIndex *FindFork(CBlockIndex *pindex) const;
+ const CBlockIndex *FindFork(const CBlockIndex *pindex) const;
};
/** The currently-connected chain of blocks. */
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 253693e624..1e5198b85c 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -461,3 +461,73 @@ Value getblockchaininfo(const Array& params, bool fHelp)
obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
return obj;
}
+
+/* Comparison function for sorting the getchaintips heads. */
+struct CompareBlocksByHeight
+{
+ bool operator()(const CBlockIndex* a, const CBlockIndex* b) const
+ {
+ /* Make sure that unequal blocks with the same height do not compare
+ equal. Use the pointers themselves to make a distinction. */
+
+ 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"
+ " },\n"
+ " {\n"
+ " \"height\": xxxx,\n"
+ " \"hash\": \"xxxx\",\n"
+ " \"branchlen\": 1 (numeric) length of branch connecting the tip to the main chain\n"
+ " }\n"
+ "]\n"
+ "\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);
+ }
+
+ /* 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));
+
+ res.push_back(obj);
+ }
+
+ return res;
+}
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index 5deb6a4e08..716a7fba6a 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -235,6 +235,7 @@ static const CRPCCommand vRPCCommands[] =
{ "getblockcount", &getblockcount, true, false, false },
{ "getblock", &getblock, true, false, false },
{ "getblockhash", &getblockhash, true, false, false },
+ { "getchaintips", &getchaintips, true, false, false },
{ "getdifficulty", &getdifficulty, true, false, false },
{ "getrawmempool", &getrawmempool, true, false, false },
{ "gettxout", &gettxout, true, false, false },
diff --git a/src/rpcserver.h b/src/rpcserver.h
index 31badadd6d..176852ca8f 100644
--- a/src/rpcserver.h
+++ b/src/rpcserver.h
@@ -205,5 +205,6 @@ extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp)
extern json_spirit::Value gettxoutsetinfo(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value gettxout(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value verifychain(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value getchaintips(const json_spirit::Array& params, bool fHelp);
#endif