Skip to content

Commit 400d15f

Browse files
feat: persistence meter, consensus tuning, TLS fix, spammer/arch docs (#5)
## Summary - Add `rustls-tls-native-roots` to snapshot download reqwest features (fixes TLS on platforms without bundled certs) - Document spammer backpressure and fire-and-forget operating modes in spammer + quake READMEs - Refresh `docs/ARCHITECTURE.md` with current crate paths, precompile addresses, remove stale denylist references - Add ADR 0002-0004 entries to `docs/adr/README.md` - Add testnet/alpha software disclaimer to root `README.md` - Add persistence latency tracking module to eth-engine - Extend consensus ready handler with validator set management - Fix follow endpoint URL handling - Add new CLI config options for consensus tuning - Update quake localdev scenarios and compose templates - Update node docs and dependency versions --------- Co-authored-by: atiwari-circle <ayush.tiwari@circle.com>
1 parent eeee562 commit 400d15f

31 files changed

Lines changed: 1673 additions & 301 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ QUAKE_MANIFEST ?= crates/quake/scenarios/localdev.toml
77
NUM_VALIDATORS := $(shell grep -c '^\[nodes\.validator' $(QUAKE_MANIFEST) 2>/dev/null || echo 5)
88
QUAKE := cargo run --bin quake --
99
LOAD_PREDEFINED_ARC_REMOTE_SIGNER_KEYS := true
10+
DEFAULT_BRANCH ?= $(shell git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@')
11+
ifeq ($(DEFAULT_BRANCH),)
12+
DEFAULT_BRANCH = master
13+
endif
1014

1115
##@ Help
1216
.PHONY: help
@@ -51,7 +55,7 @@ buf-format: ## Format protobuf files using buf
5155

5256
.PHONY: buf-breaking
5357
buf-breaking: ## Check for breaking changes in protobuf files
54-
buf breaking --against '.git#branch=master'
58+
buf breaking --against '.git#branch=$(DEFAULT_BRANCH)'
5559

5660
.PHONY: lint
5761
lint: fmt buf-format build-contract ## Run formatting and linting

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Arc Node
22

3-
> The Economic OS for the internet
3+
> [!IMPORTANT]
4+
> Arc is currently in testnet, and this is alpha software currently undergoing audits.
5+
6+
The Economic OS for the internet
47

58
[![Website](https://img.shields.io/badge/Website-arc.network-blue)](https://www.arc.network/)
69

crates/eth-engine/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ mocks = ["dep:mockall"]
1414

1515
# alloy crates
1616
alloy-consensus = { workspace = true }
17+
alloy-eips = { workspace = true }
1718
alloy-genesis = { workspace = true }
1819
alloy-primitives = { workspace = true }
1920
alloy-rpc-types = { workspace = true }
@@ -29,7 +30,7 @@ backon = { workspace = true }
2930
ethereum_serde_utils = "0.8.0"
3031
eyre = { workspace = true }
3132
hex = { workspace = true }
32-
jsonrpsee = { workspace = true }
33+
jsonrpsee = { workspace = true, features = ["ws-client"] }
3334
jsonrpsee-types = { workspace = true }
3435
jsonwebtoken = { workspace = true }
3536
malachitebft-core-types = { workspace = true }

crates/eth-engine/src/engine.rs

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ use crate::ipc::{engine_ipc::EngineIPC, ethereum_ipc::EthereumIPC};
3939
use crate::json_structures::ExecutionBlock;
4040
use crate::rpc::{engine_rpc::EngineRpc, ethereum_rpc::EthereumRPC};
4141

42+
/// A subscription-capable transport endpoint for the execution layer.
43+
///
44+
/// Exposed so that callers (e.g. startup replay, RPC sync) can establish
45+
/// auxiliary subscriptions without Engine needing to know about those concerns.
46+
#[derive(Clone, Debug)]
47+
pub enum SubscriptionEndpoint {
48+
Ipc { socket_path: String },
49+
Ws { url: Url },
50+
}
51+
4252
#[cfg_attr(any(test, feature = "mocks"), mockall::automock)]
4353
#[async_trait]
4454
pub trait EngineAPI: Send + Sync {
@@ -105,7 +115,10 @@ impl Engine {
105115
pub async fn new_ipc(execution_socket: &str, eth_socket: &str) -> eyre::Result<Self> {
106116
let api = Box::new(EngineIPC::new(execution_socket).await?);
107117
let eth = Box::new(EthereumIPC::new(eth_socket).await?);
108-
Ok(Self::new(api, eth))
118+
let sub_endpoint = SubscriptionEndpoint::Ipc {
119+
socket_path: eth_socket.to_owned(),
120+
};
121+
Ok(Self(Arc::new(Inner::new(api, eth, Some(sub_endpoint)))))
109122
}
110123

111124
/// Create a new engine using RPC.
@@ -115,6 +128,7 @@ impl Engine {
115128
pub async fn new_rpc(
116129
execution_endpoint: Url,
117130
eth_endpoint: Url,
131+
ws_endpoint: Option<Url>,
118132
execution_jwt: &str,
119133
) -> eyre::Result<Self> {
120134
let api = Box::new(EngineRpc::new(
@@ -126,12 +140,13 @@ impl Engine {
126140
// Probe the RPC server to confirm it is reachable.
127141
eth.check_connectivity().await?;
128142

129-
Ok(Self::new(api, eth))
143+
let sub_endpoint = ws_endpoint.map(|url| SubscriptionEndpoint::Ws { url });
144+
Ok(Self(Arc::new(Inner::new(api, eth, sub_endpoint))))
130145
}
131146

132147
/// Create a new engine with custom API implementations.
133148
pub fn new(api: Box<dyn EngineAPI>, eth: Box<dyn EthereumAPI>) -> Self {
134-
Self(Arc::new(Inner::new(api, eth)))
149+
Self(Arc::new(Inner::new(api, eth, None)))
135150
}
136151

137152
/// Set the function that determines whether Osaka is active at a given timestamp.
@@ -209,6 +224,13 @@ impl Engine {
209224
.expect("Clock is before UNIX epoch!")
210225
.as_secs()
211226
}
227+
228+
/// Returns the subscription-capable endpoint for the execution layer,
229+
/// if one was configured. `None` for test/mock engines or RPC without
230+
/// `--execution-ws-endpoint`.
231+
pub fn subscription_endpoint(&self) -> Option<&SubscriptionEndpoint> {
232+
self.0.subscription_endpoint.as_ref()
233+
}
212234
}
213235

214236
impl Deref for Engine {
@@ -224,18 +246,24 @@ pub struct Inner {
224246
pub api: Box<dyn EngineAPI>,
225247
/// Client for Ethereum API.
226248
pub eth: Box<dyn EthereumAPI>,
249+
/// Subscription-capable endpoint for the execution layer.
250+
subscription_endpoint: Option<SubscriptionEndpoint>,
227251
/// Optional function to check if Osaka is active at a given timestamp.
228252
/// Set after construction via [`Engine::set_is_osaka_active`].
229253
/// When `None`, defaults to `false` (use V4).
230254
is_osaka_active: OnceLock<IsOsakaActiveFn>,
231255
}
232256

233257
impl Inner {
234-
/// Create a new engine with custom API implementations.
235-
fn new(api: Box<dyn EngineAPI>, eth: Box<dyn EthereumAPI>) -> Self {
258+
fn new(
259+
api: Box<dyn EngineAPI>,
260+
eth: Box<dyn EthereumAPI>,
261+
subscription_endpoint: Option<SubscriptionEndpoint>,
262+
) -> Self {
236263
Self {
237264
api,
238265
eth,
266+
subscription_endpoint,
239267
is_osaka_active: OnceLock::new(),
240268
}
241269
}

crates/eth-engine/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub mod capabilities;
1818
pub mod engine;
1919
pub mod ipc;
2020
pub mod json_structures;
21+
pub mod persistence_meter;
2122
pub mod retry;
2223
pub mod rpc;
2324

@@ -29,4 +30,5 @@ pub use constants::INITIAL_RETRY_DELAY;
2930
#[cfg(any(test, feature = "mocks"))]
3031
pub mod mocks {
3132
pub use crate::engine::{MockEngineAPI, MockEthereumAPI};
33+
pub use crate::persistence_meter::MockPersistenceMeter;
3234
}

0 commit comments

Comments
 (0)