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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ incremental = false
signet-blobber = { version = "0.16.0-rc.7", path = "crates/blobber" }
signet-block-processor = { version = "0.16.0-rc.7", path = "crates/block-processor" }
signet-genesis = { version = "0.16.0-rc.7", path = "crates/genesis" }
signet-host-rpc = { version = "0.16.0-rc.7", path = "crates/host-rpc" }
signet-node = { version = "0.16.0-rc.7", path = "crates/node" }
signet-node-config = { version = "0.16.0-rc.7", path = "crates/node-config" }
signet-node-tests = { version = "0.16.0-rc.7", path = "crates/node-tests" }
Expand Down
20 changes: 20 additions & 0 deletions crates/host-rpc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "signet-host-rpc"
description = "RPC-based implementation of the HostNotifier trait for signet-node."
version.workspace = true
edition.workspace = true
rust-version.workspace = true
authors.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true

[dependencies]
signet-node-types.workspace = true
signet-extract.workspace = true
signet-types.workspace = true

alloy.workspace = true
futures-util.workspace = true
thiserror.workspace = true
tracing.workspace = true
6 changes: 6 additions & 0 deletions crates/host-rpc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# signet-host-rpc

RPC-based implementation of the `HostNotifier` trait for signet-node.

Connects to any Ethereum execution layer client via WebSocket, following
the host chain without embedding a full reth node.
79 changes: 79 additions & 0 deletions crates/host-rpc/src/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use crate::{RpcHostError, RpcHostNotifier};
use alloy::providers::Provider;
use std::collections::VecDeque;

/// Default block buffer capacity.
const DEFAULT_BUFFER_CAPACITY: usize = 64;
/// Default backfill batch size.
const DEFAULT_BACKFILL_BATCH_SIZE: u64 = 32;

/// Builder for [`RpcHostNotifier`].
///
/// # Example
///
/// ```ignore
/// let notifier = RpcHostNotifierBuilder::new(provider)
/// .with_buffer_capacity(128)
/// .with_backfill_batch_size(64)
/// .build()
/// .await?;
/// ```
#[derive(Debug)]
pub struct RpcHostNotifierBuilder<P> {
provider: P,
buffer_capacity: usize,
backfill_batch_size: u64,
genesis_timestamp: u64,
}

impl<P> RpcHostNotifierBuilder<P>
where
P: Provider + Clone,
{
/// Create a new builder with the given provider.
pub const fn new(provider: P) -> Self {
Self {
provider,
buffer_capacity: DEFAULT_BUFFER_CAPACITY,
backfill_batch_size: DEFAULT_BACKFILL_BATCH_SIZE,
genesis_timestamp: 0,
}
}

/// Set the block buffer capacity (default: 64).
pub const fn with_buffer_capacity(mut self, capacity: usize) -> Self {
self.buffer_capacity = capacity;
self
}

/// Set the backfill batch size (default: 32).
pub const fn with_backfill_batch_size(mut self, batch_size: u64) -> Self {
self.backfill_batch_size = batch_size;
self
}

/// Set the genesis timestamp for epoch calculation.
pub const fn with_genesis_timestamp(mut self, timestamp: u64) -> Self {
self.genesis_timestamp = timestamp;
self
}

/// Build the notifier, establishing the `newHeads` WebSocket subscription.
pub async fn build(self) -> Result<RpcHostNotifier<P>, RpcHostError> {
let sub = self.provider.subscribe_blocks().await?;
let header_sub = sub.into_stream();

Ok(RpcHostNotifier {
provider: self.provider,
header_sub,
block_buffer: VecDeque::with_capacity(self.buffer_capacity),
buffer_capacity: self.buffer_capacity,
cached_safe: None,
cached_finalized: None,
last_tag_epoch: None,
backfill_from: None,
backfill_batch_size: self.backfill_batch_size,
genesis_timestamp: self.genesis_timestamp,
})
}
}
26 changes: 26 additions & 0 deletions crates/host-rpc/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use alloy::transports::{RpcError, TransportErrorKind};

/// Errors from the RPC host notifier.
#[derive(Debug, thiserror::Error)]
pub enum RpcHostError {
/// The WebSocket subscription was dropped unexpectedly.
#[error("subscription closed")]
SubscriptionClosed,

/// An RPC call failed.
#[error("rpc error: {0}")]
Rpc(#[from] RpcError<TransportErrorKind>),

/// The RPC node returned no block for the requested number.
#[error("missing block {0}")]
MissingBlock(u64),

/// Reorg deeper than the block buffer.
#[error("reorg depth {depth} exceeds buffer capacity {capacity}")]
ReorgTooDeep {
/// The detected reorg depth.
depth: u64,
/// The configured buffer capacity.
capacity: usize,
},
}
24 changes: 24 additions & 0 deletions crates/host-rpc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#![doc = include_str!("../README.md")]
#![warn(
missing_copy_implementations,
missing_debug_implementations,
missing_docs,
unreachable_pub,
clippy::missing_const_for_fn,
rustdoc::all
)]
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![deny(unused_must_use, rust_2018_idioms)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]

mod builder;
pub use builder::RpcHostNotifierBuilder;

mod error;
pub use error::RpcHostError;

mod notifier;
pub use notifier::RpcHostNotifier;

mod segment;
pub use segment::{RpcBlock, RpcChainSegment};
Loading
Loading