From b4ac43cede4bf156a1c90a6399bd60ae33b8b506 Mon Sep 17 00:00:00 2001 From: Swanny Date: Tue, 12 May 2026 12:01:02 -0400 Subject: [PATCH 1/2] chore: bump signet-storage family to 0.8 and migrate to new API Bumps the workspace to 0.18.0 and updates the signet-storage family of crates (signet-storage, signet-cold, signet-hot, signet-hot-mdbx, signet-cold-mdbx, signet-storage-types) from 0.7 to 0.8. This is a breaking upstream release, so the rest of the signet ecosystem (signet-bundle, signet-types, signet-evm, signet-zenith, etc.) and init4-bin-base also move forward to coherent versions: 0.16 -> 0.17, init4-bin-base 0.19.1 -> 0.20.0. Code migration for the new storage API: - UnifiedStorage -> UnifiedStorage (second generic for the cold-storage backend). The B parameter propagates through every type that holds the unified handle: StorageRpcCtx, SignetNode, SignetNodeBuilder, and all rpc endpoint signatures. - ColdStorageReadHandle -> ColdStorage (read handle is now a cheap clone of the cold storage handle itself). - ColdStorageTask::spawn / ColdStorageHandle removed; use ColdStorage::new or UnifiedStorage::spawn. - append_blocks and unwind_above on UnifiedStorage are now async. - signet-types 0.17 wraps headers in SignetHeaderV1. Sites that used Sealed
directly now bridge via SignetHeaderV1::new_unchecked and SignetHeaderV1::into_inner. - node-config exposes a NodeColdBackend type alias that resolves to EitherCold when SQL features are on and to MdbxColdBackend otherwise, so callers can name the cold side concretely without caring which runtime backend was chosen. Pre-push checks (fmt, clippy --all-features, clippy --no-default-features, doc) all pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- Cargo.toml | 58 ++++---- crates/block-processor/src/v1/processor.rs | 5 +- crates/host-rpc/src/notifier.rs | 9 +- crates/node-config/Cargo.toml | 1 + crates/node-config/src/lib.rs | 8 +- crates/node-config/src/storage.rs | 36 +++-- crates/node-tests/src/context.rs | 6 +- crates/node-tests/src/utils.rs | 4 +- crates/node/src/builder.rs | 17 +-- crates/node/src/node.rs | 18 ++- crates/node/src/rpc.rs | 6 +- crates/rpc/src/config/ctx.rs | 20 +-- crates/rpc/src/config/gas_oracle.rs | 6 +- crates/rpc/src/debug/endpoints.rs | 41 +++--- crates/rpc/src/debug/mod.rs | 22 +-- crates/rpc/src/eth/endpoints.rs | 155 +++++++++++++-------- crates/rpc/src/eth/helpers.rs | 5 +- crates/rpc/src/eth/mod.rs | 76 +++++----- crates/rpc/src/lib.rs | 3 +- crates/rpc/src/net/mod.rs | 10 +- crates/rpc/src/signet/endpoints.rs | 11 +- crates/rpc/src/signet/mod.rs | 8 +- crates/rpc/src/trace/endpoints.rs | 46 +++--- crates/rpc/src/trace/mod.rs | 22 +-- crates/rpc/src/web3/mod.rs | 4 +- crates/rpc/tests/eth_rpc.rs | 11 +- 26 files changed, 361 insertions(+), 247 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 27e9b035..43244ea6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["crates/*"] resolver = "2" [workspace.package] -version = "0.17.2" +version = "0.18.0" edition = "2024" rust-version = "1.88" authors = ["init4"] @@ -34,34 +34,34 @@ debug = false incremental = false [workspace.dependencies] -signet-blobber = { version = "0.17.2", path = "crates/blobber" } -signet-block-processor = { version = "0.17.2", path = "crates/block-processor" } -signet-genesis = { version = "0.17.2", path = "crates/genesis" } -signet-host-reth = { version = "0.17.2", path = "crates/host-reth" } -signet-host-rpc = { version = "0.17.2", path = "crates/host-rpc" } -signet-node = { version = "0.17.2", path = "crates/node" } -signet-node-config = { version = "0.17.2", path = "crates/node-config" } -signet-node-tests = { version = "0.17.2", path = "crates/node-tests" } -signet-node-types = { version = "0.17.2", path = "crates/node-types" } -signet-rpc = { version = "0.17.2", path = "crates/rpc" } - -init4-bin-base = { version = "0.19.1", features = ["alloy"] } - -signet-bundle = "0.16.0" -signet-constants = "0.16.0" -signet-evm = "0.16.0" -signet-extract = "0.16.0" -signet-test-utils = "0.16.0" -signet-tx-cache = "0.16.0" -signet-types = "0.16.0" -signet-zenith = "0.16.0" -signet-journal = "0.16.0" -signet-storage = "0.7" -signet-cold = "0.7" -signet-hot = "0.7" -signet-hot-mdbx = "0.7" -signet-cold-mdbx = "0.7" -signet-storage-types = "0.7" +signet-blobber = { version = "0.18.0", path = "crates/blobber" } +signet-block-processor = { version = "0.18.0", path = "crates/block-processor" } +signet-genesis = { version = "0.18.0", path = "crates/genesis" } +signet-host-reth = { version = "0.18.0", path = "crates/host-reth" } +signet-host-rpc = { version = "0.18.0", path = "crates/host-rpc" } +signet-node = { version = "0.18.0", path = "crates/node" } +signet-node-config = { version = "0.18.0", path = "crates/node-config" } +signet-node-tests = { version = "0.18.0", path = "crates/node-tests" } +signet-node-types = { version = "0.18.0", path = "crates/node-types" } +signet-rpc = { version = "0.18.0", path = "crates/rpc" } + +init4-bin-base = { version = "0.20.0", features = ["alloy"] } + +signet-bundle = "0.17" +signet-constants = "0.17" +signet-evm = "0.17" +signet-extract = "0.17" +signet-test-utils = "0.17" +signet-tx-cache = "0.17" +signet-types = "0.17" +signet-zenith = "0.17" +signet-journal = "0.17" +signet-storage = "0.8" +signet-cold = "0.8" +signet-hot = "0.8" +signet-hot-mdbx = "0.8" +signet-cold-mdbx = "0.8" +signet-storage-types = "0.8" # ajj ajj = "0.7.0" diff --git a/crates/block-processor/src/v1/processor.rs b/crates/block-processor/src/v1/processor.rs index bbf374ce..9a49421e 100644 --- a/crates/block-processor/src/v1/processor.rs +++ b/crates/block-processor/src/v1/processor.rs @@ -15,6 +15,7 @@ use signet_hot::{ model::{HotKv, HotKvRead, RevmRead}, }; use signet_storage_types::{DbSignetEvent, DbZenithHeader, ExecutedBlock, ExecutedBlockBuilder}; +use signet_types::primitives::SignetHeaderV1; use std::collections::VecDeque; use tracing::{error, instrument}; use trevm::revm::{ @@ -195,7 +196,7 @@ where block_extracts, to_alias, txns, - parent_header, + SignetHeaderV1::new_unchecked(parent_header.unseal()), self.constants.clone(), ); @@ -255,7 +256,7 @@ where let zenith_header = block_extracts.ru_header().map(DbZenithHeader::from); ExecutedBlockBuilder::new() - .header(header) + .header(header.into_inner()) .bundle(bundle) .transactions(transactions) .receipts(receipts) diff --git a/crates/host-rpc/src/notifier.rs b/crates/host-rpc/src/notifier.rs index d9d31496..31ca4399 100644 --- a/crates/host-rpc/src/notifier.rs +++ b/crates/host-rpc/src/notifier.rs @@ -3,14 +3,14 @@ use alloy::{ consensus::{BlockHeader, transaction::Recovered}, eips::{BlockId, BlockNumberOrTag}, network::BlockResponse, - primitives::{B256, Sealed}, + primitives::B256, providers::Provider, pubsub::SubscriptionStream, rpc::types::Header as RpcHeader, }; use futures_util::{StreamExt, TryStreamExt, stream}; use signet_node_types::{HostNotification, HostNotificationKind, HostNotifier, RevertRange}; -use signet_types::primitives::{RecoveredBlock, SealedBlock, TransactionSigned}; +use signet_types::primitives::{RecoveredBlock, SealedBlock, SignetHeaderV1, TransactionSigned}; use std::{collections::VecDeque, sync::Arc, time::Instant}; use tracing::{debug, info, warn}; @@ -189,7 +189,6 @@ where rpc_block: alloy::rpc::types::Block, rpc_receipts: Option>, ) -> RpcBlock { - let hash = rpc_block.header.hash; let block = rpc_block .map_transactions(|tx| { let recovered = tx.inner; @@ -198,7 +197,9 @@ where Recovered::new_unchecked(tx, signer) }) .into_consensus(); - let sealed_header = Sealed::new_unchecked(block.header, hash); + // SignetHeaderV1 reseals the header; the recomputed hash matches the + // RPC-supplied hash for any well-formed provider response. + let sealed_header = SignetHeaderV1::new_unchecked(block.header); let block: RecoveredBlock = SealedBlock::new(sealed_header, block.body.transactions); let receipts = rpc_receipts .unwrap_or_default() diff --git a/crates/node-config/Cargo.toml b/crates/node-config/Cargo.toml index 9a1a34cb..511e06b5 100644 --- a/crates/node-config/Cargo.toml +++ b/crates/node-config/Cargo.toml @@ -11,6 +11,7 @@ repository.workspace = true [dependencies] signet-blobber.workspace = true +signet-cold-mdbx.workspace = true signet-storage.workspace = true signet-types.workspace = true diff --git a/crates/node-config/src/lib.rs b/crates/node-config/src/lib.rs index c3b6e8ac..10f0597f 100644 --- a/crates/node-config/src/lib.rs +++ b/crates/node-config/src/lib.rs @@ -18,7 +18,13 @@ pub use core::SignetNodeConfig; // responsibility of the host adapter crate (e.g. `signet-host-reth`). mod storage; -pub use storage::StorageConfig; +pub use storage::{NodeColdBackend, StorageConfig}; + +// `signet-cold-mdbx` is referenced via `NodeColdBackend` only when the SQL +// features are disabled. Keep the dependency satisfied for the SQL-enabled +// build so callers can still type-name the backend uniformly. +#[cfg(any(feature = "postgres", feature = "sqlite"))] +use signet_cold_mdbx as _; /// Test configuration for Signet Nodes. #[cfg(feature = "test_utils")] diff --git a/crates/node-config/src/storage.rs b/crates/node-config/src/storage.rs index 6270b565..be582ca6 100644 --- a/crates/node-config/src/storage.rs +++ b/crates/node-config/src/storage.rs @@ -1,12 +1,24 @@ use init4_bin_base::utils::from_env::FromEnv; +use signet_storage::{DatabaseEnv, Either, MdbxConnector, UnifiedStorage, builder::StorageBuilder}; #[cfg(any(feature = "postgres", feature = "sqlite"))] -use signet_storage::SqlConnector; -use signet_storage::{DatabaseEnv, MdbxConnector, UnifiedStorage, builder::StorageBuilder}; +use signet_storage::{SqlConnector, either::EitherCold}; use std::borrow::Cow; #[cfg(any(feature = "postgres", feature = "sqlite"))] use std::time::Duration; use tokio_util::sync::CancellationToken; +/// Cold storage backend used by the unified node storage. +/// +/// When SQL features are enabled, this is the [`EitherCold`] enum that can +/// hold either an MDBX or SQL cold backend (selected at runtime). When SQL +/// features are disabled, it falls back to MDBX only. +#[cfg(any(feature = "postgres", feature = "sqlite"))] +pub type NodeColdBackend = EitherCold; + +/// Cold storage backend used by the unified node storage (no SQL feature). +#[cfg(not(any(feature = "postgres", feature = "sqlite")))] +pub type NodeColdBackend = signet_cold_mdbx::MdbxColdBackend; + /// Configuration for signet unified storage. /// /// Reads hot and cold storage configuration from environment variables. @@ -22,12 +34,10 @@ use tokio_util::sync::CancellationToken; /// Exactly one of `SIGNET_COLD_PATH` or `SIGNET_COLD_SQL_URL` must be set. /// /// When using SQL cold storage, connection pool tuning is configured via -/// [`SqlConnector`]'s own environment variables (e.g. +/// the `SqlConnector`'s own environment variables (e.g. /// `SIGNET_COLD_SQL_MAX_CONNECTIONS`). See the `cold-sql` feature of /// `init4-bin-base` for the full list. /// -/// [`SqlConnector`]: signet_storage::SqlConnector -/// /// # Example /// /// ```rust,no_run @@ -163,7 +173,7 @@ impl StorageConfig { pub async fn build_storage( &self, cancel: CancellationToken, - ) -> eyre::Result> { + ) -> eyre::Result> { let hot = MdbxConnector::new(self.hot_path.as_ref()); let has_mdbx = !self.cold_path.is_empty(); @@ -172,10 +182,20 @@ impl StorageConfig { #[cfg(not(any(feature = "postgres", feature = "sqlite")))] let has_sql = std::env::var("SIGNET_COLD_SQL_URL").is_ok_and(|v| !v.is_empty()); + // Helper to label the right-hand variant of `Either` for the + // current feature set, so both match arms produce the same + // `Either` type. + #[cfg(any(feature = "postgres", feature = "sqlite"))] + type RightCold = SqlConnector; + #[cfg(not(any(feature = "postgres", feature = "sqlite")))] + type RightCold = (); + match (has_mdbx, has_sql) { (true, false) => Ok(StorageBuilder::new() .hot(hot) - .cold(MdbxConnector::new(self.cold_path.as_ref())) + .cold(Either::::left(MdbxConnector::new( + self.cold_path.as_ref(), + ))) .cancel_token(cancel) .build() .await?), @@ -185,7 +205,7 @@ impl StorageConfig { self.cold_sql.clone().expect("cold_sql must be Some when has_sql is true"); Ok(StorageBuilder::new() .hot(hot) - .cold(connector) + .cold(Either::::right(connector)) .cancel_token(cancel) .build() .await?) diff --git a/crates/node-tests/src/context.rs b/crates/node-tests/src/context.rs index d2ad4434..39daf302 100644 --- a/crates/node-tests/src/context.rs +++ b/crates/node-tests/src/context.rs @@ -15,7 +15,7 @@ use alloy::{ rpc::types::eth::{TransactionReceipt, TransactionRequest}, }; use signet_blobber::MemoryBlobSource; -use signet_cold::{ColdStorageReadHandle, mem::MemColdBackend}; +use signet_cold::{ColdStorage, mem::MemColdBackend}; use signet_hot::{ db::{HotDbRead, UnsafeDbWrite}, mem::MemKv, @@ -103,7 +103,7 @@ pub struct SignetTestContext { pub node_status: watch::Receiver, /// Unified hot + cold storage for the rollup. - pub storage: Arc>, + pub storage: Arc>, /// An alloy provider connected to the Signet Node RPC. pub alloy_provider: CtxProvider, @@ -288,7 +288,7 @@ impl SignetTestContext { } /// Get a cold storage read handle. - pub fn cold(&self) -> ColdStorageReadHandle { + pub fn cold(&self) -> ColdStorage { self.storage.cold_reader() } diff --git a/crates/node-tests/src/utils.rs b/crates/node-tests/src/utils.rs index 356ceadf..84d76bfe 100644 --- a/crates/node-tests/src/utils.rs +++ b/crates/node-tests/src/utils.rs @@ -5,7 +5,7 @@ use alloy::{ signers::{SignerSync, local::PrivateKeySigner}, uint, }; -use signet_types::primitives::{RecoveredBlock, Transaction, TransactionSigned}; +use signet_types::primitives::{RecoveredBlock, SignetHeaderV1, Transaction, TransactionSigned}; use signet_zenith::Zenith; use std::{panic, sync::Once}; use tracing_subscriber::EnvFilter; @@ -21,7 +21,7 @@ pub fn fake_block(number: u64) -> RecoveredBlock { excess_blob_gas: Some(0), ..Default::default() }; - RecoveredBlock::blank_with_header(header) + RecoveredBlock::blank_with_header(SignetHeaderV1::new_unchecked(header)) } /// Sign a transaction with a wallet. diff --git a/crates/node/src/builder.rs b/crates/node/src/builder.rs index 3995070f..ff31a02e 100644 --- a/crates/node/src/builder.rs +++ b/crates/node/src/builder.rs @@ -4,7 +4,7 @@ use crate::{NodeStatus, SignetNode}; use eyre::OptionExt; use signet_blobber::CacheHandle; use signet_block_processor::AliasOracleFactory; -use signet_cold::BlockData; +use signet_cold::{BlockData, ColdStorageBackend}; use signet_hot::db::{HotDbRead, UnsafeDbWrite}; use signet_node_config::SignetNodeConfig; use signet_node_types::HostNotifier; @@ -26,7 +26,7 @@ pub struct NotAStorage; /// /// The builder requires the following components to be set before building: /// - A [`HostNotifier`], via [`Self::with_notifier`]. -/// - An [`Arc>`], via [`Self::with_storage`]. +/// - An [`Arc>`], via [`Self::with_storage`]. /// - An [`AliasOracleFactory`], via [`Self::with_alias_oracle`]. /// - A [`CacheHandle`], via [`Self::with_blob_cacher`]. /// - A [`ServeConfig`], via [`Self::with_serve_config`]. @@ -41,7 +41,7 @@ pub struct NotAStorage; /// # fn example( /// # config: signet_node_config::SignetNodeConfig, /// # notifier: impl signet_node_types::HostNotifier, -/// # storage: std::sync::Arc>, +/// # storage: std::sync::Arc>, /// # alias_oracle: impl signet_block_processor::AliasOracleFactory, /// # blob_cacher: signet_blobber::CacheHandle, /// # serve_config: signet_rpc::ServeConfig, @@ -91,10 +91,10 @@ impl SignetNodeBuilder { impl SignetNodeBuilder { /// Set the [`UnifiedStorage`] backend for the signet node. - pub fn with_storage( + pub fn with_storage( self, - storage: Arc>, - ) -> SignetNodeBuilder>, Aof> { + storage: Arc>, + ) -> SignetNodeBuilder>, Aof> { SignetNodeBuilder { config: self.config, alias_oracle: self.alias_oracle, @@ -163,10 +163,11 @@ impl SignetNodeBuilder { } } -impl SignetNodeBuilder>, Aof> +impl SignetNodeBuilder>, Aof> where N: HostNotifier, H: HotKv + Clone + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, Aof: AliasOracleFactory, { @@ -214,7 +215,7 @@ where /// - Inits storage from genesis if needed. pub async fn build( mut self, - ) -> eyre::Result<(SignetNode, tokio::sync::watch::Receiver)> { + ) -> eyre::Result<(SignetNode, tokio::sync::watch::Receiver)> { self.prebuild().await?; // NB: Notifier, Storage, and Aof are enforced by typestate generics. // The remaining fields are set via `Option` and checked at runtime. diff --git a/crates/node/src/node.rs b/crates/node/src/node.rs index ea045fc3..b95bda30 100644 --- a/crates/node/src/node.rs +++ b/crates/node/src/node.rs @@ -3,6 +3,7 @@ use alloy::consensus::BlockHeader; use eyre::{Context, OptionExt}; use signet_blobber::CacheHandle; use signet_block_processor::{AliasOracleFactory, SignetBlockProcessorV1}; +use signet_cold::ColdStorageBackend; use signet_evm::EthereumHardfork; use signet_extract::{Extractable, Extractor}; use signet_node_config::SignetNodeConfig; @@ -19,10 +20,11 @@ use tracing::{debug, info, instrument}; use trevm::revm::database::DBErrorMarker; /// Signet context and configuration. -pub struct SignetNode +pub struct SignetNode where N: HostNotifier, H: HotKv, + B: ColdStorageBackend, { /// The host notifier, which yields chain notifications. pub(crate) notifier: N, @@ -31,7 +33,7 @@ where pub(crate) config: Arc, /// Unified hot + cold storage backend. - pub(crate) storage: Arc>, + pub(crate) storage: Arc>, /// Shared chain state (block tags + notification sender). /// Cloned to the RPC context on startup. @@ -63,20 +65,22 @@ where pub(crate) rpc_config: StorageRpcConfig, } -impl fmt::Debug for SignetNode +impl fmt::Debug for SignetNode where N: HostNotifier, H: HotKv, + B: ColdStorageBackend, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SignetNode").field("config", &self.config).finish_non_exhaustive() } } -impl SignetNode +impl SignetNode where N: HostNotifier, H: HotKv + Clone + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, AliasOracle: AliasOracleFactory, { @@ -97,7 +101,7 @@ where pub fn new_unsafe( notifier: N, config: SignetNodeConfig, - storage: Arc>, + storage: Arc>, alias_oracle: AliasOracle, client: reqwest::Client, blob_cacher: CacheHandle, @@ -151,7 +155,7 @@ where unwind_to = target, "storage layers inconsistent, reconciling" ); - self.storage.unwind_above(target)?; + self.storage.unwind_above(target).await?; } } @@ -282,7 +286,7 @@ where ); let executed = processor.process_block(block_extracts).await?; self.notify_new_block(&executed); - self.storage.append_blocks(vec![executed])?; + self.storage.append_blocks(vec![executed]).await?; processed = true; } Ok(processed) diff --git a/crates/node/src/rpc.rs b/crates/node/src/rpc.rs index e143f97a..0b2be1df 100644 --- a/crates/node/src/rpc.rs +++ b/crates/node/src/rpc.rs @@ -1,5 +1,6 @@ use crate::SignetNode; use signet_block_processor::AliasOracleFactory; +use signet_cold::ColdStorageBackend; use signet_node_types::HostNotifier; use signet_rpc::{RpcServerGuard, StorageRpcCtx}; use signet_storage::HotKv; @@ -7,10 +8,11 @@ use signet_tx_cache::TxCache; use std::sync::Arc; use tracing::info; -impl SignetNode +impl SignetNode where N: HostNotifier, H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: trevm::revm::database::DBErrorMarker, AliasOracle: AliasOracleFactory, { @@ -34,7 +36,7 @@ where tx_cache, self.rpc_config, ); - let router = signet_rpc::router::().with_state(rpc_ctx); + let router = signet_rpc::router::().with_state(rpc_ctx); self.serve_config.clone().serve(router).await.map_err(Into::into) } diff --git a/crates/rpc/src/config/ctx.rs b/crates/rpc/src/config/ctx.rs index 042a9e0f..cb5246db 100644 --- a/crates/rpc/src/config/ctx.rs +++ b/crates/rpc/src/config/ctx.rs @@ -68,7 +68,7 @@ use alloy::{ eips::{BlockId, BlockNumberOrTag}, genesis::ChainConfig, }; -use signet_cold::ColdStorageReadHandle; +use signet_cold::{ColdStorage, ColdStorageBackend}; use signet_evm::EthereumHardfork; use signet_hot::{ HotKv, @@ -123,19 +123,19 @@ pub(crate) struct EvmBlockContext { /// Call [`StorageRpcCtx::new`] with unified storage, system constants, /// a [`ChainNotifier`], an optional [`TxCache`], and [`StorageRpcConfig`]. #[derive(Debug)] -pub struct StorageRpcCtx { - inner: Arc>, +pub struct StorageRpcCtx { + inner: Arc>, } -impl Clone for StorageRpcCtx { +impl Clone for StorageRpcCtx { fn clone(&self) -> Self { Self { inner: Arc::clone(&self.inner) } } } #[derive(Debug)] -struct StorageRpcCtxInner { - storage: Arc>, +struct StorageRpcCtxInner { + storage: Arc>, constants: SignetSystemConstants, chain_config: ChainConfig, chain: ChainNotifier, @@ -147,7 +147,7 @@ struct StorageRpcCtxInner { gas_cache: GasOracleCache, } -impl StorageRpcCtx { +impl StorageRpcCtx { /// Create a new storage-backed RPC context. /// /// The [`ChainNotifier`] provides block tag tracking and a broadcast @@ -157,7 +157,7 @@ impl StorageRpcCtx { /// The `chain_config` is the rollup genesis chain configuration, used /// to determine the active EVM hardfork (spec ID) for each block. pub fn new( - storage: Arc>, + storage: Arc>, constants: SignetSystemConstants, chain_config: ChainConfig, chain: ChainNotifier, @@ -186,12 +186,12 @@ impl StorageRpcCtx { } /// Access the unified storage. - pub fn storage(&self) -> &UnifiedStorage { + pub fn storage(&self) -> &UnifiedStorage { &self.inner.storage } /// Get a cold storage read handle. - pub fn cold(&self) -> ColdStorageReadHandle { + pub fn cold(&self) -> ColdStorage { self.inner.storage.cold_reader() } diff --git a/crates/rpc/src/config/gas_oracle.rs b/crates/rpc/src/config/gas_oracle.rs index a77d838c..4178de66 100644 --- a/crates/rpc/src/config/gas_oracle.rs +++ b/crates/rpc/src/config/gas_oracle.rs @@ -8,7 +8,7 @@ use crate::config::{GasOracleCache, StorageRpcConfig}; use alloy::{consensus::Transaction, primitives::U256}; -use signet_cold::{ColdStorageError, ColdStorageReadHandle, HeaderSpecifier}; +use signet_cold::{ColdStorageBackend, ColdStorageError, HeaderSpecifier}; /// Suggest a tip cap based on recent transaction tips. /// @@ -22,8 +22,8 @@ use signet_cold::{ColdStorageError, ColdStorageReadHandle, HeaderSpecifier}; /// /// Uses the provided `cache` to avoid redundant cold storage reads /// when the tip has already been computed for the current block. -pub(crate) async fn suggest_tip_cap( - cold: &ColdStorageReadHandle, +pub(crate) async fn suggest_tip_cap( + cold: &signet_cold::ColdStorage, latest: u64, config: &StorageRpcConfig, cache: &GasOracleCache, diff --git a/crates/rpc/src/debug/endpoints.rs b/crates/rpc/src/debug/endpoints.rs index cb763eb8..e4453da7 100644 --- a/crates/rpc/src/debug/endpoints.rs +++ b/crates/rpc/src/debug/endpoints.rs @@ -19,6 +19,7 @@ use alloy::{ rpc::types::trace::geth::{GethDebugTracingOptions, GethTrace, TraceResult}, }; use itertools::Itertools; +use signet_cold::ColdStorageBackend; use signet_hot::{HotKv, model::HotKvRead}; use signet_types::{MagicSig, constants::SignetSystemConstants}; use tracing::Instrument; @@ -79,14 +80,15 @@ where } /// `debug_traceBlockByNumber` and `debug_traceBlockByHash` handler. -pub(crate) async fn trace_block( +pub(crate) async fn trace_block( hctx: HandlerCtx, TraceBlockParams(id, opts): TraceBlockParams, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result, DebugError> where T: Into, H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let opts = opts.unwrap_or_default(); @@ -149,13 +151,14 @@ where } /// `debug_traceTransaction` handler. -pub(crate) async fn trace_transaction( +pub(crate) async fn trace_transaction( hctx: HandlerCtx, TraceTransactionParams(tx_hash, opts): TraceTransactionParams, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let opts = opts.unwrap_or_default(); @@ -240,13 +243,14 @@ where } /// `debug_traceBlock` — trace all transactions in a raw RLP-encoded block. -pub(crate) async fn trace_block_rlp( +pub(crate) async fn trace_block_rlp( hctx: HandlerCtx, (rlp_bytes, opts): (Bytes, Option), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result, DebugError> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let opts = opts.unwrap_or_default(); @@ -296,13 +300,14 @@ where /// Resolves the given [`BlockId`], fetches header and transactions from cold /// storage, assembles them into an [`alloy::consensus::Block`], and returns /// the RLP-encoded bytes. -pub(crate) async fn get_raw_block( +pub(crate) async fn get_raw_block( hctx: HandlerCtx, (id,): (BlockId,), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let span = tracing::debug_span!("getRawBlock", ?id); @@ -350,13 +355,14 @@ where /// /// Fetches all receipts for the given [`BlockId`] and returns a list of /// EIP-2718 encoded consensus receipt envelopes (one per transaction). -pub(crate) async fn get_raw_receipts( +pub(crate) async fn get_raw_receipts( hctx: HandlerCtx, (id,): (BlockId,), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result, DebugError> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let span = tracing::debug_span!("getRawReceipts", ?id); @@ -407,13 +413,14 @@ where /// `debug_getRawHeader` handler. /// /// Resolves the given [`BlockId`] and returns the RLP-encoded block header. -pub(crate) async fn get_raw_header( +pub(crate) async fn get_raw_header( hctx: HandlerCtx, (id,): (BlockId,), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let span = tracing::debug_span!("getRawHeader", ?id); @@ -447,17 +454,18 @@ where /// from a [`alloy::rpc::types::TransactionRequest`], then routes through /// the tracer. State overrides are not supported in this initial /// implementation. -pub(crate) async fn debug_trace_call( +pub(crate) async fn debug_trace_call( hctx: HandlerCtx, (request, block_id, opts): ( alloy::rpc::types::TransactionRequest, Option, Option, ), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let opts = opts.unwrap_or_default(); @@ -502,13 +510,14 @@ where /// /// Fetches the transaction by hash from cold storage and returns the /// EIP-2718 encoded bytes. -pub(crate) async fn get_raw_transaction( +pub(crate) async fn get_raw_transaction( hctx: HandlerCtx, (hash,): (B256,), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let span = tracing::debug_span!("getRawTransaction", %hash); diff --git a/crates/rpc/src/debug/mod.rs b/crates/rpc/src/debug/mod.rs index 5825bfa9..f070262e 100644 --- a/crates/rpc/src/debug/mod.rs +++ b/crates/rpc/src/debug/mod.rs @@ -12,23 +12,25 @@ mod types; use crate::config::StorageRpcCtx; use alloy::{eips::BlockNumberOrTag, primitives::B256}; +use signet_cold::ColdStorageBackend; use signet_hot::{HotKv, model::HotKvRead}; use trevm::revm::database::DBErrorMarker; /// Instantiate a `debug` API router backed by storage. -pub(crate) fn debug() -> ajj::Router> +pub(crate) fn debug() -> ajj::Router> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { ajj::Router::new() - .route("traceBlockByNumber", trace_block::) - .route("traceBlockByHash", trace_block::) - .route("traceTransaction", trace_transaction::) - .route("traceBlock", trace_block_rlp::) - .route("getRawBlock", get_raw_block::) - .route("getRawHeader", get_raw_header::) - .route("getRawReceipts", get_raw_receipts::) - .route("getRawTransaction", get_raw_transaction::) - .route("traceCall", debug_trace_call::) + .route("traceBlockByNumber", trace_block::) + .route("traceBlockByHash", trace_block::) + .route("traceTransaction", trace_transaction::) + .route("traceBlock", trace_block_rlp::) + .route("getRawBlock", get_raw_block::) + .route("getRawHeader", get_raw_header::) + .route("getRawReceipts", get_raw_receipts::) + .route("getRawTransaction", get_raw_transaction::) + .route("traceCall", debug_trace_call::) } diff --git a/crates/rpc/src/eth/endpoints.rs b/crates/rpc/src/eth/endpoints.rs index 1ce6604b..6e97b374 100644 --- a/crates/rpc/src/eth/endpoints.rs +++ b/crates/rpc/src/eth/endpoints.rs @@ -30,7 +30,7 @@ use alloy::{ }; use revm_inspectors::access_list::AccessListInspector; use serde::Serialize; -use signet_cold::{HeaderSpecifier, ReceiptSpecifier}; +use signet_cold::{ColdStorageBackend, HeaderSpecifier, ReceiptSpecifier}; use signet_hot::{HistoryRead, HotKv, db::HotDbRead, model::HotKvRead}; use tracing::{Instrument, debug, trace, trace_span}; use trevm::{ @@ -58,7 +58,9 @@ pub(crate) enum SyncingResponse { } /// `eth_syncing` — returns sync status or `false` when fully synced. -pub(crate) async fn syncing(ctx: StorageRpcCtx) -> Result { +pub(crate) async fn syncing( + ctx: StorageRpcCtx, +) -> Result { match ctx.tags().sync_status() { Some(status) => Ok(SyncingResponse::Syncing { starting_block: U64::from(status.starting_block), @@ -92,12 +94,16 @@ pub(crate) async fn protocol_version() -> Result { // --------------------------------------------------------------------------- /// `eth_blockNumber` — returns the latest block number from block tags. -pub(crate) async fn block_number(ctx: StorageRpcCtx) -> Result { +pub(crate) async fn block_number( + ctx: StorageRpcCtx, +) -> Result { Ok(U64::from(ctx.tags().latest())) } /// `eth_chainId` — returns the configured chain ID. -pub(crate) async fn chain_id(ctx: StorageRpcCtx) -> Result { +pub(crate) async fn chain_id( + ctx: StorageRpcCtx, +) -> Result { Ok(U64::from(ctx.chain_id())) } @@ -106,9 +112,13 @@ pub(crate) async fn chain_id(ctx: StorageRpcCtx) -> Result // --------------------------------------------------------------------------- /// `eth_gasPrice` — suggests gas price based on recent block tips + base fee. -pub(crate) async fn gas_price(hctx: HandlerCtx, ctx: StorageRpcCtx) -> Result +pub(crate) async fn gas_price( + hctx: HandlerCtx, + ctx: StorageRpcCtx, +) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let task = async move { @@ -130,12 +140,13 @@ where } /// `eth_maxPriorityFeePerGas` — suggests priority fee from recent block tips. -pub(crate) async fn max_priority_fee_per_gas( +pub(crate) async fn max_priority_fee_per_gas( hctx: HandlerCtx, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let task = async move { @@ -147,13 +158,14 @@ where } /// `eth_feeHistory` — returns base fee and reward percentile data. -pub(crate) async fn fee_history( +pub(crate) async fn fee_history( hctx: HandlerCtx, FeeHistoryArgs(block_count, newest, reward_percentiles): FeeHistoryArgs, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let task = async move { @@ -315,14 +327,15 @@ fn calculate_reward_percentiles( /// `eth_getBlockByHash` / `eth_getBlockByNumber` — resolve block, fetch /// header + transactions from cold storage, assemble RPC block response. -pub(crate) async fn block( +pub(crate) async fn block( hctx: HandlerCtx, BlockParams(t, full): BlockParams, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result, EthError> where T: Into, H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let id = t.into(); @@ -366,14 +379,15 @@ where } /// `eth_getBlockTransactionCount*` — transaction count in a block. -pub(crate) async fn block_tx_count( +pub(crate) async fn block_tx_count( hctx: HandlerCtx, (t,): (T,), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result, EthError> where T: Into, H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let id = t.into(); @@ -389,13 +403,14 @@ where } /// `eth_getBlockReceipts` — all receipts in a block. -pub(crate) async fn block_receipts( +pub(crate) async fn block_receipts( hctx: HandlerCtx, (id,): (BlockId,), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result, EthError> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let task = async move { @@ -421,14 +436,15 @@ where } /// `eth_getBlockHeaderByHash` / `eth_getBlockHeaderByNumber`. -pub(crate) async fn header_by( +pub(crate) async fn header_by( hctx: HandlerCtx, (t,): (T,), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result, EthError> where T: Into, H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let id = t.into(); @@ -453,13 +469,14 @@ where // --------------------------------------------------------------------------- /// `eth_getTransactionByHash` — look up transaction by hash from cold storage. -pub(crate) async fn transaction_by_hash( +pub(crate) async fn transaction_by_hash( hctx: HandlerCtx, (hash,): (B256,), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result, EthError> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let task = async move { @@ -481,13 +498,14 @@ where } /// `eth_getRawTransactionByHash` — RLP-encoded transaction bytes. -pub(crate) async fn raw_transaction_by_hash( +pub(crate) async fn raw_transaction_by_hash( hctx: HandlerCtx, (hash,): (B256,), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result, EthError> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let task = async move { @@ -498,14 +516,15 @@ where } /// `eth_getTransactionByBlock*AndIndex` — transaction by position in block. -pub(crate) async fn transaction_by_block_and_index( +pub(crate) async fn transaction_by_block_and_index( hctx: HandlerCtx, (t, index): (T, U64), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result, EthError> where T: Into, H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let id = t.into(); @@ -530,14 +549,15 @@ where } /// `eth_getRawTransactionByBlock*AndIndex` — raw RLP bytes by position. -pub(crate) async fn raw_transaction_by_block_and_index( +pub(crate) async fn raw_transaction_by_block_and_index( hctx: HandlerCtx, (t, index): (T, U64), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result, EthError> where T: Into, H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let id = t.into(); @@ -557,13 +577,14 @@ where /// `eth_getTransactionReceipt` — receipt by tx hash. Fetches the receipt, /// then the associated transaction and header for derived fields. -pub(crate) async fn transaction_receipt( +pub(crate) async fn transaction_receipt( hctx: HandlerCtx, (hash,): (B256,), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result, EthError> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let task = async move { @@ -592,13 +613,14 @@ where // --------------------------------------------------------------------------- /// `eth_getBalance` — account balance at a given block from hot storage. -pub(crate) async fn balance( +pub(crate) async fn balance( hctx: HandlerCtx, AddrWithBlock(address, block): AddrWithBlock, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let id = block.unwrap_or(BlockId::latest()); @@ -616,13 +638,14 @@ where } /// `eth_getStorageAt` — contract storage slot at a given block. -pub(crate) async fn storage_at( +pub(crate) async fn storage_at( hctx: HandlerCtx, StorageAtArgs(address, key, block): StorageAtArgs, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let id = block.unwrap_or(BlockId::latest()); @@ -640,13 +663,14 @@ where } /// `eth_getTransactionCount` — account nonce at a given block. -pub(crate) async fn addr_tx_count( +pub(crate) async fn addr_tx_count( hctx: HandlerCtx, AddrWithBlock(address, block): AddrWithBlock, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let id = block.unwrap_or(BlockId::latest()); @@ -664,13 +688,14 @@ where } /// `eth_getCode` — contract bytecode at a given block. -pub(crate) async fn code_at( +pub(crate) async fn code_at( hctx: HandlerCtx, AddrWithBlock(address, block): AddrWithBlock, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let id = block.unwrap_or(BlockId::latest()); @@ -706,13 +731,14 @@ where /// /// Resolves the block, builds a revm instance with the requested state /// and block overrides, then executes the transaction request. -pub(crate) async fn run_call( +pub(crate) async fn run_call( hctx: HandlerCtx, TxParams(request, block, state_overrides, block_overrides): TxParams, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let id = block.unwrap_or(BlockId::latest()); @@ -749,13 +775,14 @@ where /// /// Delegates to [`run_call`], then maps the execution result to raw /// output bytes, revert data, or halt reason. -pub(crate) async fn call( +pub(crate) async fn call( hctx: HandlerCtx, mut params: TxParams, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let max_gas = ctx.config().rpc_gas_cap; @@ -780,13 +807,14 @@ where } /// `eth_estimateGas` — estimate gas required for a transaction. -pub(crate) async fn estimate_gas( +pub(crate) async fn estimate_gas( hctx: HandlerCtx, TxParams(mut request, block, state_overrides, block_overrides): TxParams, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let max_gas = ctx.config().rpc_gas_cap; @@ -827,13 +855,14 @@ where } /// `eth_createAccessList` — generate an access list for a transaction. -pub(crate) async fn create_access_list( +pub(crate) async fn create_access_list( hctx: HandlerCtx, TxParams(mut request, block, state_overrides, block_overrides): TxParams, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let max_gas = ctx.config().rpc_gas_cap; @@ -884,13 +913,14 @@ where /// /// The transaction is forwarded to the tx cache in a fire-and-forget /// task; the hash is returned immediately. -pub(crate) async fn send_raw_transaction( +pub(crate) async fn send_raw_transaction( hctx: HandlerCtx, (tx,): (alloy::primitives::Bytes,), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let Some(tx_cache) = ctx.tx_cache().cloned() else { @@ -936,13 +966,14 @@ async fn collect_log_stream(stream: signet_cold::LogStream) -> signet_cold::Cold /// /// Uses `stream_logs` for deadline enforcement and dedicated concurrency /// control. The stream is collected into a `Vec` for the JSON-RPC response. -pub(crate) async fn get_logs( +pub(crate) async fn get_logs( hctx: HandlerCtx, (filter,): (Filter,), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result, EthError> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let task = async move { @@ -996,13 +1027,14 @@ where // --------------------------------------------------------------------------- /// `eth_newFilter` — install a log filter for polling. -pub(crate) async fn new_filter( +pub(crate) async fn new_filter( hctx: HandlerCtx, (filter,): (Filter,), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let task = async move { @@ -1014,12 +1046,13 @@ where } /// `eth_newBlockFilter` — install a block hash filter for polling. -pub(crate) async fn new_block_filter( +pub(crate) async fn new_block_filter( hctx: HandlerCtx, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let task = async move { @@ -1031,13 +1064,14 @@ where } /// `eth_uninstallFilter` — remove a filter. -pub(crate) async fn uninstall_filter( +pub(crate) async fn uninstall_filter( hctx: HandlerCtx, (id,): (U64,), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let task = async move { Ok(ctx.filter_manager().uninstall(id).is_some()) }; @@ -1046,13 +1080,14 @@ where /// `eth_getFilterChanges` / `eth_getFilterLogs` — poll a filter for new /// results since the last poll. Fetches matching data from cold storage. -pub(crate) async fn get_filter_changes( +pub(crate) async fn get_filter_changes( hctx: HandlerCtx, (id,): (U64,), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let task = async move { @@ -1141,13 +1176,14 @@ where // --------------------------------------------------------------------------- /// `eth_subscribe` — register a push-based subscription (WebSocket/SSE). -pub(crate) async fn subscribe( +pub(crate) async fn subscribe( hctx: HandlerCtx, sub: SubscribeArgs, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let interest: InterestKind = sub.try_into()?; @@ -1158,13 +1194,14 @@ where } /// `eth_unsubscribe` — cancel a push-based subscription. -pub(crate) async fn unsubscribe( +pub(crate) async fn unsubscribe( hctx: HandlerCtx, (id,): (U64,), - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let task = async move { Ok(ctx.sub_manager().unsubscribe(id)) }; diff --git a/crates/rpc/src/eth/helpers.rs b/crates/rpc/src/eth/helpers.rs index b0fa90c0..b4548b89 100644 --- a/crates/rpc/src/eth/helpers.rs +++ b/crates/rpc/src/eth/helpers.rs @@ -119,12 +119,13 @@ pub(crate) use await_handler; /// /// Used by account-state endpoints (`balance`, `storage_at`, /// `addr_tx_count`, `code_at`). -pub(crate) fn hot_reader_at_block( - ctx: &crate::config::StorageRpcCtx, +pub(crate) fn hot_reader_at_block( + ctx: &crate::config::StorageRpcCtx, id: BlockId, ) -> Result<(H::RoTx, u64), EthError> where H: signet_hot::HotKv, + B: signet_cold::ColdStorageBackend, ::Error: std::error::Error + Send + Sync + 'static, { let reader = ctx.hot_reader()?; diff --git a/crates/rpc/src/eth/mod.rs b/crates/rpc/src/eth/mod.rs index 89cf680b..c5229a41 100644 --- a/crates/rpc/src/eth/mod.rs +++ b/crates/rpc/src/eth/mod.rs @@ -18,61 +18,63 @@ pub(crate) mod types; use crate::config::StorageRpcCtx; use alloy::{eips::BlockNumberOrTag, primitives::B256}; +use signet_cold::ColdStorageBackend; use signet_hot::{HotKv, model::HotKvRead}; use trevm::revm::database::DBErrorMarker; /// Instantiate the `eth` API router backed by storage. -pub(crate) fn eth() -> ajj::Router> +pub(crate) fn eth() -> ajj::Router> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { ajj::Router::new() - .route("blockNumber", block_number::) - .route("chainId", chain_id::) - .route("getBlockByHash", block::) - .route("getBlockByNumber", block::) - .route("getBlockTransactionCountByHash", block_tx_count::) - .route("getBlockTransactionCountByNumber", block_tx_count::) - .route("getBlockReceipts", block_receipts::) - .route("getRawTransactionByHash", raw_transaction_by_hash::) - .route("getTransactionByHash", transaction_by_hash::) + .route("blockNumber", block_number::) + .route("chainId", chain_id::) + .route("getBlockByHash", block::) + .route("getBlockByNumber", block::) + .route("getBlockTransactionCountByHash", block_tx_count::) + .route("getBlockTransactionCountByNumber", block_tx_count::) + .route("getBlockReceipts", block_receipts::) + .route("getRawTransactionByHash", raw_transaction_by_hash::) + .route("getTransactionByHash", transaction_by_hash::) .route( "getRawTransactionByBlockHashAndIndex", - raw_transaction_by_block_and_index::, + raw_transaction_by_block_and_index::, ) .route( "getRawTransactionByBlockNumberAndIndex", - raw_transaction_by_block_and_index::, + raw_transaction_by_block_and_index::, ) - .route("getTransactionByBlockHashAndIndex", transaction_by_block_and_index::) + .route("getTransactionByBlockHashAndIndex", transaction_by_block_and_index::) .route( "getTransactionByBlockNumberAndIndex", - transaction_by_block_and_index::, + transaction_by_block_and_index::, ) - .route("getTransactionReceipt", transaction_receipt::) - .route("getBlockHeaderByHash", header_by::) - .route("getBlockHeaderByNumber", header_by::) - .route("getBalance", balance::) - .route("getStorageAt", storage_at::) - .route("getTransactionCount", addr_tx_count::) - .route("getCode", code_at::) - .route("call", call::) - .route("estimateGas", estimate_gas::) - .route("sendRawTransaction", send_raw_transaction::) - .route("getLogs", get_logs::) - .route("syncing", syncing::) - .route("gasPrice", gas_price::) - .route("maxPriorityFeePerGas", max_priority_fee_per_gas::) - .route("feeHistory", fee_history::) - .route("createAccessList", create_access_list::) - .route("newFilter", new_filter::) - .route("newBlockFilter", new_block_filter::) - .route("uninstallFilter", uninstall_filter::) - .route("getFilterChanges", get_filter_changes::) - .route("getFilterLogs", get_filter_changes::) - .route("subscribe", subscribe::) - .route("unsubscribe", unsubscribe::) + .route("getTransactionReceipt", transaction_receipt::) + .route("getBlockHeaderByHash", header_by::) + .route("getBlockHeaderByNumber", header_by::) + .route("getBalance", balance::) + .route("getStorageAt", storage_at::) + .route("getTransactionCount", addr_tx_count::) + .route("getCode", code_at::) + .route("call", call::) + .route("estimateGas", estimate_gas::) + .route("sendRawTransaction", send_raw_transaction::) + .route("getLogs", get_logs::) + .route("syncing", syncing::) + .route("gasPrice", gas_price::) + .route("maxPriorityFeePerGas", max_priority_fee_per_gas::) + .route("feeHistory", fee_history::) + .route("createAccessList", create_access_list::) + .route("newFilter", new_filter::) + .route("newBlockFilter", new_block_filter::) + .route("uninstallFilter", uninstall_filter::) + .route("getFilterChanges", get_filter_changes::) + .route("getFilterLogs", get_filter_changes::) + .route("subscribe", subscribe::) + .route("unsubscribe", unsubscribe::) // Uncle queries return semantically correct values (0 / null) // because Signet has no uncle blocks. .route("getUncleCountByBlockHash", uncle_count) diff --git a/crates/rpc/src/lib.rs b/crates/rpc/src/lib.rs index 40c5f62c..1c0d9237 100644 --- a/crates/rpc/src/lib.rs +++ b/crates/rpc/src/lib.rs @@ -39,9 +39,10 @@ pub use serve::{RpcServerGuard, ServeConfig, ServeConfigEnv, ServeError}; /// Instantiate a combined router with `eth`, `debug`, `trace`, `signet`, /// `web3`, and `net` namespaces. -pub fn router() -> ajj::Router> +pub fn router() -> ajj::Router> where H: signet_hot::HotKv + Send + Sync + 'static, + B: signet_cold::ColdStorageBackend, ::Error: trevm::revm::database::DBErrorMarker, { ajj::Router::new() diff --git a/crates/rpc/src/net/mod.rs b/crates/rpc/src/net/mod.rs index 44d45f02..3628286a 100644 --- a/crates/rpc/src/net/mod.rs +++ b/crates/rpc/src/net/mod.rs @@ -1,20 +1,24 @@ //! `net` namespace RPC handlers. use crate::config::StorageRpcCtx; +use signet_cold::ColdStorageBackend; use signet_hot::{HotKv, model::HotKvRead}; use trevm::revm::database::DBErrorMarker; /// Instantiate the `net` API router. -pub(crate) fn net() -> ajj::Router> +pub(crate) fn net() -> ajj::Router> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { - ajj::Router::new().route("version", version::).route("listening", listening) + ajj::Router::new().route("version", version::).route("listening", listening) } /// `net_version` — returns the chain ID as a decimal string. -pub(crate) async fn version(ctx: StorageRpcCtx) -> Result { +pub(crate) async fn version( + ctx: StorageRpcCtx, +) -> Result { Ok(ctx.chain_id().to_string()) } diff --git a/crates/rpc/src/signet/endpoints.rs b/crates/rpc/src/signet/endpoints.rs index 9a87b196..efc74f5a 100644 --- a/crates/rpc/src/signet/endpoints.rs +++ b/crates/rpc/src/signet/endpoints.rs @@ -8,6 +8,7 @@ use crate::{ use ajj::HandlerCtx; use alloy::eips::BlockId; use signet_bundle::{SignetBundleDriver, SignetCallBundle, SignetCallBundleResponse}; +use signet_cold::ColdStorageBackend; use signet_hot::{HotKv, model::HotKvRead}; use signet_types::SignedOrder; use std::time::Duration; @@ -19,13 +20,14 @@ use trevm::revm::database::DBErrorMarker; /// Forwards the order to the transaction cache asynchronously. The /// response is returned immediately — forwarding errors are logged /// but not propagated to the caller (fire-and-forget). -pub(super) async fn send_order( +pub(super) async fn send_order( hctx: HandlerCtx, order: SignedOrder, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result<(), SignetError> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let Some(tx_cache) = ctx.tx_cache().cloned() else { @@ -48,13 +50,14 @@ where } /// `signet_callBundle` handler. -pub(super) async fn call_bundle( +pub(super) async fn call_bundle( hctx: HandlerCtx, bundle: SignetCallBundle, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let timeout = bundle.bundle.timeout.unwrap_or(ctx.config().default_bundle_timeout_ms); diff --git a/crates/rpc/src/signet/mod.rs b/crates/rpc/src/signet/mod.rs index ad3fdd70..8de0a283 100644 --- a/crates/rpc/src/signet/mod.rs +++ b/crates/rpc/src/signet/mod.rs @@ -5,14 +5,18 @@ use endpoints::{call_bundle, send_order}; pub(crate) mod error; use crate::config::StorageRpcCtx; +use signet_cold::ColdStorageBackend; use signet_hot::{HotKv, model::HotKvRead}; use trevm::revm::database::DBErrorMarker; /// Instantiate a `signet` API router backed by storage. -pub(crate) fn signet() -> ajj::Router> +pub(crate) fn signet() -> ajj::Router> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { - ajj::Router::new().route("sendOrder", send_order::).route("callBundle", call_bundle::) + ajj::Router::new() + .route("sendOrder", send_order::) + .route("callBundle", call_bundle::) } diff --git a/crates/rpc/src/trace/endpoints.rs b/crates/rpc/src/trace/endpoints.rs index 204a3c48..ed14843c 100644 --- a/crates/rpc/src/trace/endpoints.rs +++ b/crates/rpc/src/trace/endpoints.rs @@ -22,6 +22,7 @@ use alloy::{ }, }; use itertools::Itertools; +use signet_cold::ColdStorageBackend; use signet_hot::{HotKv, model::HotKvRead}; use signet_types::{MagicSig, constants::SignetSystemConstants}; use tracing::Instrument; @@ -121,13 +122,14 @@ where } /// `trace_block` — return Parity traces for all transactions in a block. -pub(super) async fn trace_block( +pub(super) async fn trace_block( hctx: HandlerCtx, TraceBlockParams(id): TraceBlockParams, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result>, TraceError> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let _permit = ctx.acquire_tracing_permit().await; @@ -180,13 +182,14 @@ where } /// `trace_transaction` — return Parity traces for a single transaction. -pub(super) async fn trace_transaction( +pub(super) async fn trace_transaction( hctx: HandlerCtx, TraceTransactionParams(tx_hash): TraceTransactionParams, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result>, TraceError> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let _permit = ctx.acquire_tracing_permit().await; @@ -259,13 +262,14 @@ where } /// `trace_replayBlockTransactions` — replay all block txs with trace type selection. -pub(super) async fn replay_block_transactions( +pub(super) async fn replay_block_transactions( hctx: HandlerCtx, ReplayBlockParams(id, trace_types): ReplayBlockParams, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result>, TraceError> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let _permit = ctx.acquire_tracing_permit().await; @@ -315,13 +319,14 @@ where } /// `trace_replayTransaction` — replay a single tx with trace type selection. -pub(super) async fn replay_transaction( +pub(super) async fn replay_transaction( hctx: HandlerCtx, ReplayTransactionParams(tx_hash, trace_types): ReplayTransactionParams, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let _permit = ctx.acquire_tracing_permit().await; @@ -380,13 +385,14 @@ where } /// `trace_call` — trace a call with Parity output and state overrides. -pub(super) async fn trace_call( +pub(super) async fn trace_call( hctx: HandlerCtx, TraceCallParams(request, trace_types, block_id, state_overrides, block_overrides): TraceCallParams, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let _permit = ctx.acquire_tracing_permit().await; @@ -428,13 +434,14 @@ where /// /// Each call sees state changes from prior calls. Per-call trace /// types. Defaults to `BlockId::pending()` (matching reth). -pub(super) async fn trace_call_many( +pub(super) async fn trace_call_many( hctx: HandlerCtx, TraceCallManyParams(calls, block_id): TraceCallManyParams, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result, TraceError> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let _permit = ctx.acquire_tracing_permit().await; @@ -474,13 +481,14 @@ where } /// `trace_rawTransaction` — trace a transaction from raw RLP bytes. -pub(super) async fn trace_raw_transaction( +pub(super) async fn trace_raw_transaction( hctx: HandlerCtx, TraceRawTransactionParams(rlp_bytes, trace_types, block_id): TraceRawTransactionParams, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let _permit = ctx.acquire_tracing_permit().await; @@ -524,13 +532,14 @@ where /// /// Returns `None` if `indices.len() != 1` (Erigon compatibility, /// matching reth). -pub(super) async fn trace_get( +pub(super) async fn trace_get( hctx: HandlerCtx, TraceGetParams(tx_hash, indices): TraceGetParams, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result, TraceError> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { if indices.len() != 1 { @@ -546,13 +555,14 @@ where /// /// Brute-force replay with configurable block range limit (default /// 100 blocks). Matches reth's approach. -pub(super) async fn trace_filter( +pub(super) async fn trace_filter( hctx: HandlerCtx, TraceFilterParams(filter): TraceFilterParams, - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, ) -> Result, TraceError> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { let _permit = ctx.acquire_tracing_permit().await; diff --git a/crates/rpc/src/trace/mod.rs b/crates/rpc/src/trace/mod.rs index bd3e175a..2a82ac03 100644 --- a/crates/rpc/src/trace/mod.rs +++ b/crates/rpc/src/trace/mod.rs @@ -10,23 +10,25 @@ pub use error::TraceError; mod types; use crate::config::StorageRpcCtx; +use signet_cold::ColdStorageBackend; use signet_hot::{HotKv, model::HotKvRead}; use trevm::revm::database::DBErrorMarker; /// Instantiate a `trace` API router backed by storage. -pub(crate) fn trace() -> ajj::Router> +pub(crate) fn trace() -> ajj::Router> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { ajj::Router::new() - .route("block", trace_block::) - .route("transaction", trace_transaction::) - .route("replayBlockTransactions", replay_block_transactions::) - .route("replayTransaction", replay_transaction::) - .route("call", trace_call::) - .route("callMany", trace_call_many::) - .route("rawTransaction", trace_raw_transaction::) - .route("get", trace_get::) - .route("filter", trace_filter::) + .route("block", trace_block::) + .route("transaction", trace_transaction::) + .route("replayBlockTransactions", replay_block_transactions::) + .route("replayTransaction", replay_transaction::) + .route("call", trace_call::) + .route("callMany", trace_call_many::) + .route("rawTransaction", trace_raw_transaction::) + .route("get", trace_get::) + .route("filter", trace_filter::) } diff --git a/crates/rpc/src/web3/mod.rs b/crates/rpc/src/web3/mod.rs index 4e728dae..ddd6e69c 100644 --- a/crates/rpc/src/web3/mod.rs +++ b/crates/rpc/src/web3/mod.rs @@ -2,13 +2,15 @@ use crate::config::StorageRpcCtx; use alloy::primitives::{B256, Bytes, keccak256}; +use signet_cold::ColdStorageBackend; use signet_hot::{HotKv, model::HotKvRead}; use trevm::revm::database::DBErrorMarker; /// Instantiate the `web3` API router. -pub(crate) fn web3() -> ajj::Router> +pub(crate) fn web3() -> ajj::Router> where H: HotKv + Send + Sync + 'static, + B: ColdStorageBackend, ::Error: DBErrorMarker, { ajj::Router::new().route("clientVersion", client_version).route("sha3", sha3) diff --git a/crates/rpc/tests/eth_rpc.rs b/crates/rpc/tests/eth_rpc.rs index c4bff04a..dfe1d881 100644 --- a/crates/rpc/tests/eth_rpc.rs +++ b/crates/rpc/tests/eth_rpc.rs @@ -14,7 +14,7 @@ use alloy::{ use axum::body::Body; use http::Request; use serde_json::{Value, json}; -use signet_cold::{BlockData, ColdStorageHandle, ColdStorageTask, mem::MemColdBackend}; +use signet_cold::{BlockData, ColdStorage, mem::MemColdBackend}; use signet_constants::SignetSystemConstants; use signet_hot::{HotKv, db::UnsafeDbWrite, mem::MemKv}; use signet_rpc::{ChainNotifier, StorageRpcConfig, StorageRpcCtx}; @@ -32,11 +32,11 @@ use trevm::revm::bytecode::Bytecode; /// Everything needed to make RPC calls against the storage-backed router. struct TestHarness { app: axum::Router, - cold: ColdStorageHandle, + cold: ColdStorage, hot: MemKv, chain: ChainNotifier, #[allow(dead_code)] - ctx: StorageRpcCtx, + ctx: StorageRpcCtx, _cancel: CancellationToken, } @@ -45,7 +45,7 @@ impl TestHarness { async fn new(latest: u64) -> Self { let cancel = CancellationToken::new(); let hot = MemKv::new(); - let cold = ColdStorageTask::spawn(MemColdBackend::new(), cancel.clone()); + let cold = ColdStorage::new(MemColdBackend::new(), cancel.clone()); let storage = UnifiedStorage::new(hot.clone(), cold.clone()); let constants = SignetSystemConstants::test(); let chain = ChainNotifier::new(16); @@ -58,7 +58,8 @@ impl TestHarness { None, StorageRpcConfig::default(), ); - let app = signet_rpc::router::().into_axum("/").with_state(ctx.clone()); + let app = + signet_rpc::router::().into_axum("/").with_state(ctx.clone()); Self { app, cold, hot, chain, ctx, _cancel: cancel } } From 6c730e0d8f8d61b0ca1d4f8aefb0038bbeb52562 Mon Sep 17 00:00:00 2001 From: Swanny Date: Tue, 12 May 2026 12:28:38 -0400 Subject: [PATCH 2/2] fix: declare missing B generic in SignetNodeBuilder doctest The `# Examples` block on `SignetNodeBuilder` referenced `UnifiedStorage` after the storage-0.8 migration but only declared `H` on the `example` fn, so `cargo test --doc` failed to compile. Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/node/src/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/node/src/builder.rs b/crates/node/src/builder.rs index ff31a02e..02230cd6 100644 --- a/crates/node/src/builder.rs +++ b/crates/node/src/builder.rs @@ -38,7 +38,7 @@ pub struct NotAStorage; /// /// ```no_run /// # use signet_node::SignetNodeBuilder; -/// # fn example( +/// # fn example( /// # config: signet_node_config::SignetNodeConfig, /// # notifier: impl signet_node_types::HostNotifier, /// # storage: std::sync::Arc>,