Skip to content

Commit e0727ec

Browse files
rswansonclaudeprestwich
authored
chore: bump signet-storage family to 0.8 (workspace 0.18.0) (#143)
* 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<H> -> UnifiedStorage<H, B> (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<B> (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<Header> 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) <noreply@anthropic.com> * fix: declare missing B generic in SignetNodeBuilder doctest The `# Examples` block on `SignetNodeBuilder` referenced `UnifiedStorage<H, B>` 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) <noreply@anthropic.com> * refactor: drop B: ColdStorageBackend generic, use concrete NodeColdBackend alias Addresses review feedback that the per-endpoint `<B: ColdStorageBackend>` propagation is code smell rooted in `ColdStorageBackend` not being dyn-compatible. Replace the generic with a concrete `NodeColdBackend` type alias defined in `signet-rpc`: - `test-utils` feature → `MemColdBackend` (in-memory, for tests) - `postgres`/`sqlite` features → `EitherCold` (runtime MDBX-or-SQL) - default → `MdbxColdBackend` This sets up the codebase so the followup boxing-futures upstream work can flip the alias to `Box<dyn ColdStorageBackend>` in one place rather than rewriting every endpoint signature. - `StorageRpcCtx<H, B>` → `StorageRpcCtx<H>` - `SignetNode<N, H, B, AliasOracle>` → `SignetNode<N, H, AliasOracle>` - `SignetNodeBuilder::with_storage<H, B>` → `<H>` - `signet_rpc::router::<H, B>()` → `<H>()` - `signet-node-config` drops its own `NodeColdBackend` alias and the `signet-cold-mdbx as _` workaround; re-exported from `signet-rpc` via the new dep - `StorageConfig::build_storage` cfg-gated to `not(feature = "test_utils")` since the production builder path is meaningless when the alias is swapped to `MemColdBackend` - `signet-rpc/tests/eth_rpc.rs` marked `required-features = ["test-utils"]` - `node-tests` now enables `signet-rpc/test-utils` so its in-memory storage matches the type the builder expects Also addresses review item 3: comment on `block-processor` clarifying that the storage API is signet-agnostic, so the header type at that seam is plain `Sealed<Header>` rather than `SignetHeaderV1`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor: drop cold backend generic, use ErasedBackend defaults Migrates to the object-safe DynColdStorageBackend trait + ErasedBackend newtype from signet-cold. ColdStorage and UnifiedStorage now default to the erased backend, so the B generic disappears from SignetNode, SignetNodeBuilder, and StorageRpcCtx. NodeColdBackend is gone: the cfg-selected concrete alias is no longer needed since erasure happens at construction time via UnifiedStorage::spawn_erased / ColdStorage::new_erased. StorageConfig inlines the connector logic for the same reason. Pins the signet-storage family to the prestwich/cold-dyn-backend branch via [patch.crates-io] until the changes ship on crates.io. ps: tell swanny i love him 💛 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: move build_storage doctest onto method, disambiguate connect() The doctest example was on the StorageConfig struct, but referenced build_storage which is cfg-gated to not(feature = "test_utils"). Under --all-features the example failed to compile. Moving it onto the method itself means rustdoc only emits the example when the method exists. Also disambiguate the two connect() calls in build_storage: both HotConnect and ColdConnect impl connect() on MdbxConnector, which broke the build under no-default-features. * chore: bump signet-storage to 0.9, signet sdk to 0.18, bin-base to 0.21 signet-storage 0.9 was published with the object-safe DynColdStorageBackend trait and erased defaults, so the prestwich/cold-dyn-backend patch can be dropped. 0.9 transitively pulls signet sdk 0.18, and the FromEnv impl for SqlConnector now lives in init4-bin-base 0.21. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: James <james@prestwi.ch>
1 parent 91ea251 commit e0727ec

16 files changed

Lines changed: 128 additions & 85 deletions

File tree

Cargo.toml

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ members = ["crates/*"]
33
resolver = "2"
44

55
[workspace.package]
6-
version = "0.17.2"
6+
version = "0.18.0"
77
edition = "2024"
88
rust-version = "1.88"
99
authors = ["init4"]
@@ -34,34 +34,34 @@ debug = false
3434
incremental = false
3535

3636
[workspace.dependencies]
37-
signet-blobber = { version = "0.17.2", path = "crates/blobber" }
38-
signet-block-processor = { version = "0.17.2", path = "crates/block-processor" }
39-
signet-genesis = { version = "0.17.2", path = "crates/genesis" }
40-
signet-host-reth = { version = "0.17.2", path = "crates/host-reth" }
41-
signet-host-rpc = { version = "0.17.2", path = "crates/host-rpc" }
42-
signet-node = { version = "0.17.2", path = "crates/node" }
43-
signet-node-config = { version = "0.17.2", path = "crates/node-config" }
44-
signet-node-tests = { version = "0.17.2", path = "crates/node-tests" }
45-
signet-node-types = { version = "0.17.2", path = "crates/node-types" }
46-
signet-rpc = { version = "0.17.2", path = "crates/rpc" }
47-
48-
init4-bin-base = { version = "0.19.1", features = ["alloy"] }
49-
50-
signet-bundle = "0.16.0"
51-
signet-constants = "0.16.0"
52-
signet-evm = "0.16.0"
53-
signet-extract = "0.16.0"
54-
signet-test-utils = "0.16.0"
55-
signet-tx-cache = "0.16.0"
56-
signet-types = "0.16.0"
57-
signet-zenith = "0.16.0"
58-
signet-journal = "0.16.0"
59-
signet-storage = "0.7"
60-
signet-cold = "0.7"
61-
signet-hot = "0.7"
62-
signet-hot-mdbx = "0.7"
63-
signet-cold-mdbx = "0.7"
64-
signet-storage-types = "0.7"
37+
signet-blobber = { version = "0.18.0", path = "crates/blobber" }
38+
signet-block-processor = { version = "0.18.0", path = "crates/block-processor" }
39+
signet-genesis = { version = "0.18.0", path = "crates/genesis" }
40+
signet-host-reth = { version = "0.18.0", path = "crates/host-reth" }
41+
signet-host-rpc = { version = "0.18.0", path = "crates/host-rpc" }
42+
signet-node = { version = "0.18.0", path = "crates/node" }
43+
signet-node-config = { version = "0.18.0", path = "crates/node-config" }
44+
signet-node-tests = { version = "0.18.0", path = "crates/node-tests" }
45+
signet-node-types = { version = "0.18.0", path = "crates/node-types" }
46+
signet-rpc = { version = "0.18.0", path = "crates/rpc" }
47+
48+
init4-bin-base = { version = "0.21.0", features = ["alloy"] }
49+
50+
signet-bundle = "0.18"
51+
signet-constants = "0.18"
52+
signet-evm = "0.18"
53+
signet-extract = "0.18"
54+
signet-test-utils = "0.18"
55+
signet-tx-cache = "0.18"
56+
signet-types = "0.18"
57+
signet-zenith = "0.18"
58+
signet-journal = "0.18"
59+
signet-storage = "0.9"
60+
signet-cold = "0.9"
61+
signet-hot = "0.9"
62+
signet-hot-mdbx = "0.9"
63+
signet-cold-mdbx = "0.9"
64+
signet-storage-types = "0.9"
6565

6666
# ajj
6767
ajj = "0.7.0"
@@ -116,3 +116,4 @@ url = "2.5.4"
116116

117117
# Test Utils
118118
tempfile = "3.17.0"
119+

crates/block-processor/src/v1/processor.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use signet_hot::{
1515
model::{HotKv, HotKvRead, RevmRead},
1616
};
1717
use signet_storage_types::{DbSignetEvent, DbZenithHeader, ExecutedBlock, ExecutedBlockBuilder};
18+
use signet_types::primitives::SignetHeaderV1;
1819
use std::collections::VecDeque;
1920
use tracing::{error, instrument};
2021
use trevm::revm::{
@@ -195,7 +196,7 @@ where
195196
block_extracts,
196197
to_alias,
197198
txns,
198-
parent_header,
199+
SignetHeaderV1::new_unchecked(parent_header.unseal()),
199200
self.constants.clone(),
200201
);
201202

@@ -254,8 +255,11 @@ where
254255

255256
let zenith_header = block_extracts.ru_header().map(DbZenithHeader::from);
256257

258+
// The storage API is signet-agnostic and stores headers as a plain
259+
// `Sealed<Header>`; unseal the `SignetHeaderV1` wrapper before
260+
// handing it off.
257261
ExecutedBlockBuilder::new()
258-
.header(header)
262+
.header(header.into_inner())
259263
.bundle(bundle)
260264
.transactions(transactions)
261265
.receipts(receipts)

crates/host-rpc/src/notifier.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ use alloy::{
33
consensus::{BlockHeader, transaction::Recovered},
44
eips::{BlockId, BlockNumberOrTag},
55
network::BlockResponse,
6-
primitives::{B256, Sealed},
6+
primitives::B256,
77
providers::Provider,
88
pubsub::SubscriptionStream,
99
rpc::types::Header as RpcHeader,
1010
};
1111
use futures_util::{StreamExt, TryStreamExt, stream};
1212
use signet_node_types::{HostNotification, HostNotificationKind, HostNotifier, RevertRange};
13-
use signet_types::primitives::{RecoveredBlock, SealedBlock, TransactionSigned};
13+
use signet_types::primitives::{RecoveredBlock, SealedBlock, SignetHeaderV1, TransactionSigned};
1414
use std::{collections::VecDeque, sync::Arc, time::Instant};
1515
use tracing::{debug, info, warn};
1616

@@ -189,7 +189,6 @@ where
189189
rpc_block: alloy::rpc::types::Block,
190190
rpc_receipts: Option<Vec<alloy::rpc::types::TransactionReceipt>>,
191191
) -> RpcBlock {
192-
let hash = rpc_block.header.hash;
193192
let block = rpc_block
194193
.map_transactions(|tx| {
195194
let recovered = tx.inner;
@@ -198,7 +197,9 @@ where
198197
Recovered::new_unchecked(tx, signer)
199198
})
200199
.into_consensus();
201-
let sealed_header = Sealed::new_unchecked(block.header, hash);
200+
// SignetHeaderV1 reseals the header; the recomputed hash matches the
201+
// RPC-supplied hash for any well-formed provider response.
202+
let sealed_header = SignetHeaderV1::new_unchecked(block.header);
202203
let block: RecoveredBlock = SealedBlock::new(sealed_header, block.body.transactions);
203204
let receipts = rpc_receipts
204205
.unwrap_or_default()

crates/node-config/Cargo.toml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ repository.workspace = true
1111

1212
[dependencies]
1313
signet-blobber.workspace = true
14+
signet-cold.workspace = true
15+
signet-hot.workspace = true
16+
signet-rpc.workspace = true
1417
signet-storage.workspace = true
1518
signet-types.workspace = true
1619

@@ -27,6 +30,6 @@ signet-genesis.workspace = true
2730

2831

2932
[features]
30-
test_utils = []
31-
postgres = ["signet-storage/postgres", "init4-bin-base/cold-sql"]
32-
sqlite = ["signet-storage/sqlite", "init4-bin-base/cold-sql"]
33+
test_utils = ["signet-rpc/test-utils"]
34+
postgres = ["signet-storage/postgres", "signet-rpc/postgres", "init4-bin-base/cold-sql"]
35+
sqlite = ["signet-storage/sqlite", "signet-rpc/sqlite", "init4-bin-base/cold-sql"]

crates/node-config/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@
1111
#![deny(unused_must_use, rust_2018_idioms)]
1212
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
1313

14+
// `signet_storage`, `signet_cold`, and `signet_hot` are only referenced
15+
// from `build_storage`, which is gated to non-test_utils. Silence
16+
// `unused_crate_dependencies` on test_utils builds where those paths are
17+
// excluded.
18+
use signet_cold as _;
19+
use signet_hot as _;
20+
use signet_storage as _;
21+
1422
mod core;
1523
pub use core::SignetNodeConfig;
1624

crates/node-config/src/storage.rs

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
use init4_bin_base::utils::from_env::FromEnv;
2+
#[cfg(not(feature = "test_utils"))]
3+
use signet_cold::ColdConnect;
4+
#[cfg(not(feature = "test_utils"))]
5+
use signet_hot::HotConnect;
26
#[cfg(any(feature = "postgres", feature = "sqlite"))]
37
use signet_storage::SqlConnector;
4-
use signet_storage::{DatabaseEnv, MdbxConnector, UnifiedStorage, builder::StorageBuilder};
8+
#[cfg(not(feature = "test_utils"))]
9+
use signet_storage::{DatabaseEnv, MdbxConnector, UnifiedStorage};
510
use std::borrow::Cow;
611
#[cfg(any(feature = "postgres", feature = "sqlite"))]
712
use std::time::Duration;
13+
#[cfg(not(feature = "test_utils"))]
814
use tokio_util::sync::CancellationToken;
915

16+
// `signet-rpc` is no longer referenced from this crate. Keep the dep
17+
// satisfied so `unused_crate_dependencies` does not fire.
18+
#[cfg(feature = "test_utils")]
19+
use eyre as _;
20+
use signet_rpc as _;
21+
#[cfg(feature = "test_utils")]
22+
use tokio_util as _;
23+
1024
/// Configuration for signet unified storage.
1125
///
1226
/// Reads hot and cold storage configuration from environment variables.
@@ -22,23 +36,9 @@ use tokio_util::sync::CancellationToken;
2236
/// Exactly one of `SIGNET_COLD_PATH` or `SIGNET_COLD_SQL_URL` must be set.
2337
///
2438
/// When using SQL cold storage, connection pool tuning is configured via
25-
/// [`SqlConnector`]'s own environment variables (e.g.
39+
/// the `SqlConnector`'s own environment variables (e.g.
2640
/// `SIGNET_COLD_SQL_MAX_CONNECTIONS`). See the `cold-sql` feature of
2741
/// `init4-bin-base` for the full list.
28-
///
29-
/// [`SqlConnector`]: signet_storage::SqlConnector
30-
///
31-
/// # Example
32-
///
33-
/// ```rust,no_run
34-
/// # use signet_node_config::StorageConfig;
35-
/// # use tokio_util::sync::CancellationToken;
36-
/// # async fn example(cfg: &StorageConfig) -> eyre::Result<()> {
37-
/// let cancel = CancellationToken::new();
38-
/// let storage = cfg.build_storage(cancel).await?;
39-
/// # Ok(())
40-
/// # }
41-
/// ```
4242
#[derive(Debug, Clone, FromEnv)]
4343
pub struct StorageConfig {
4444
/// Path to the hot MDBX database.
@@ -160,11 +160,27 @@ impl StorageConfig {
160160
/// background task, and returns a [`UnifiedStorage`] ready for use.
161161
///
162162
/// Exactly one of `cold_path` or `cold_sql` must be configured.
163+
///
164+
/// Not available when the `test_utils` feature is enabled — tests
165+
/// construct an in-memory `UnifiedStorage` directly instead.
166+
///
167+
/// # Example
168+
///
169+
/// ```rust,no_run
170+
/// # use signet_node_config::StorageConfig;
171+
/// # use tokio_util::sync::CancellationToken;
172+
/// # async fn example(cfg: &StorageConfig) -> eyre::Result<()> {
173+
/// let cancel = CancellationToken::new();
174+
/// let storage = cfg.build_storage(cancel).await?;
175+
/// # Ok(())
176+
/// # }
177+
/// ```
178+
#[cfg(not(feature = "test_utils"))]
163179
pub async fn build_storage(
164180
&self,
165181
cancel: CancellationToken,
166182
) -> eyre::Result<UnifiedStorage<DatabaseEnv>> {
167-
let hot = MdbxConnector::new(self.hot_path.as_ref());
183+
let hot = HotConnect::connect(&MdbxConnector::new(self.hot_path.as_ref()))?;
168184
let has_mdbx = !self.cold_path.is_empty();
169185

170186
#[cfg(any(feature = "postgres", feature = "sqlite"))]
@@ -173,22 +189,17 @@ impl StorageConfig {
173189
let has_sql = std::env::var("SIGNET_COLD_SQL_URL").is_ok_and(|v| !v.is_empty());
174190

175191
match (has_mdbx, has_sql) {
176-
(true, false) => Ok(StorageBuilder::new()
177-
.hot(hot)
178-
.cold(MdbxConnector::new(self.cold_path.as_ref()))
179-
.cancel_token(cancel)
180-
.build()
181-
.await?),
192+
(true, false) => {
193+
let cold =
194+
ColdConnect::connect(&MdbxConnector::new(self.cold_path.as_ref())).await?;
195+
Ok(UnifiedStorage::spawn_erased(hot, cold, cancel))
196+
}
182197
#[cfg(any(feature = "postgres", feature = "sqlite"))]
183198
(false, true) => {
184199
let connector =
185200
self.cold_sql.clone().expect("cold_sql must be Some when has_sql is true");
186-
Ok(StorageBuilder::new()
187-
.hot(hot)
188-
.cold(connector)
189-
.cancel_token(cancel)
190-
.build()
191-
.await?)
201+
let cold = connector.connect().await?;
202+
Ok(UnifiedStorage::spawn_erased(hot, cold, cancel))
192203
}
193204
#[cfg(not(any(feature = "postgres", feature = "sqlite")))]
194205
(false, true) => {

crates/node-tests/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ signet-blobber = { workspace = true, features = ["test-utils"] }
1515
signet-node.workspace = true
1616
signet-node-config = { workspace = true, features = ["test_utils"] }
1717
signet-node-types.workspace = true
18-
signet-rpc.workspace = true
18+
signet-rpc = { workspace = true, features = ["test-utils"] }
1919

2020
signet-cold = { workspace = true, features = ["in-memory"] }
2121
signet-constants.workspace = true

crates/node-tests/src/context.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use alloy::{
1515
rpc::types::eth::{TransactionReceipt, TransactionRequest},
1616
};
1717
use signet_blobber::MemoryBlobSource;
18-
use signet_cold::{ColdStorageReadHandle, mem::MemColdBackend};
18+
use signet_cold::{ColdStorage, mem::MemColdBackend};
1919
use signet_hot::{
2020
db::{HotDbRead, UnsafeDbWrite},
2121
mem::MemKv,
@@ -186,8 +186,11 @@ impl SignetTestContext {
186186
}
187187

188188
// Create UnifiedStorage
189-
let storage =
190-
Arc::new(UnifiedStorage::spawn(hot, MemColdBackend::new(), cancel_token.clone()));
189+
let storage = Arc::new(UnifiedStorage::spawn_erased(
190+
hot,
191+
MemColdBackend::new(),
192+
cancel_token.clone(),
193+
));
191194

192195
let alias_oracle: Arc<Mutex<HashSet<Address>>> = Arc::new(Mutex::new(HashSet::default()));
193196

@@ -288,7 +291,7 @@ impl SignetTestContext {
288291
}
289292

290293
/// Get a cold storage read handle.
291-
pub fn cold(&self) -> ColdStorageReadHandle {
294+
pub fn cold(&self) -> ColdStorage {
292295
self.storage.cold_reader()
293296
}
294297

crates/node-tests/src/utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use alloy::{
55
signers::{SignerSync, local::PrivateKeySigner},
66
uint,
77
};
8-
use signet_types::primitives::{RecoveredBlock, Transaction, TransactionSigned};
8+
use signet_types::primitives::{RecoveredBlock, SignetHeaderV1, Transaction, TransactionSigned};
99
use signet_zenith::Zenith;
1010
use std::{panic, sync::Once};
1111
use tracing_subscriber::EnvFilter;
@@ -21,7 +21,7 @@ pub fn fake_block(number: u64) -> RecoveredBlock {
2121
excess_blob_gas: Some(0),
2222
..Default::default()
2323
};
24-
RecoveredBlock::blank_with_header(header)
24+
RecoveredBlock::blank_with_header(SignetHeaderV1::new_unchecked(header))
2525
}
2626

2727
/// Sign a transaction with a wallet.

crates/node-tests/tests/db.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ async fn test_genesis() {
2828
writer.commit().unwrap();
2929
}
3030

31-
let storage = Arc::new(UnifiedStorage::spawn(hot, MemColdBackend::new(), cancel_token.clone()));
31+
let storage =
32+
Arc::new(UnifiedStorage::spawn_erased(hot, MemColdBackend::new(), cancel_token.clone()));
3233

3334
// Create a dummy notifier (not used, we only check genesis loading)
3435
let (_sender, receiver) = mpsc::unbounded_channel();

0 commit comments

Comments
 (0)