Skip to content

Commit 0ddf441

Browse files
committed
Merge pull request #5386
1b91be4 Report status of chain tips (Pieter Wuille)
2 parents b248a38 + 1b91be4 commit 0ddf441

File tree

3 files changed

+34
-1
lines changed

3 files changed

+34
-1
lines changed

qa/pull-tester/rpc-tests.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ if [ "x${ENABLE_BITCOIND}${ENABLE_UTILS}${ENABLE_WALLET}" = "x111" ]; then
2020
${BUILDDIR}/qa/rpc-tests/listtransactions.py --srcdir "${BUILDDIR}/src"
2121
${BUILDDIR}/qa/rpc-tests/txn_doublespend.py --srcdir "${BUILDDIR}/src"
2222
${BUILDDIR}/qa/rpc-tests/txn_doublespend.py --mineblock --srcdir "${BUILDDIR}/src"
23+
${BUILDDIR}/qa/rpc-tests/getchaintips.py --srcdir "${BUILDDIR}/src"
2324
#${BUILDDIR}/qa/rpc-tests/forknotify.py --srcdir "${BUILDDIR}/src"
2425
else
2526
echo "No rpc tests to run. Wallet, utils, and bitcoind must all be enabled"

qa/rpc-tests/getchaintips.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def run_test (self):
1919
assert_equal (len (tips), 1)
2020
assert_equal (tips[0]['branchlen'], 0)
2121
assert_equal (tips[0]['height'], 200)
22+
assert_equal (tips[0]['status'], 'active')
2223

2324
# Split the network and build two chains of different lengths.
2425
self.split_network ()
@@ -31,12 +32,14 @@ def run_test (self):
3132
shortTip = tips[0]
3233
assert_equal (shortTip['branchlen'], 0)
3334
assert_equal (shortTip['height'], 210)
35+
assert_equal (tips[0]['status'], 'active')
3436

3537
tips = self.nodes[3].getchaintips ()
3638
assert_equal (len (tips), 1)
3739
longTip = tips[0]
3840
assert_equal (longTip['branchlen'], 0)
3941
assert_equal (longTip['height'], 220)
42+
assert_equal (tips[0]['status'], 'active')
4043

4144
# Join the network halves and check that we now have two tips
4245
# (at least at the nodes that previously had the short chain).
@@ -47,7 +50,9 @@ def run_test (self):
4750
assert_equal (tips[0], longTip)
4851

4952
assert_equal (tips[1]['branchlen'], 10)
50-
tips[1]['branchlen'] = 0;
53+
assert_equal (tips[1]['status'], 'valid-fork')
54+
tips[1]['branchlen'] = 0
55+
tips[1]['status'] = 'active'
5156
assert_equal (tips[1], shortTip)
5257

5358
if __name__ == '__main__':

src/rpcblockchain.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,11 +496,13 @@ Value getchaintips(const Array& params, bool fHelp)
496496
" \"height\": xxxx, (numeric) height of the chain tip\n"
497497
" \"hash\": \"xxxx\", (string) block hash of the tip\n"
498498
" \"branchlen\": 0 (numeric) zero for main chain\n"
499+
" \"status\": \"active\" (string) \"active\" for the main chain\n"
499500
" },\n"
500501
" {\n"
501502
" \"height\": xxxx,\n"
502503
" \"hash\": \"xxxx\",\n"
503504
" \"branchlen\": 1 (numeric) length of branch connecting the tip to the main chain\n"
505+
" \"status\": \"xxxx\" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid)\n"
504506
" }\n"
505507
"]\n"
506508
"\nExamples:\n"
@@ -521,6 +523,9 @@ Value getchaintips(const Array& params, bool fHelp)
521523
setTips.erase(pprev);
522524
}
523525

526+
// Always report the currently active tip.
527+
setTips.insert(chainActive.Tip());
528+
524529
/* Construct the output array. */
525530
Array res;
526531
BOOST_FOREACH(const CBlockIndex* block, setTips)
@@ -532,6 +537,28 @@ Value getchaintips(const Array& params, bool fHelp)
532537
const int branchLen = block->nHeight - chainActive.FindFork(block)->nHeight;
533538
obj.push_back(Pair("branchlen", branchLen));
534539

540+
string status;
541+
if (chainActive.Contains(block)) {
542+
// This block is part of the currently active chain.
543+
status = "active";
544+
} else if (block->nStatus & BLOCK_FAILED_MASK) {
545+
// This block or one of its ancestors is invalid.
546+
status = "invalid";
547+
} else if (block->nChainTx == 0) {
548+
// This block cannot be connected because full block data for it or one of its parents is missing.
549+
status = "headers-only";
550+
} else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
551+
// This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.
552+
status = "valid-fork";
553+
} else if (block->IsValid(BLOCK_VALID_TREE)) {
554+
// The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.
555+
status = "valid-headers";
556+
} else {
557+
// No clue.
558+
status = "unknown";
559+
}
560+
obj.push_back(Pair("status", status));
561+
535562
res.push_back(obj);
536563
}
537564

0 commit comments

Comments
 (0)