Skip to content

Commit dd662be

Browse files
prestwichclaude
andcommitted
feat: add signet-host-rpc crate with RpcHostNotifier
Add new `signet-host-rpc` crate providing an RPC WebSocket-based HostNotifier implementation. Remove signet-sdk patch overrides now that the new version is published. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 612831d commit dd662be

8 files changed

Lines changed: 635 additions & 0 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ signet-blobber = { version = "0.16.0-rc.7", path = "crates/blobber" }
3838
signet-block-processor = { version = "0.16.0-rc.7", path = "crates/block-processor" }
3939
signet-genesis = { version = "0.16.0-rc.7", path = "crates/genesis" }
4040
signet-host-reth = { version = "0.16.0-rc.7", path = "crates/host-reth" }
41+
signet-host-rpc = { version = "0.16.0-rc.7", path = "crates/host-rpc" }
4142
signet-node = { version = "0.16.0-rc.7", path = "crates/node" }
4243
signet-node-config = { version = "0.16.0-rc.7", path = "crates/node-config" }
4344
signet-node-tests = { version = "0.16.0-rc.7", path = "crates/node-tests" }

crates/host-rpc/Cargo.toml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[package]
2+
name = "signet-host-rpc"
3+
description = "RPC-based implementation of the HostNotifier trait for signet-node."
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-node-types.workspace = true
14+
signet-extract.workspace = true
15+
signet-types.workspace = true
16+
17+
alloy.workspace = true
18+
futures-util.workspace = true
19+
thiserror.workspace = true
20+
tracing.workspace = true

crates/host-rpc/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# signet-host-rpc
2+
3+
RPC-based implementation of the `HostNotifier` trait for signet-node.
4+
5+
Connects to any Ethereum execution layer client via WebSocket, following
6+
the host chain without embedding a full reth node.

crates/host-rpc/src/builder.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use crate::{RpcHostError, RpcHostNotifier};
2+
use alloy::providers::Provider;
3+
use std::collections::VecDeque;
4+
5+
/// Default block buffer capacity.
6+
const DEFAULT_BUFFER_CAPACITY: usize = 64;
7+
/// Default backfill batch size.
8+
const DEFAULT_BACKFILL_BATCH_SIZE: u64 = 32;
9+
10+
/// Builder for [`RpcHostNotifier`].
11+
///
12+
/// # Example
13+
///
14+
/// ```ignore
15+
/// let notifier = RpcHostNotifierBuilder::new(provider)
16+
/// .with_buffer_capacity(128)
17+
/// .with_backfill_batch_size(64)
18+
/// .build()
19+
/// .await?;
20+
/// ```
21+
#[derive(Debug)]
22+
pub struct RpcHostNotifierBuilder<P> {
23+
provider: P,
24+
buffer_capacity: usize,
25+
backfill_batch_size: u64,
26+
genesis_timestamp: u64,
27+
}
28+
29+
impl<P> RpcHostNotifierBuilder<P>
30+
where
31+
P: Provider + Clone,
32+
{
33+
/// Create a new builder with the given provider.
34+
pub const fn new(provider: P) -> Self {
35+
Self {
36+
provider,
37+
buffer_capacity: DEFAULT_BUFFER_CAPACITY,
38+
backfill_batch_size: DEFAULT_BACKFILL_BATCH_SIZE,
39+
genesis_timestamp: 0,
40+
}
41+
}
42+
43+
/// Set the block buffer capacity (default: 64).
44+
pub const fn with_buffer_capacity(mut self, capacity: usize) -> Self {
45+
self.buffer_capacity = capacity;
46+
self
47+
}
48+
49+
/// Set the backfill batch size (default: 32).
50+
pub const fn with_backfill_batch_size(mut self, batch_size: u64) -> Self {
51+
self.backfill_batch_size = batch_size;
52+
self
53+
}
54+
55+
/// Set the genesis timestamp for epoch calculation.
56+
pub const fn with_genesis_timestamp(mut self, timestamp: u64) -> Self {
57+
self.genesis_timestamp = timestamp;
58+
self
59+
}
60+
61+
/// Build the notifier, establishing the `newHeads` WebSocket subscription.
62+
pub async fn build(self) -> Result<RpcHostNotifier<P>, RpcHostError> {
63+
let sub = self.provider.subscribe_blocks().await?;
64+
let header_sub = sub.into_stream();
65+
66+
Ok(RpcHostNotifier {
67+
provider: self.provider,
68+
header_sub,
69+
block_buffer: VecDeque::with_capacity(self.buffer_capacity),
70+
buffer_capacity: self.buffer_capacity,
71+
cached_safe: None,
72+
cached_finalized: None,
73+
last_tag_epoch: None,
74+
backfill_from: None,
75+
backfill_batch_size: self.backfill_batch_size,
76+
genesis_timestamp: self.genesis_timestamp,
77+
})
78+
}
79+
}

crates/host-rpc/src/error.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use alloy::transports::{RpcError, TransportErrorKind};
2+
3+
/// Errors from the RPC host notifier.
4+
#[derive(Debug, thiserror::Error)]
5+
pub enum RpcHostError {
6+
/// The WebSocket subscription was dropped unexpectedly.
7+
#[error("subscription closed")]
8+
SubscriptionClosed,
9+
10+
/// An RPC call failed.
11+
#[error("rpc error: {0}")]
12+
Rpc(#[from] RpcError<TransportErrorKind>),
13+
14+
/// The RPC node returned no block for the requested number.
15+
#[error("missing block {0}")]
16+
MissingBlock(u64),
17+
18+
/// Reorg deeper than the block buffer.
19+
#[error("reorg depth {depth} exceeds buffer capacity {capacity}")]
20+
ReorgTooDeep {
21+
/// The detected reorg depth.
22+
depth: u64,
23+
/// The configured buffer capacity.
24+
capacity: usize,
25+
},
26+
}

crates/host-rpc/src/lib.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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 builder;
15+
pub use builder::RpcHostNotifierBuilder;
16+
17+
mod error;
18+
pub use error::RpcHostError;
19+
20+
mod notifier;
21+
pub use notifier::RpcHostNotifier;
22+
23+
mod segment;
24+
pub use segment::{RpcBlock, RpcChainSegment};

0 commit comments

Comments
 (0)