Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ signet-tx-cache = "0.18"
signet-types = "0.18"
signet-zenith = "0.18"
signet-journal = "0.18"
signet-journal-chain = "0.1"
signet-storage = "0.9"
signet-cold = "0.9"
signet-hot = "0.9"
Expand Down Expand Up @@ -97,6 +98,7 @@ tokio-stream = "0.1"
tokio-util = "0.7"

# Misc
bytes = "1.11"
eyre = "0.6.12"
futures-util = "0.3.31"
hex = { package = "const-hex", version = "1.10", default-features = false, features = [
Expand All @@ -117,3 +119,5 @@ url = "2.5.4"
# Test Utils
tempfile = "3.17.0"

[patch.crates-io]
signet-journal-chain = { git = "https://github.com/init4tech/journal-service", branch = "fraser/eng-2013/server-tests" }
1 change: 1 addition & 0 deletions crates/node-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ repository.workspace = true
signet-blobber.workspace = true
signet-cold.workspace = true
signet-hot.workspace = true
signet-journal-chain.workspace = true
signet-rpc.workspace = true
signet-storage.workspace = true
signet-types.workspace = true
Expand Down
15 changes: 14 additions & 1 deletion crates/node-config/src/core.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::StorageConfig;
use crate::{JournalConfig, StorageConfig};
use alloy::genesis::Genesis;
use init4_bin_base::utils::{calc::SlotCalculator, from_env::FromEnv};
use signet_blobber::BlobFetcherConfig;
Expand Down Expand Up @@ -28,6 +28,11 @@ pub struct SignetNodeConfig {
)]
forward_url: Option<Cow<'static, str>>,

/// Configuration settings for the embedded journal chain.
#[from_env(infallible)]
#[serde(default)]
journal: JournalConfig,

/// Configuration loaded from genesis file, or known genesis.
genesis: GenesisSpec,

Expand Down Expand Up @@ -57,13 +62,15 @@ impl SignetNodeConfig {
block_extractor: BlobFetcherConfig,
storage: StorageConfig,
forward_url: Option<Cow<'static, str>>,
journal: JournalConfig,
genesis: GenesisSpec,
slot_calculator: SlotCalculator,
) -> Self {
Self {
block_extractor,
storage,
forward_url,
journal,
genesis,
slot_calculator,
backfill_max_blocks: None,
Expand Down Expand Up @@ -127,6 +134,11 @@ impl SignetNodeConfig {
// Default to 10,000 if not explicitly configured
Some(self.backfill_max_blocks.unwrap_or(10_000))
}

/// Get the journal chain configuration.
pub const fn journal(&self) -> &JournalConfig {
&self.journal
}
}

#[cfg(test)]
Expand All @@ -140,6 +152,7 @@ mod defaults {
block_extractor: BlobFetcherConfig::new(Cow::Borrowed("")),
storage: StorageConfig::new(Cow::Borrowed(""), Cow::Borrowed("")),
forward_url: None,
journal: JournalConfig::default(),
genesis: GenesisSpec::Known(KnownChains::Test),
slot_calculator: SlotCalculator::new(0, 0, 12),
backfill_max_blocks: None,
Expand Down
113 changes: 113 additions & 0 deletions crates/node-config/src/journal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
use core::num::NonZeroU64;
use init4_bin_base::utils::from_env::FromEnv;
use signet_journal_chain::SAFETY_MARGIN;
use tracing::warn;

/// Default maximum total byte size of the journal ring buffer (64 MiB).
pub const DEFAULT_RING_BUFFER_MAX_BYTES: u64 = 64 * 1024 * 1024;

/// Default maximum number of journals held in the ring buffer. Must be at
/// least [`SAFETY_MARGIN`]; smaller values are clamped up by the chain.
pub const DEFAULT_RING_BUFFER_MAX_COUNT: u64 = 200;

const _: () = assert!(
DEFAULT_RING_BUFFER_MAX_COUNT >= SAFETY_MARGIN,
"DEFAULT_RING_BUFFER_MAX_COUNT must be at least signet_journal_chain::SAFETY_MARGIN"
);

/// Default broadcast-subscriber lag tolerance (in journals) before the
/// chain disconnects a slow subscriber.
pub const DEFAULT_MAX_SUBSCRIBER_LAG: u64 = 100;

/// Configuration settings for the embedded journal chain.
///
/// All fields are optional. When unset, [`JournalConfig`] returns the
/// constants above via its accessors. Configurable via environment variables
/// (`SIGNET_JOURNAL_*`) or via serde for file-based config.
#[derive(Debug, Clone, Copy, Default, serde::Deserialize, FromEnv)]
#[serde(rename_all = "camelCase", default)]
pub struct JournalConfig {
/// Maximum total byte size of the journal ring buffer.
#[from_env(
var = "SIGNET_JOURNAL_RING_BUFFER_MAX_BYTES",
desc = "Journal ring buffer byte limit [default: 67108864 (64 MiB)]",
optional
)]
ring_buffer_max_bytes: Option<u64>,

/// Maximum number of journals in the ring buffer. Values below the
/// chain's `SAFETY_MARGIN` are clamped up.
#[from_env(
var = "SIGNET_JOURNAL_RING_BUFFER_MAX_COUNT",
desc = "Journal ring buffer count limit [default: 200]",
optional
)]
ring_buffer_max_count: Option<u64>,

/// Maximum number of journals a `/journal` WebSocket subscriber may lag
/// behind the broadcast tip before the chain closes the connection with
/// a `Lagged` (4003) close frame. Zero is normalized to the default
/// because the chain requires a non-zero value.
#[from_env(
var = "SIGNET_JOURNAL_MAX_SUBSCRIBER_LAG",
desc = "Journal subscriber lag tolerance [default: 100, 0 means use default]",
optional
)]
max_subscriber_lag: Option<u64>,
}

impl JournalConfig {
/// Maximum total byte size of the ring buffer, falling back to
/// [`DEFAULT_RING_BUFFER_MAX_BYTES`].
pub const fn ring_buffer_max_bytes(&self) -> u64 {
match self.ring_buffer_max_bytes {
Some(bytes) => bytes,
None => DEFAULT_RING_BUFFER_MAX_BYTES,
}
}

/// Maximum ring buffer entry count, falling back to
/// [`DEFAULT_RING_BUFFER_MAX_COUNT`].
pub const fn ring_buffer_max_count(&self) -> u64 {
match self.ring_buffer_max_count {
Some(count) => count,
None => DEFAULT_RING_BUFFER_MAX_COUNT,
}
}

/// Subscriber lag tolerance, falling back to
/// [`DEFAULT_MAX_SUBSCRIBER_LAG`]. Zero is normalized to the default
/// because the chain requires a non-zero value.
pub const fn max_subscriber_lag(&self) -> NonZeroU64 {
let value = match self.max_subscriber_lag {
Some(0) | None => DEFAULT_MAX_SUBSCRIBER_LAG,
Some(lag) => lag,
};
NonZeroU64::new(value).expect("DEFAULT_MAX_SUBSCRIBER_LAG is non-zero")
}

/// Emit a warning for any field that is explicitly set to a value the
/// journal chain will silently normalize. Covers a zero
/// `max_subscriber_lag` (which the chain rejects, so the default is
/// substituted) and a `ring_buffer_max_count` below [`SAFETY_MARGIN`]
/// (which the chain clamps up). Intended to be called once at startup.
pub fn warn_on_misconfiguration(&self) {
if self.max_subscriber_lag == Some(0) {
warn!(
default = DEFAULT_MAX_SUBSCRIBER_LAG,
"SIGNET_JOURNAL_MAX_SUBSCRIBER_LAG=0 is not a valid lag tolerance; \
falling back to the default"
);
}
if let Some(configured) = self.ring_buffer_max_count
&& configured < SAFETY_MARGIN
{
warn!(
configured,
safety_margin = SAFETY_MARGIN,
"SIGNET_JOURNAL_RING_BUFFER_MAX_COUNT is below the journal chain's safety \
margin and will be clamped up"
);
}
}
}
6 changes: 6 additions & 0 deletions crates/node-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ pub use core::SignetNodeConfig;
// NB: RPC config merging (previously `merge_rpc_configs`) is now the
// responsibility of the host adapter crate (e.g. `signet-host-reth`).

mod journal;
pub use journal::{
DEFAULT_MAX_SUBSCRIBER_LAG, DEFAULT_RING_BUFFER_MAX_BYTES, DEFAULT_RING_BUFFER_MAX_COUNT,
JournalConfig,
};

mod storage;
pub use storage::StorageConfig;

Expand Down
24 changes: 11 additions & 13 deletions crates/node-config/src/test_utils.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
use crate::{SignetNodeConfig, StorageConfig};
use crate::{JournalConfig, SignetNodeConfig, StorageConfig};
use init4_bin_base::utils::calc::SlotCalculator;
use signet_blobber::BlobFetcherConfig;
use signet_genesis::GenesisSpec;
use signet_types::constants::KnownChains;
use std::borrow::Cow;

/// Make a test config
pub const fn test_config() -> SignetNodeConfig {
TEST_CONFIG
/// Make a test config.
pub fn test_config() -> SignetNodeConfig {
SignetNodeConfig::new(
BlobFetcherConfig::new(Cow::Borrowed("")),
StorageConfig::new(Cow::Borrowed("NOP"), Cow::Borrowed("NOP")),
None,
JournalConfig::default(),
GenesisSpec::Known(KnownChains::Test),
SlotCalculator::new(0, 0, 12),
)
}

/// Test SignetNodeConfig
const TEST_CONFIG: SignetNodeConfig = SignetNodeConfig::new(
BlobFetcherConfig::new(Cow::Borrowed("")),
StorageConfig::new(Cow::Borrowed("NOP"), Cow::Borrowed("NOP")),
None,
GenesisSpec::Known(KnownChains::Test),
SlotCalculator::new(0, 0, 12),
);
6 changes: 6 additions & 0 deletions crates/node-tests/tests/multiple-blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ async fn test_write_account_histories_with_empty_block() {

#[serial]
#[tokio::test]
#[ignore = "ENG-2017: needs producer-side journal-hash persistence to seed \
previous_journal_hash on revert; without it the chain rejects the \
first post-revert journal with PreviousHashMismatch."]
async fn test_write_account_histories_with_reorg_and_empty_blocks() {
run_test(|ctx| async move {
let ctx = setup_accounts_history(ctx).await;
Expand Down Expand Up @@ -412,6 +415,9 @@ async fn test_historical_state_provider_with_empty_blocks() {

#[serial]
#[tokio::test]
#[ignore = "ENG-2017: needs producer-side journal-hash persistence to seed \
previous_journal_hash on revert; without it the chain rejects the \
first post-revert journal with PreviousHashMismatch."]
async fn test_historical_state_provider_with_reorg() {
run_test(|ctx| async move {
let ctx = setup_accounts_history(ctx).await;
Expand Down
24 changes: 24 additions & 0 deletions crates/node-tests/tests/reorg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ async fn process_increment(ctx: &SignetTestContext, contract_address: Address) -

#[serial]
#[tokio::test]
#[ignore = "ENG-2017: needs producer-side journal-hash persistence to seed \
previous_journal_hash on revert; without it the chain rejects the \
first post-revert journal with PreviousHashMismatch."]
async fn test_block_tags_reorg() {
run_test(|ctx| async move {
// Process two blocks via enter events.
Expand Down Expand Up @@ -98,6 +101,9 @@ async fn test_block_tags_reorg() {

#[serial]
#[tokio::test]
#[ignore = "ENG-2017: needs producer-side journal-hash persistence to seed \
previous_journal_hash on revert; without it the chain rejects the \
first post-revert journal with PreviousHashMismatch."]
async fn test_block_filter_reorg() {
rpc_test(|ctx, contract| async move {
// Install a block filter (starts after block 1, where contract was deployed).
Expand Down Expand Up @@ -142,6 +148,9 @@ async fn test_block_filter_reorg() {

#[serial]
#[tokio::test]
#[ignore = "ENG-2017: needs producer-side journal-hash persistence to seed \
previous_journal_hash on revert; without it the chain rejects the \
first post-revert journal with PreviousHashMismatch."]
async fn test_log_filter_reorg() {
rpc_test(|ctx, contract| async move {
// Install a log filter on the Counter address.
Expand Down Expand Up @@ -192,6 +201,9 @@ async fn test_log_filter_reorg() {

#[serial]
#[tokio::test]
#[ignore = "ENG-2017: needs producer-side journal-hash persistence to seed \
previous_journal_hash on revert; without it the chain rejects the \
first post-revert journal with PreviousHashMismatch."]
async fn test_block_subscription_reorg() {
rpc_test(|ctx, contract| async move {
let mut sub = ctx.alloy_provider.subscribe_blocks().await.unwrap();
Expand Down Expand Up @@ -224,6 +236,9 @@ async fn test_block_subscription_reorg() {

#[serial]
#[tokio::test]
#[ignore = "ENG-2017: needs producer-side journal-hash persistence to seed \
previous_journal_hash on revert; without it the chain rejects the \
first post-revert journal with PreviousHashMismatch."]
async fn test_log_subscription_reorg() {
rpc_test(|ctx, contract| async move {
let mut sub = ctx
Expand Down Expand Up @@ -390,6 +405,9 @@ async fn test_no_regression_filters_and_subscriptions() {

#[serial]
#[tokio::test]
#[ignore = "ENG-2017: needs producer-side journal-hash persistence to seed \
previous_journal_hash on revert; without it the chain rejects the \
first post-revert journal with PreviousHashMismatch."]
async fn test_multi_block_reorg_log_filter() {
rpc_test(|ctx, contract| async move {
let addr = *contract.address();
Expand Down Expand Up @@ -445,6 +463,9 @@ async fn test_multi_block_reorg_log_filter() {

#[serial]
#[tokio::test]
#[ignore = "ENG-2017: needs producer-side journal-hash persistence to seed \
previous_journal_hash on revert; without it the chain rejects the \
first post-revert journal with PreviousHashMismatch."]
async fn test_multi_block_reorg_log_subscription() {
rpc_test(|ctx, contract| async move {
let addr = *contract.address();
Expand Down Expand Up @@ -494,6 +515,9 @@ async fn test_multi_block_reorg_log_subscription() {

#[serial]
#[tokio::test]
#[ignore = "ENG-2017: needs producer-side journal-hash persistence to seed \
previous_journal_hash on revert; without it the chain rejects the \
first post-revert journal with PreviousHashMismatch."]
async fn test_multiple_reorgs_between_polls() {
rpc_test(|ctx, contract| async move {
let addr = *contract.address();
Expand Down
3 changes: 3 additions & 0 deletions crates/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ signet-evm.workspace = true
signet-extract.workspace = true
signet-genesis.workspace = true
signet-hot.workspace = true
signet-journal.workspace = true
signet-journal-chain = { workspace = true, features = ["serve", "signet-extract"] }
signet-node-config.workspace = true
signet-node-types.workspace = true
signet-rpc.workspace = true
Expand All @@ -27,6 +29,7 @@ signet-types.workspace = true
alloy.workspace = true
trevm.workspace = true

bytes.workspace = true
eyre.workspace = true
metrics.workspace = true
reqwest.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ notifications, and manages the lifecycle of the rest of the node components.

This library contains the following:

- `SignetNode` - The main node struct, which manages the lifecycle of the node.
- `SignetNode` - The main node struct, which manages the lifecycle of the node.
Loading
Loading