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.
This commit is contained in:
parent
6278bd57c6
commit
b33bd7a3be
24
qa/rpc-tests/getchaintips.py
Executable file
24
qa/rpc-tests/getchaintips.py
Executable file
@ -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 ()
|
@ -444,7 +444,7 @@ CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const {
|
|||||||
return Genesis();
|
return Genesis();
|
||||||
}
|
}
|
||||||
|
|
||||||
CBlockIndex *CChain::FindFork(CBlockIndex *pindex) const {
|
const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const {
|
||||||
if (pindex->nHeight > Height())
|
if (pindex->nHeight > Height())
|
||||||
pindex = pindex->GetAncestor(Height());
|
pindex = pindex->GetAncestor(Height());
|
||||||
while (pindex && !Contains(pindex))
|
while (pindex && !Contains(pindex))
|
||||||
@ -2067,8 +2067,8 @@ static CBlockIndex* FindMostWorkChain() {
|
|||||||
static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork) {
|
static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork) {
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
bool fInvalidFound = false;
|
bool fInvalidFound = false;
|
||||||
CBlockIndex *pindexOldTip = chainActive.Tip();
|
const CBlockIndex *pindexOldTip = chainActive.Tip();
|
||||||
CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
|
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
|
||||||
|
|
||||||
// Disconnect active blocks which are no longer in the best chain.
|
// Disconnect active blocks which are no longer in the best chain.
|
||||||
while (chainActive.Tip() && chainActive.Tip() != pindexFork) {
|
while (chainActive.Tip() && chainActive.Tip() != pindexFork) {
|
||||||
|
@ -1068,7 +1068,7 @@ public:
|
|||||||
CBlockIndex *FindFork(const CBlockLocator &locator) const;
|
CBlockIndex *FindFork(const CBlockLocator &locator) const;
|
||||||
|
|
||||||
/** Find the last common block between this chain and a block index entry. */
|
/** 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. */
|
/** The currently-connected chain of blocks. */
|
||||||
|
@ -461,3 +461,73 @@ Value getblockchaininfo(const Array& params, bool fHelp)
|
|||||||
obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
|
obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
|
||||||
return obj;
|
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;
|
||||||
|
}
|
||||||
|
@ -235,6 +235,7 @@ static const CRPCCommand vRPCCommands[] =
|
|||||||
{ "getblockcount", &getblockcount, true, false, false },
|
{ "getblockcount", &getblockcount, true, false, false },
|
||||||
{ "getblock", &getblock, true, false, false },
|
{ "getblock", &getblock, true, false, false },
|
||||||
{ "getblockhash", &getblockhash, true, false, false },
|
{ "getblockhash", &getblockhash, true, false, false },
|
||||||
|
{ "getchaintips", &getchaintips, true, false, false },
|
||||||
{ "getdifficulty", &getdifficulty, true, false, false },
|
{ "getdifficulty", &getdifficulty, true, false, false },
|
||||||
{ "getrawmempool", &getrawmempool, true, false, false },
|
{ "getrawmempool", &getrawmempool, true, false, false },
|
||||||
{ "gettxout", &gettxout, true, false, false },
|
{ "gettxout", &gettxout, true, false, false },
|
||||||
|
@ -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 gettxoutsetinfo(const json_spirit::Array& params, bool fHelp);
|
||||||
extern json_spirit::Value gettxout(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 verifychain(const json_spirit::Array& params, bool fHelp);
|
||||||
|
extern json_spirit::Value getchaintips(const json_spirit::Array& params, bool fHelp);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user