Browse Source

Merge pull request #4536

b33bd7a Implement "getchaintips" RPC command to monitor blockchain forks. (Daniel Kraft)
0.10
Pieter Wuille 10 years ago
parent
commit
1d2a1d4bbc
No known key found for this signature in database
GPG Key ID: 8F653255C87992E0
  1. 24
      qa/rpc-tests/getchaintips.py
  2. 6
      src/main.cpp
  3. 2
      src/main.h
  4. 70
      src/rpcblockchain.cpp
  5. 1
      src/rpcserver.cpp
  6. 1
      src/rpcserver.h

24
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 ()

6
src/main.cpp

@ -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) {

2
src/main.h

@ -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. */

70
src/rpcblockchain.cpp

@ -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;
}

1
src/rpcserver.cpp

@ -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 },

1
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 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…
Cancel
Save