Skip to content

Commit 4697dff

Browse files
committed
feat: add HostNotifier trait and decouple node from ExExContext
1 parent ccfa991 commit 4697dff

17 files changed

Lines changed: 479 additions & 370 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ signet-genesis = { version = "0.16.0-rc.7", path = "crates/genesis" }
4040
signet-node = { version = "0.16.0-rc.7", path = "crates/node" }
4141
signet-node-config = { version = "0.16.0-rc.7", path = "crates/node-config" }
4242
signet-node-tests = { version = "0.16.0-rc.7", path = "crates/node-tests" }
43+
signet-node-types = { version = "0.16.0-rc.7", path = "crates/node-types" }
4344
signet-rpc = { version = "0.16.0-rc.7", path = "crates/rpc" }
4445

4546
init4-bin-base = { version = "0.18.0-rc.8", features = ["alloy"] }

crates/node-config/Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ init4-bin-base.workspace = true
1818

1919
reth.workspace = true
2020
reth-chainspec.workspace = true
21-
reth-exex.workspace = true
22-
reth-node-api.workspace = true
2321
alloy.workspace = true
2422

2523
eyre.workspace = true

crates/node-config/src/core.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use crate::StorageConfig;
22
use alloy::genesis::Genesis;
33
use init4_bin_base::utils::{calc::SlotCalculator, from_env::FromEnv};
4+
use reth::primitives::NodePrimitives;
45
use reth::providers::providers::StaticFileProvider;
56
use reth_chainspec::ChainSpec;
6-
use reth_node_api::NodePrimitives;
77
use signet_blobber::BlobFetcherConfig;
88
use signet_genesis::GenesisSpec;
99
use signet_types::constants::{ConfigError, SignetSystemConstants};

crates/node-config/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
mod core;
1515
pub use core::{SIGNET_NODE_DEFAULT_HTTP_PORT, SignetNodeConfig};
1616

17-
mod rpc;
17+
// NB: RPC config merging (previously `merge_rpc_configs`) is now the
18+
// responsibility of the host adapter crate (e.g. `signet-host-reth`).
1819

1920
mod storage;
2021
pub use storage::StorageConfig;

crates/node-config/src/rpc.rs

Lines changed: 0 additions & 29 deletions
This file was deleted.

crates/node-types/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "signet-node-types"
3+
description = "Trait abstractions for the signet node's host chain interface."
4+
version.workspace = true
5+
edition.workspace = true
6+
rust-version.workspace = true
7+
authors.workspace = true
8+
license.workspace = true
9+
homepage.workspace = true
10+
repository.workspace = true
11+
12+
[dependencies]
13+
signet-extract.workspace = true

crates/node-types/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# signet-node-types
2+
3+
Trait abstractions for the signet node's host chain interface.

crates/node-types/src/lib.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#![doc = include_str!("../README.md")]
2+
#![warn(
3+
missing_copy_implementations,
4+
missing_debug_implementations,
5+
missing_docs,
6+
unreachable_pub,
7+
clippy::missing_const_for_fn,
8+
rustdoc::all
9+
)]
10+
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
11+
#![deny(unused_must_use, rust_2018_idioms)]
12+
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
13+
14+
mod notification;
15+
pub use notification::{HostNotification, HostNotificationKind};
16+
17+
mod notifier;
18+
pub use notifier::HostNotifier;
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use signet_extract::Extractable;
2+
use std::sync::Arc;
3+
4+
/// A notification from the host chain, bundling a chain event with
5+
/// point-in-time block tag data. The safe/finalized block numbers are
6+
/// intentionally snapshotted at notification creation time rather than
7+
/// fetched live, because rollup safe/finalized tags are only updated
8+
/// after block processing completes.
9+
///
10+
/// # Examples
11+
///
12+
/// ```
13+
/// # use std::sync::Arc;
14+
/// # use signet_node_types::{HostNotification, HostNotificationKind};
15+
/// # fn example<C: signet_extract::Extractable>(chain: Arc<C>) {
16+
/// let notification = HostNotification {
17+
/// kind: HostNotificationKind::ChainCommitted { new: chain },
18+
/// safe_block_number: Some(100),
19+
/// finalized_block_number: Some(90),
20+
/// };
21+
///
22+
/// // Access the committed chain via the shortcut method.
23+
/// assert!(notification.committed_chain().is_some());
24+
/// assert!(notification.reverted_chain().is_none());
25+
/// # }
26+
/// ```
27+
#[derive(Debug, Clone)]
28+
pub struct HostNotification<C> {
29+
/// The chain event (commit, revert, or reorg).
30+
pub kind: HostNotificationKind<C>,
31+
/// The host chain "safe" block number at the time of this notification.
32+
pub safe_block_number: Option<u64>,
33+
/// The host chain "finalized" block number at the time of this
34+
/// notification.
35+
pub finalized_block_number: Option<u64>,
36+
}
37+
38+
impl<C: Extractable> HostNotification<C> {
39+
/// Returns the committed chain, if any. Shortcut for
40+
/// `self.kind.committed_chain()`.
41+
pub const fn committed_chain(&self) -> Option<&Arc<C>> {
42+
self.kind.committed_chain()
43+
}
44+
45+
/// Returns the reverted chain, if any. Shortcut for
46+
/// `self.kind.reverted_chain()`.
47+
pub const fn reverted_chain(&self) -> Option<&Arc<C>> {
48+
self.kind.reverted_chain()
49+
}
50+
}
51+
52+
/// The kind of chain event in a [`HostNotification`].
53+
///
54+
/// # Examples
55+
///
56+
/// ```
57+
/// # use std::sync::Arc;
58+
/// # use signet_node_types::HostNotificationKind;
59+
/// # fn example<C: signet_extract::Extractable>(old: Arc<C>, new: Arc<C>) {
60+
/// let kind = HostNotificationKind::ChainReorged {
61+
/// old: old.clone(),
62+
/// new: new.clone(),
63+
/// };
64+
/// # }
65+
/// ```
66+
#[derive(Debug, Clone)]
67+
pub enum HostNotificationKind<C> {
68+
/// A new chain segment was committed.
69+
ChainCommitted {
70+
/// The newly committed chain segment.
71+
new: Arc<C>,
72+
},
73+
/// A chain segment was reverted.
74+
ChainReverted {
75+
/// The reverted chain segment.
76+
old: Arc<C>,
77+
},
78+
/// A chain reorg occurred: one segment was reverted and replaced by
79+
/// another.
80+
ChainReorged {
81+
/// The reverted chain segment.
82+
old: Arc<C>,
83+
/// The newly committed chain segment.
84+
new: Arc<C>,
85+
},
86+
}
87+
88+
impl<C: Extractable> HostNotificationKind<C> {
89+
/// Returns the committed chain, if any.
90+
///
91+
/// Returns `Some` for [`ChainCommitted`] and [`ChainReorged`], `None`
92+
/// for [`ChainReverted`].
93+
///
94+
/// [`ChainCommitted`]: HostNotificationKind::ChainCommitted
95+
/// [`ChainReorged`]: HostNotificationKind::ChainReorged
96+
/// [`ChainReverted`]: HostNotificationKind::ChainReverted
97+
pub const fn committed_chain(&self) -> Option<&Arc<C>> {
98+
match self {
99+
Self::ChainCommitted { new } | Self::ChainReorged { new, .. } => Some(new),
100+
Self::ChainReverted { .. } => None,
101+
}
102+
}
103+
104+
/// Returns the reverted chain, if any.
105+
///
106+
/// Returns `Some` for [`ChainReverted`] and [`ChainReorged`], `None`
107+
/// for [`ChainCommitted`].
108+
///
109+
/// [`ChainReverted`]: HostNotificationKind::ChainReverted
110+
/// [`ChainReorged`]: HostNotificationKind::ChainReorged
111+
/// [`ChainCommitted`]: HostNotificationKind::ChainCommitted
112+
pub const fn reverted_chain(&self) -> Option<&Arc<C>> {
113+
match self {
114+
Self::ChainReverted { old } | Self::ChainReorged { old, .. } => Some(old),
115+
Self::ChainCommitted { .. } => None,
116+
}
117+
}
118+
}

crates/node-types/src/notifier.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use crate::HostNotification;
2+
use core::future::Future;
3+
use signet_extract::Extractable;
4+
5+
/// Abstraction over a host chain notification source.
6+
///
7+
/// Drives the signet node's main loop: yielding chain events, controlling
8+
/// backfill, and sending feedback. All block data comes from notifications;
9+
/// the backend handles hash resolution internally.
10+
///
11+
/// # Implementors
12+
///
13+
/// - `signet-host-reth`: wraps reth's `ExExContext`
14+
///
15+
/// # Implementing
16+
///
17+
/// Implementations must uphold the following contract:
18+
///
19+
/// 1. **`set_head`** — called once at startup before the first
20+
/// [`next_notification`]. The backend must resolve the block number to a
21+
/// hash (falling back to genesis if the number is not yet available) and
22+
/// begin delivering notifications from that point.
23+
/// 2. **`next_notification`** — must yield notifications in host-chain order.
24+
/// Returning `None` signals a clean shutdown.
25+
/// 3. **`set_backfill_thresholds`** — may be called at any time. Passing
26+
/// `None` should restore the backend's default batch size.
27+
/// 4. **`send_finished_height`** — may be called after processing each
28+
/// notification batch. The backend resolves the block number to a hash
29+
/// internally. Sending a height that has already been acknowledged is a
30+
/// no-op.
31+
///
32+
/// [`next_notification`]: HostNotifier::next_notification
33+
pub trait HostNotifier {
34+
/// A chain segment — contiguous blocks with receipts.
35+
type Chain: Extractable;
36+
37+
/// The error type for fallible operations.
38+
type Error: core::error::Error + Send + Sync + 'static;
39+
40+
/// Yield the next notification. `None` signals host shutdown.
41+
fn next_notification(
42+
&mut self,
43+
) -> impl Future<Output = Option<Result<HostNotification<Self::Chain>, Self::Error>>> + Send;
44+
45+
/// Set the head position, requesting backfill from this block number.
46+
/// The backend resolves the block number to a block hash internally.
47+
fn set_head(&mut self, block_number: u64);
48+
49+
/// Configure backfill batch size limits. `None` means use the backend's
50+
/// default.
51+
fn set_backfill_thresholds(&mut self, max_blocks: Option<u64>);
52+
53+
/// Signal that processing is complete up to this host block number.
54+
/// The backend resolves the block number to a block hash internally.
55+
fn send_finished_height(&self, block_number: u64) -> Result<(), Self::Error>;
56+
}

0 commit comments

Comments
 (0)