From 3db760557c331738dc42e02355b925b361f67e8c Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Mon, 4 Apr 2022 16:05:53 +0200 Subject: [PATCH] Feat(standalone): Function to get latest/earliest block --- engine-standalone-storage/src/lib.rs | 30 ++++++++++++++ engine-tests/src/tests/standalone/storage.rs | 42 ++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/engine-standalone-storage/src/lib.rs b/engine-standalone-storage/src/lib.rs index 88596bc1b..4290500a4 100644 --- a/engine-standalone-storage/src/lib.rs +++ b/engine-standalone-storage/src/lib.rs @@ -53,6 +53,36 @@ impl Storage { }) } + pub fn get_latest_block(&self) -> Result<(H256, u64), error::Error> { + self.block_read(rocksdb::IteratorMode::End) + } + + pub fn get_earliest_block(&self) -> Result<(H256, u64), error::Error> { + self.block_read(rocksdb::IteratorMode::Start) + } + + fn block_read(&self, mode: rocksdb::IteratorMode) -> Result<(H256, u64), error::Error> { + let upper_bound = construct_storage_key(StoragePrefix::BlockHash, &u64::MAX.to_be_bytes()); + let lower_bound = construct_storage_key(StoragePrefix::BlockHash, &[]); + let prefix_len = lower_bound.len(); + let mut opt = rocksdb::ReadOptions::default(); + opt.set_iterate_upper_bound(upper_bound); + opt.set_iterate_lower_bound(lower_bound); + + let mut iter = self.db.iterator_opt(mode, opt); + iter.next() + .map(|(key, value)| { + let block_height = { + let mut buf = [0u8; 8]; + buf.copy_from_slice(&key[prefix_len..]); + u64::from_be_bytes(buf) + }; + let block_hash = H256::from_slice(&value); + (block_hash, block_height) + }) + .ok_or(error::Error::NoBlockAtHeight(0)) + } + pub fn get_block_hash_by_height(&self, block_height: u64) -> Result { let storage_key = construct_storage_key(StoragePrefix::BlockHash, &block_height.to_be_bytes()); diff --git a/engine-tests/src/tests/standalone/storage.rs b/engine-tests/src/tests/standalone/storage.rs index 41c54b1ee..05f6af616 100644 --- a/engine-tests/src/tests/standalone/storage.rs +++ b/engine-tests/src/tests/standalone/storage.rs @@ -195,6 +195,14 @@ fn test_block_index() { block_metadata, storage.get_block_metadata(block_hash).unwrap() ); + assert_eq!( + (block_hash, block_height), + storage.get_latest_block().unwrap(), + ); + assert_eq!( + (block_hash, block_height), + storage.get_earliest_block().unwrap(), + ); // block hash / height that do not exist are errors let missing_block_height = block_height + 1; @@ -214,6 +222,40 @@ fn test_block_index() { other => panic!("Unexpected response: {:?}", other), } + // insert later block + let next_height = block_height + 1; + let next_hash = H256([0xaa; 32]); + storage + .set_block_data(next_hash, next_height, block_metadata.clone()) + .unwrap(); + + // check earliest+latest blocks are still correct + assert_eq!( + (next_hash, next_height), + storage.get_latest_block().unwrap(), + ); + assert_eq!( + (block_hash, block_height), + storage.get_earliest_block().unwrap(), + ); + + // insert earlier block + let prev_height = block_height - 1; + let prev_hash = H256([0xbb; 32]); + storage + .set_block_data(prev_hash, prev_height, block_metadata.clone()) + .unwrap(); + + // check earliest+latest blocks are still correct + assert_eq!( + (next_hash, next_height), + storage.get_latest_block().unwrap(), + ); + assert_eq!( + (prev_hash, prev_height), + storage.get_earliest_block().unwrap(), + ); + drop(storage); temp_dir.close().unwrap(); }