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..02230cd6 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`]. @@ -38,10 +38,10 @@ 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>, +/// # 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 } }