diff --git a/crates/cold-mdbx/src/backend.rs b/crates/cold-mdbx/src/backend.rs index 329300f..101bc5a 100644 --- a/crates/cold-mdbx/src/backend.rs +++ b/crates/cold-mdbx/src/backend.rs @@ -5,8 +5,8 @@ //! database environment from `signet-hot-mdbx`. use crate::{ - ColdBlockHashIndex, ColdHeaders, ColdMetadata, ColdReceipts, ColdSignetEvents, - ColdTransactions, ColdTxHashIndex, ColdZenithHeaders, MdbxColdError, MetadataKey, + ColdBlockHashIndex, ColdHeaders, ColdReceipts, ColdSignetEvents, ColdTransactions, + ColdTxHashIndex, ColdZenithHeaders, MdbxColdError, }; use alloy::{consensus::Header, primitives::BlockNumber}; use signet_cold::{ @@ -92,12 +92,6 @@ impl MdbxColdBackend { ColdTxHashIndex::FIXED_VAL_SIZE, ColdTxHashIndex::INT_KEY, ), - ( - ColdMetadata::NAME, - ColdMetadata::DUAL_KEY_SIZE, - ColdMetadata::FIXED_VAL_SIZE, - ColdMetadata::INT_KEY, - ), ( ColdTransactions::NAME, ColdTransactions::DUAL_KEY_SIZE, @@ -124,11 +118,6 @@ impl MdbxColdBackend { Ok(()) } - fn get_metadata(&self, key: MetadataKey) -> Result, MdbxColdError> { - let tx = self.env.tx()?; - Ok(TableTraverse::::exact(&mut tx.new_cursor::()?, &key)?) - } - fn get_header_inner(&self, spec: HeaderSpecifier) -> Result, MdbxColdError> { let tx = self.env.tx()?; let block_num = match spec { @@ -359,16 +348,6 @@ impl MdbxColdBackend { tx.queue_put::(&block, zh)?; } - // Update block bounds - let current_latest: Option = TableTraverse::::exact( - &mut tx.new_cursor::()?, - &MetadataKey::LatestBlock, - )?; - tx.queue_put::( - &MetadataKey::LatestBlock, - ¤t_latest.map_or(block, |prev| prev.max(block)), - )?; - tx.raw_commit()?; Ok(()) } @@ -420,22 +399,6 @@ impl MdbxColdBackend { tx.queue_delete::(block_num)?; } - // Update latest block - { - let mut cursor = tx.new_cursor::()?; - match KvTraverse::<_>::last(&mut cursor)? { - Some((key, _)) => { - tx.queue_put::( - &MetadataKey::LatestBlock, - &BlockNumber::decode_key(&key)?, - )?; - } - None => { - tx.queue_delete::(&MetadataKey::LatestBlock)?; - } - } - } - tx.raw_commit()?; Ok(()) } @@ -575,7 +538,14 @@ impl ColdStorage for MdbxColdBackend { } async fn get_latest_block(&self) -> ColdResult> { - Ok(self.get_metadata(MetadataKey::LatestBlock)?) + let tx = self.env.tx().map_err(MdbxColdError::from)?; + let mut cursor = tx.new_cursor::().map_err(MdbxColdError::from)?; + let latest = KvTraverse::<_>::last(&mut cursor) + .map_err(MdbxColdError::from)? + .map(|(key, _)| BlockNumber::decode_key(&key)) + .transpose() + .map_err(MdbxColdError::from)?; + Ok(latest) } async fn get_receipt_with_context( diff --git a/crates/cold-mdbx/src/lib.rs b/crates/cold-mdbx/src/lib.rs index 96bdf76..738ece0 100644 --- a/crates/cold-mdbx/src/lib.rs +++ b/crates/cold-mdbx/src/lib.rs @@ -16,10 +16,6 @@ //! - [`ColdBlockHashIndex`]: Maps block hash to block number. //! - [`ColdTxHashIndex`]: Maps transaction hash to (block number, tx index). //! -//! ## Metadata Tables -//! -//! - [`ColdMetadata`]: Storage metadata (latest block, finalized, safe, earliest). -//! //! # Feature Flags //! //! - **`test-utils`**: Propagates `signet-cold/test-utils` for conformance @@ -42,8 +38,8 @@ pub use error::MdbxColdError; mod tables; pub use tables::{ - ColdBlockHashIndex, ColdHeaders, ColdMetadata, ColdReceipts, ColdSignetEvents, - ColdTransactions, ColdTxHashIndex, ColdZenithHeaders, MetadataKey, + ColdBlockHashIndex, ColdHeaders, ColdReceipts, ColdSignetEvents, ColdTransactions, + ColdTxHashIndex, ColdZenithHeaders, }; mod backend; diff --git a/crates/cold-mdbx/src/tables.rs b/crates/cold-mdbx/src/tables.rs index 53d4b71..6c76979 100644 --- a/crates/cold-mdbx/src/tables.rs +++ b/crates/cold-mdbx/src/tables.rs @@ -4,52 +4,10 @@ //! the [`Table`], [`SingleKey`], and [`DualKey`] traits. use alloy::{consensus::Header, primitives::B256, primitives::BlockNumber}; -use signet_hot::ser::{DeserError, KeySer, MAX_KEY_SIZE}; +use signet_hot::ser::KeySer; use signet_hot::tables::{DualKey, SingleKey, Table}; use signet_storage_types::{DbSignetEvent, DbZenithHeader, Receipt, TransactionSigned, TxLocation}; -// ============================================================================ -// Metadata Key Enum -// ============================================================================ - -/// Keys for the cold storage metadata table. -/// -/// These are used to store semantic block references like "latest" or -/// "finalized" that need to be resolved to actual block numbers. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[repr(u8)] -pub enum MetadataKey { - /// The latest (most recent) block number stored. - LatestBlock = 0, -} - -impl TryFrom for MetadataKey { - type Error = DeserError; - - fn try_from(value: u8) -> Result { - match value { - 0 => Ok(Self::LatestBlock), - _ => Err(DeserError::String(format!("Invalid MetadataKey value: {}", value))), - } - } -} - -impl KeySer for MetadataKey { - const SIZE: usize = 1; - - fn encode_key<'a: 'c, 'b: 'c, 'c>(&'a self, buf: &'b mut [u8; MAX_KEY_SIZE]) -> &'c [u8] { - buf[0] = *self as u8; - &buf[..1] - } - - fn decode_key(data: &[u8]) -> Result { - if data.is_empty() { - return Err(DeserError::InsufficientData { needed: 1, available: 0 }); - } - MetadataKey::try_from(data[0]) - } -} - // ============================================================================ // Primary Data Tables // ============================================================================ @@ -189,24 +147,6 @@ impl Table for ColdTxHashIndex { impl SingleKey for ColdTxHashIndex {} -// ============================================================================ -// Metadata Table -// ============================================================================ - -/// Cold storage metadata. -/// -/// Keys: `LatestBlock(0)` -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct ColdMetadata; - -impl Table for ColdMetadata { - const NAME: &'static str = "ColdMetadata"; - type Key = MetadataKey; - type Value = BlockNumber; -} - -impl SingleKey for ColdMetadata {} - #[cfg(test)] mod tests { use super::*; @@ -220,7 +160,6 @@ mod tests { assert_eq!(ColdZenithHeaders::NAME, "ColdZenithHeaders"); assert_eq!(ColdBlockHashIndex::NAME, "ColdBlockHashIndex"); assert_eq!(ColdTxHashIndex::NAME, "ColdTxHashIndex"); - assert_eq!(ColdMetadata::NAME, "ColdMetadata"); } #[test] @@ -232,7 +171,6 @@ mod tests { assert_single_key::(); assert_single_key::(); assert_single_key::(); - assert_single_key::(); } #[test] @@ -257,7 +195,6 @@ mod tests { // Non-int_key tables should have INT_KEY = false const { assert!(!ColdBlockHashIndex::INT_KEY) }; const { assert!(!ColdTxHashIndex::INT_KEY) }; - const { assert!(!ColdMetadata::INT_KEY) }; } #[test] @@ -268,28 +205,8 @@ mod tests { // ColdBlockHashIndex has BlockNumber (u64) = 8 bytes assert_eq!(ColdBlockHashIndex::FIXED_VAL_SIZE, Some(8)); - // ColdMetadata also has BlockNumber (u64) = 8 bytes - assert_eq!(ColdMetadata::FIXED_VAL_SIZE, Some(8)); - // Variable-size value tables should not have fixed value size assert_eq!(ColdHeaders::FIXED_VAL_SIZE, None); assert_eq!(ColdZenithHeaders::FIXED_VAL_SIZE, None); } - - #[test] - fn test_metadata_key_try_from() { - assert_eq!(MetadataKey::try_from(0).unwrap(), MetadataKey::LatestBlock); - assert!(MetadataKey::try_from(1).is_err()); - assert!(MetadataKey::try_from(255).is_err()); - } - - #[test] - fn test_metadata_key_ser_roundtrip() { - let mut buf = [0u8; MAX_KEY_SIZE]; - let encoded = MetadataKey::LatestBlock.encode_key(&mut buf); - assert_eq!(encoded.len(), 1); - - let decoded = MetadataKey::decode_key(encoded).unwrap(); - assert_eq!(MetadataKey::LatestBlock, decoded); - } } diff --git a/crates/cold-sql/migrations/001_initial.sql b/crates/cold-sql/migrations/001_initial.sql index fc79b03..d04e404 100644 --- a/crates/cold-sql/migrations/001_initial.sql +++ b/crates/cold-sql/migrations/001_initial.sql @@ -108,8 +108,3 @@ CREATE TABLE IF NOT EXISTS zenith_headers ( reward_address BLOB NOT NULL, block_data_hash BLOB NOT NULL ); - -CREATE TABLE IF NOT EXISTS metadata ( - key TEXT PRIMARY KEY NOT NULL, - block_number INTEGER NOT NULL -); diff --git a/crates/cold-sql/migrations/001_initial_pg.sql b/crates/cold-sql/migrations/001_initial_pg.sql index 3254f21..491a623 100644 --- a/crates/cold-sql/migrations/001_initial_pg.sql +++ b/crates/cold-sql/migrations/001_initial_pg.sql @@ -106,8 +106,3 @@ CREATE TABLE IF NOT EXISTS zenith_headers ( reward_address BYTEA NOT NULL, block_data_hash BYTEA NOT NULL ); - -CREATE TABLE IF NOT EXISTS metadata ( - key TEXT PRIMARY KEY NOT NULL, - block_number BIGINT NOT NULL -); diff --git a/crates/cold-sql/src/backend.rs b/crates/cold-sql/src/backend.rs index 81af1c4..8fa97c7 100644 --- a/crates/cold-sql/src/backend.rs +++ b/crates/cold-sql/src/backend.rs @@ -106,58 +106,6 @@ impl SqlColdBackend { } } - async fn resolve_tx_spec( - &self, - spec: TransactionSpecifier, - ) -> Result, SqlColdError> { - match spec { - TransactionSpecifier::Hash(hash) => { - let hash_bytes = hash.as_slice(); - let row = sqlx::query( - "SELECT block_number, tx_index FROM transactions WHERE tx_hash = $1", - ) - .bind(hash_bytes) - .fetch_optional(&self.pool) - .await?; - Ok(row.map(|r| { - ( - from_i64(r.get::("block_number")), - from_i64(r.get::("tx_index")), - ) - })) - } - TransactionSpecifier::BlockAndIndex { block, index } => Ok(Some((block, index))), - TransactionSpecifier::BlockHashAndIndex { block_hash, index } => { - let block = self.resolve_header_spec(HeaderSpecifier::Hash(block_hash)).await?; - Ok(block.map(|b| (b, index))) - } - } - } - - async fn resolve_receipt_spec( - &self, - spec: ReceiptSpecifier, - ) -> Result, SqlColdError> { - match spec { - ReceiptSpecifier::TxHash(hash) => { - let hash_bytes = hash.as_slice(); - let row = sqlx::query( - "SELECT block_number, tx_index FROM transactions WHERE tx_hash = $1", - ) - .bind(hash_bytes) - .fetch_optional(&self.pool) - .await?; - Ok(row.map(|r| { - ( - from_i64(r.get::("block_number")), - from_i64(r.get::("tx_index")), - ) - })) - } - ReceiptSpecifier::BlockAndIndex { block, index } => Ok(Some((block, index))), - } - } - // ======================================================================== // Read helpers // ======================================================================== @@ -202,91 +150,6 @@ impl SqlColdBackend { .transpose() } - async fn fetch_block_hash( - &self, - block_num: BlockNumber, - ) -> Result, SqlColdError> { - let bn = to_i64(block_num); - let row = sqlx::query("SELECT block_hash FROM headers WHERE block_number = $1") - .bind(bn) - .fetch_optional(&self.pool) - .await?; - Ok(row.map(|r| { - let bytes: Vec = r.get("block_hash"); - alloy::primitives::B256::from_slice(&bytes) - })) - } - - async fn fetch_tx_by_location( - &self, - block: BlockNumber, - index: u64, - ) -> Result, SqlColdError> { - let bn = to_i64(block); - let idx = to_i64(index); - let row = - sqlx::query("SELECT * FROM transactions WHERE block_number = $1 AND tx_index = $2") - .bind(bn) - .bind(idx) - .fetch_optional(&self.pool) - .await?; - - row.map(|r| row_to_tx_row(&r).into_tx()).transpose() - } - - async fn fetch_receipt_by_location( - &self, - block: BlockNumber, - index: u64, - ) -> Result, SqlColdError> { - let bn = to_i64(block); - let idx = to_i64(index); - - let receipt_row = - sqlx::query("SELECT * FROM receipts WHERE block_number = $1 AND tx_index = $2") - .bind(bn) - .bind(idx) - .fetch_optional(&self.pool) - .await?; - - let Some(rr) = receipt_row else { - return Ok(None); - }; - - let receipt = ReceiptRow { - block_number: rr.get("block_number"), - tx_index: rr.get("tx_index"), - tx_type: rr.get::("tx_type") as i16, - success: rr.get::("success") != 0, - cumulative_gas_used: rr.get("cumulative_gas_used"), - }; - - let log_rows = sqlx::query( - "SELECT * FROM logs WHERE block_number = $1 AND tx_index = $2 ORDER BY log_index", - ) - .bind(bn) - .bind(idx) - .fetch_all(&self.pool) - .await?; - - let logs = log_rows - .into_iter() - .map(|r| LogRow { - block_number: r.get("block_number"), - tx_index: r.get("tx_index"), - log_index: r.get("log_index"), - address: r.get("address"), - topic0: r.get("topic0"), - topic1: r.get("topic1"), - topic2: r.get("topic2"), - topic3: r.get("topic3"), - data: r.get("data"), - }) - .collect(); - - receipt_from_rows(receipt, logs).map(Some) - } - // ======================================================================== // Write helpers // ======================================================================== @@ -457,37 +320,6 @@ impl SqlColdBackend { .await?; } - // Update metadata - let current_latest: Option = - sqlx::query("SELECT block_number FROM metadata WHERE key = 'latest_block'") - .fetch_optional(&mut *tx) - .await? - .map(|r| r.get("block_number")); - - let new_latest = current_latest.map_or(bn, |prev| prev.max(bn)); - sqlx::query( - "INSERT INTO metadata (key, block_number) VALUES ('latest_block', $1) - ON CONFLICT(key) DO UPDATE SET block_number = $1", - ) - .bind(new_latest) - .execute(&mut *tx) - .await?; - - let current_earliest: Option = - sqlx::query("SELECT block_number FROM metadata WHERE key = 'earliest_block'") - .fetch_optional(&mut *tx) - .await? - .map(|r| r.get("block_number")); - - let new_earliest = current_earliest.map_or(bn, |prev| prev.min(bn)); - sqlx::query( - "INSERT INTO metadata (key, block_number) VALUES ('earliest_block', $1) - ON CONFLICT(key) DO UPDATE SET block_number = $1", - ) - .bind(new_earliest) - .execute(&mut *tx) - .await?; - tx.commit().await?; Ok(()) } @@ -570,15 +402,50 @@ impl ColdStorage for SqlColdBackend { &self, spec: TransactionSpecifier, ) -> ColdResult>> { - let Some((block, index)) = self.resolve_tx_spec(spec).await? else { - return Ok(None); - }; - let Some(tx) = self.fetch_tx_by_location(block, index).await? else { - return Ok(None); + let row = match spec { + TransactionSpecifier::Hash(hash) => sqlx::query( + "SELECT t.*, h.block_hash + FROM transactions t + JOIN headers h ON t.block_number = h.block_number + WHERE t.tx_hash = $1", + ) + .bind(hash.as_slice()) + .fetch_optional(&self.pool) + .await + .map_err(SqlColdError::from)?, + TransactionSpecifier::BlockAndIndex { block, index } => sqlx::query( + "SELECT t.*, h.block_hash + FROM transactions t + JOIN headers h ON t.block_number = h.block_number + WHERE t.block_number = $1 AND t.tx_index = $2", + ) + .bind(to_i64(block)) + .bind(to_i64(index)) + .fetch_optional(&self.pool) + .await + .map_err(SqlColdError::from)?, + TransactionSpecifier::BlockHashAndIndex { block_hash, index } => sqlx::query( + "SELECT t.*, h.block_hash + FROM transactions t + JOIN headers h ON t.block_number = h.block_number + WHERE h.block_hash = $1 AND t.tx_index = $2", + ) + .bind(block_hash.as_slice()) + .bind(to_i64(index)) + .fetch_optional(&self.pool) + .await + .map_err(SqlColdError::from)?, }; - let Some(block_hash) = self.fetch_block_hash(block).await? else { + + let Some(r) = row else { return Ok(None); }; + + let tx = row_to_tx_row(&r).into_tx().map_err(ColdStorageError::from)?; + let block = from_i64(r.get::("block_number")); + let index = from_i64(r.get::("tx_index")); + let hash_bytes: Vec = r.get("block_hash"); + let block_hash = alloy::primitives::B256::from_slice(&hash_bytes); let meta = ConfirmationMeta::new(block, block_hash, index); Ok(Some(Confirmed::new(tx, meta))) } @@ -612,17 +479,78 @@ impl ColdStorage for SqlColdBackend { } async fn get_receipt(&self, spec: ReceiptSpecifier) -> ColdResult>> { - let Some((block, index)) = self.resolve_receipt_spec(spec).await? else { - return Ok(None); + // Fetch receipt + block_hash in one query via JOIN + let receipt_row = match spec { + ReceiptSpecifier::TxHash(hash) => sqlx::query( + "SELECT r.*, h.block_hash + FROM transactions t + JOIN receipts r ON t.block_number = r.block_number AND t.tx_index = r.tx_index + JOIN headers h ON t.block_number = h.block_number + WHERE t.tx_hash = $1", + ) + .bind(hash.as_slice()) + .fetch_optional(&self.pool) + .await + .map_err(SqlColdError::from)?, + ReceiptSpecifier::BlockAndIndex { block, index } => sqlx::query( + "SELECT r.*, h.block_hash + FROM receipts r + JOIN headers h ON r.block_number = h.block_number + WHERE r.block_number = $1 AND r.tx_index = $2", + ) + .bind(to_i64(block)) + .bind(to_i64(index)) + .fetch_optional(&self.pool) + .await + .map_err(SqlColdError::from)?, }; - let Some(receipt) = self.fetch_receipt_by_location(block, index).await? else { + + let Some(rr) = receipt_row else { return Ok(None); }; - let Some(block_hash) = self.fetch_block_hash(block).await? else { - return Ok(None); + + let bn: i64 = rr.get("block_number"); + let tx_idx: i64 = rr.get("tx_index"); + let hash_bytes: Vec = rr.get("block_hash"); + let block_hash = alloy::primitives::B256::from_slice(&hash_bytes); + + let receipt = ReceiptRow { + block_number: bn, + tx_index: tx_idx, + tx_type: rr.get::("tx_type") as i16, + success: rr.get::("success") != 0, + cumulative_gas_used: rr.get("cumulative_gas_used"), }; + + let log_rows = sqlx::query( + "SELECT * FROM logs WHERE block_number = $1 AND tx_index = $2 ORDER BY log_index", + ) + .bind(bn) + .bind(tx_idx) + .fetch_all(&self.pool) + .await + .map_err(SqlColdError::from)?; + + let logs = log_rows + .into_iter() + .map(|r| LogRow { + block_number: r.get("block_number"), + tx_index: r.get("tx_index"), + log_index: r.get("log_index"), + address: r.get("address"), + topic0: r.get("topic0"), + topic1: r.get("topic1"), + topic2: r.get("topic2"), + topic3: r.get("topic3"), + data: r.get("data"), + }) + .collect(); + + let built = receipt_from_rows(receipt, logs).map_err(ColdStorageError::from)?; + let block = from_i64(bn); + let index = from_i64(tx_idx); let meta = ConfirmationMeta::new(block, block_hash, index); - Ok(Some(Confirmed::new(receipt, meta))) + Ok(Some(Confirmed::new(built, meta))) } async fn get_receipts_in_block(&self, block: BlockNumber) -> ColdResult> { @@ -635,45 +563,46 @@ impl ColdStorage for SqlColdBackend { .await .map_err(SqlColdError::from)?; - let mut receipts = Vec::with_capacity(receipt_rows.len()); - for rr in receipt_rows { - let tx_idx: i64 = rr.get("tx_index"); - let receipt = ReceiptRow { - block_number: rr.get("block_number"), - tx_index: tx_idx, - tx_type: rr.get::("tx_type") as i16, - success: rr.get::("success") != 0, - cumulative_gas_used: rr.get("cumulative_gas_used"), - }; - - let log_rows = sqlx::query( - "SELECT * FROM logs WHERE block_number = $1 AND tx_index = $2 ORDER BY log_index", - ) - .bind(bn) - .bind(tx_idx) - .fetch_all(&self.pool) - .await - .map_err(SqlColdError::from)?; + let all_log_rows = + sqlx::query("SELECT * FROM logs WHERE block_number = $1 ORDER BY tx_index, log_index") + .bind(bn) + .fetch_all(&self.pool) + .await + .map_err(SqlColdError::from)?; - let logs = log_rows - .into_iter() - .map(|r| LogRow { - block_number: r.get("block_number"), - tx_index: r.get("tx_index"), - log_index: r.get("log_index"), - address: r.get("address"), - topic0: r.get("topic0"), - topic1: r.get("topic1"), - topic2: r.get("topic2"), - topic3: r.get("topic3"), - data: r.get("data"), - }) - .collect(); - - receipts.push(receipt_from_rows(receipt, logs)?); + // Group logs by tx_index + let mut logs_by_tx: std::collections::BTreeMap> = + std::collections::BTreeMap::new(); + for r in all_log_rows { + let tx_idx: i64 = r.get("tx_index"); + logs_by_tx.entry(tx_idx).or_default().push(LogRow { + block_number: r.get("block_number"), + tx_index: tx_idx, + log_index: r.get("log_index"), + address: r.get("address"), + topic0: r.get("topic0"), + topic1: r.get("topic1"), + topic2: r.get("topic2"), + topic3: r.get("topic3"), + data: r.get("data"), + }); } - Ok(receipts) + receipt_rows + .into_iter() + .map(|rr| { + let tx_idx: i64 = rr.get("tx_index"); + let receipt = ReceiptRow { + block_number: rr.get("block_number"), + tx_index: tx_idx, + tx_type: rr.get::("tx_type") as i16, + success: rr.get::("success") != 0, + cumulative_gas_used: rr.get("cumulative_gas_used"), + }; + let logs = logs_by_tx.remove(&tx_idx).unwrap_or_default(); + receipt_from_rows(receipt, logs).map_err(ColdStorageError::from) + }) + .collect() } async fn get_signet_events( @@ -764,12 +693,11 @@ impl ColdStorage for SqlColdBackend { } async fn get_latest_block(&self) -> ColdResult> { - let row = sqlx::query("SELECT block_number FROM metadata WHERE key = $1") - .bind("latest_block") - .fetch_optional(&self.pool) + let row = sqlx::query("SELECT MAX(block_number) as max_bn FROM headers") + .fetch_one(&self.pool) .await .map_err(SqlColdError::from)?; - Ok(row.map(|r| from_i64(r.get::("block_number")))) + Ok(row.get::, _>("max_bn").map(from_i64)) } async fn append_block(&self, data: BlockData) -> ColdResult<()> { @@ -818,33 +746,6 @@ impl ColdStorage for SqlColdBackend { .await .map_err(SqlColdError::from)?; - // Update latest block metadata - let new_latest: Option = - sqlx::query("SELECT MAX(block_number) as max_bn FROM headers") - .fetch_one(&mut *tx) - .await - .map_err(SqlColdError::from)? - .get("max_bn"); - - match new_latest { - Some(latest) => { - sqlx::query( - "INSERT INTO metadata (key, block_number) VALUES ('latest_block', $1) - ON CONFLICT(key) DO UPDATE SET block_number = $1", - ) - .bind(latest) - .execute(&mut *tx) - .await - .map_err(SqlColdError::from)?; - } - None => { - sqlx::query("DELETE FROM metadata WHERE key = 'latest_block'") - .execute(&mut *tx) - .await - .map_err(SqlColdError::from)?; - } - } - tx.commit().await.map_err(SqlColdError::from)?; Ok(()) } diff --git a/crates/cold/src/mem.rs b/crates/cold/src/mem.rs index fb1fd52..740f1cb 100644 --- a/crates/cold/src/mem.rs +++ b/crates/cold/src/mem.rs @@ -43,9 +43,6 @@ struct MemColdBackendInner { /// Zenith headers indexed by block number. zenith_headers: BTreeMap, - - /// The latest (highest) block number in storage. - latest_block: Option, } /// In-memory cold storage backend. @@ -203,7 +200,7 @@ impl ColdStorage for MemColdBackend { async fn get_latest_block(&self) -> ColdResult> { let inner = self.inner.read().await; - Ok(inner.latest_block) + Ok(inner.headers.last_key_value().map(|(k, _)| *k)) } async fn append_block(&self, data: BlockData) -> ColdResult<()> { @@ -235,9 +232,6 @@ impl ColdStorage for MemColdBackend { inner.zenith_headers.insert(block, zh); } - // Update latest block - inner.latest_block = Some(inner.latest_block.map_or(block, |prev| prev.max(block))); - Ok(()) } @@ -270,9 +264,6 @@ impl ColdStorage for MemColdBackend { inner.zenith_headers.remove(k); } - // Update latest block - inner.latest_block = inner.headers.last_key_value().map(|(k, _)| *k); - Ok(()) } }