diff --git a/doc/release-notes.md b/doc/release-notes.md
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -3,3 +3,5 @@
This release includes the following features and fixes:
+ - Add `getfinalizedblock` rpc to allow node operators to introspec
+ the current finalized block.
\ No newline at end of file
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -176,6 +176,24 @@
return chainActive.Tip()->GetBlockHash().GetHex();
}
+UniValue getfinalizedblockhash(const Config &config,
+ const JSONRPCRequest &request) {
+ if (request.fHelp || request.params.size() != 0) {
+ throw std::runtime_error(
+ "getfinalizedblockhash\n"
+ "\nReturns the hash of the currently finalized block\n"
+ "\nResult:\n"
+ "\"hex\" (string) the block hash hex encoded\n");
+ }
+
+ LOCK(cs_main);
+ const CBlockIndex *blockIndexFinalized = GetFinalizedBlock();
+ if (blockIndexFinalized) {
+ return blockIndexFinalized->GetBlockHash().GetHex();
+ }
+ return UniValue(UniValue::VSTR);
+}
+
void RPCNotifyBlockChange(bool ibd, const CBlockIndex *pindex) {
if (pindex) {
std::lock_guard lock(cs_blockchange);
@@ -1815,6 +1833,7 @@
{ "blockchain", "preciousblock", preciousblock, {"blockhash"} },
/* Not shown in help */
+ { "hidden", "getfinalizedblockhash", getfinalizedblockhash, {} },
{ "hidden", "finalizeblock", finalizeblock, {"blockhash"} },
{ "hidden", "invalidateblock", invalidateblock, {"blockhash"} },
{ "hidden", "parkblock", parkblock, {"blockhash"} },
diff --git a/src/validation.h b/src/validation.h
--- a/src/validation.h
+++ b/src/validation.h
@@ -636,6 +636,8 @@
bool FinalizeBlockAndInvalidate(const Config &config, CValidationState &state,
CBlockIndex *pindex);
+const CBlockIndex *GetFinalizedBlock();
+
/** Mark a block as invalid. */
bool InvalidateBlock(const Config &config, CValidationState &state,
CBlockIndex *pindex);
diff --git a/src/validation.cpp b/src/validation.cpp
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -2915,6 +2915,11 @@
return true;
}
+const CBlockIndex *GetFinalizedBlock() {
+ AssertLockHeld(cs_main);
+ return pindexFinalized;
+}
+
bool InvalidateBlock(const Config &config, CValidationState &state,
CBlockIndex *pindex) {
return UnwindBlock(config, state, pindex, true);
diff --git a/test/functional/abc-finalize-block.py b/test/functional/abc-finalize-block.py
--- a/test/functional/abc-finalize-block.py
+++ b/test/functional/abc-finalize-block.py
@@ -9,11 +9,14 @@
from test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes_bi, sync_blocks, wait_until
RPC_FINALIZE_INVALID_BLOCK_ERROR = 'finalize-invalid-block'
+AUTO_FINALIZATION_DEPTH = 10
class FinalizeBlockTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
+ self.extra_flags = [["-maxreorgdepth={}".format(AUTO_FINALIZATION_DEPTH)], [
+ "-maxreorgdepth={}".format(AUTO_FINALIZATION_DEPTH)]]
# There should only be one chaintip, which is expected_tip
def only_valid_tip(self, expected_tip, other_tip_status=None):
@@ -39,6 +42,8 @@
sync_blocks(self.nodes[0:2])
alt_node.invalidateblock(tip)
+ # We will use this later to check auto-finalization during a reorg
+ auto_finalized_tip = alt_node.getbestblockhash()
alt_node.generate(10)
# Wait for node 0 to invalidate the chain.
@@ -67,19 +72,29 @@
"Test that invalidating a finalized block moves the finalization backward...")
node.invalidateblock(tip)
node.reconsiderblock(tip)
+ finalized_block = node.getblockhash(
+ int(node.getblockheader(tip)['height']) - AUTO_FINALIZATION_DEPTH)
assert_equal(node.getbestblockhash(), tip)
+ assert_equal(
+ node.getfinalizedblockhash(),
+ finalized_block)
# The node will now accept that chain as the finalized block moved back.
node.reconsiderblock(alt_node.getbestblockhash())
assert_equal(node.getbestblockhash(), alt_node.getbestblockhash())
+ assert_equal(node.getfinalizedblockhash(), auto_finalized_tip)
self.log.info("Trigger reorg via block finalization...")
node.finalizeblock(tip)
- assert_equal(node.getbestblockhash(), tip)
+ assert_equal(node.getfinalizedblockhash(),
+ finalized_block)
self.log.info("Try to finalized a block on a competiting fork...")
assert_raises_rpc_error(-20, RPC_FINALIZE_INVALID_BLOCK_ERROR,
node.finalizeblock, alt_node.getbestblockhash())
+ assert node.getfinalizedblockhash() != alt_node.getbestblockhash(), \
+ "Finalize block is alt_node's tip!"
+ assert_equal(node.getfinalizedblockhash(), finalized_block)
if __name__ == '__main__':