Page MenuHomePhabricator

D13829.id40105.diff
No OneTemporary

D13829.id40105.diff

diff --git a/chronik/chronik-http/src/server.rs b/chronik/chronik-http/src/server.rs
--- a/chronik/chronik-http/src/server.rs
+++ b/chronik/chronik-http/src/server.rs
@@ -111,6 +111,7 @@
fn make_router(indexer: ChronikIndexerRef) -> Router {
Router::new()
+ .route("/blockchain-info", routing::get(handle_blockchain_info))
.route("/block/:hash_or_height", routing::get(handle_block))
.route("/tx/:txid", routing::get(handle_tx))
.route(
@@ -135,6 +136,14 @@
}
}
+async fn handle_blockchain_info(
+ Extension(indexer): Extension<ChronikIndexerRef>,
+) -> Result<Protobuf<proto::BlockchainInfo>, ReportError> {
+ let indexer = indexer.read().await;
+ let blocks = indexer.blocks();
+ Ok(Protobuf(blocks.blockchain_info()?))
+}
+
async fn handle_block(
Path(hash_or_height): Path<String>,
Extension(indexer): Extension<ChronikIndexerRef>,
diff --git a/chronik/chronik-indexer/src/query/blocks.rs b/chronik/chronik-indexer/src/query/blocks.rs
--- a/chronik/chronik-indexer/src/query/blocks.rs
+++ b/chronik/chronik-indexer/src/query/blocks.rs
@@ -71,4 +71,19 @@
}),
})
}
+
+ /// Query some info about the blockchain, e.g. the tip hash and height.
+ pub fn blockchain_info(&self) -> Result<proto::BlockchainInfo> {
+ let block_reader = BlockReader::new(self.db)?;
+ match block_reader.tip()? {
+ Some(block) => Ok(proto::BlockchainInfo {
+ tip_hash: block.hash.to_vec(),
+ tip_height: block.height,
+ }),
+ None => Ok(proto::BlockchainInfo {
+ tip_hash: vec![0; 32],
+ tip_height: -1,
+ }),
+ }
+ }
}
diff --git a/chronik/chronik-proto/proto/chronik.proto b/chronik/chronik-proto/proto/chronik.proto
--- a/chronik/chronik-proto/proto/chronik.proto
+++ b/chronik/chronik-proto/proto/chronik.proto
@@ -12,6 +12,14 @@
BlockInfo block_info = 1;
}
+// Info about the state of the blockchain.
+message BlockchainInfo {
+ // Hash (little-endian) of the current tip
+ bytes tip_hash = 1;
+ // Height of the current tip (genesis has height = 0)
+ int32 tip_height = 2;
+}
+
// Info about a block
message BlockInfo {
// Hash (little-endian)
diff --git a/test/functional/chronik_blockchain_info.py b/test/functional/chronik_blockchain_info.py
new file mode 100644
--- /dev/null
+++ b/test/functional/chronik_blockchain_info.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+# Copyright (c) 2023 The Bitcoin developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""
+Test Chronik's /blockchain-info endpoint.
+"""
+
+from test_framework.address import ADDRESS_ECREG_UNSPENDABLE
+from test_framework.blocktools import GENESIS_BLOCK_HASH
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+
+class ChronikBlockchainInfoTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+ self.extra_args = [['-chronik']]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_chronik()
+
+ def run_test(self):
+ from test_framework.chronik.client import ChronikClient, pb
+
+ node = self.nodes[0]
+ chronik = ChronikClient('127.0.0.1', node.chronik_port)
+
+ assert_equal(chronik.blockchain_info().ok(), pb.BlockchainInfo(
+ tip_hash=bytes.fromhex(GENESIS_BLOCK_HASH)[::-1],
+ tip_height=0,
+ ))
+
+ block_hashes = self.generatetoaddress(node, 12, ADDRESS_ECREG_UNSPENDABLE)
+
+ assert_equal(chronik.blockchain_info().ok(), pb.BlockchainInfo(
+ tip_hash=bytes.fromhex(block_hashes[11])[::-1],
+ tip_height=12,
+ ))
+
+ node.invalidateblock(block_hashes[6])
+
+ assert_equal(chronik.blockchain_info().ok(), pb.BlockchainInfo(
+ tip_hash=bytes.fromhex(block_hashes[5])[::-1],
+ tip_height=6,
+ ))
+
+
+if __name__ == '__main__':
+ ChronikBlockchainInfoTest().main()
diff --git a/test/functional/test_framework/chronik/client.py b/test/functional/test_framework/chronik/client.py
--- a/test/functional/test_framework/chronik/client.py
+++ b/test/functional/test_framework/chronik/client.py
@@ -139,6 +139,9 @@
ok_proto.ParseFromString(body)
return ChronikResponse(response.status, ok_proto=ok_proto)
+ def blockchain_info(self) -> ChronikResponse:
+ return self._request_get('/blockchain-info', pb.BlockchainInfo)
+
def block(self, hash_or_height: Union[str, int]) -> ChronikResponse:
return self._request_get(f'/block/{hash_or_height}', pb.Block)

File Metadata

Mime Type
text/plain
Expires
Tue, May 20, 19:58 (8 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5865603
Default Alt Text
D13829.id40105.diff (4 KB)

Event Timeline