diff --git a/bin/node/src/commands/node.rs b/bin/node/src/commands/node.rs index f56812b831..57d6dbc89b 100644 --- a/bin/node/src/commands/node.rs +++ b/bin/node/src/commands/node.rs @@ -62,16 +62,6 @@ pub struct NodeCommand { /// (overrides the default rollup configuration from the registry) #[arg(long, visible_alias = "rollup-cfg", env = "KONA_NODE_ROLLUP_CONFIG")] pub l2_config_file: Option, - /// Poll interval (in seconds) for reloading the runtime config. - /// Provides a backup for when config events are not being picked up. - /// Disabled if `0`. - #[arg( - long, - visible_alias = "l1.runtime-config-reload-interval", - default_value = "600", // 10 minutes in seconds - env = "KONA_NODE_L1_RUNTIME_CONFIG_RELOAD_INTERVAL", - )] - pub l1_runtime_config_reload_interval: u64, /// P2P CLI arguments. #[command(flatten)] pub p2p_flags: P2PArgs, @@ -95,7 +85,6 @@ impl Default for NodeCommand { l2_provider_rpc: Url::parse("http://localhost:8545").unwrap(), l2_engine_jwt_secret: None, l2_config_file: None, - l1_runtime_config_reload_interval: 600, node_mode: NodeMode::Validator, p2p_flags: P2PArgs::default(), rpc_flags: RpcArgs::default(), @@ -218,9 +207,6 @@ impl NodeCommand { let p2p_config = self.p2p_flags.config(&cfg, args, Some(self.l1_eth_rpc.clone())).await?; let rpc_config = self.rpc_flags.into(); - let runtime_interval = - std::time::Duration::from_secs(self.l1_runtime_config_reload_interval); - info!( target: "rollup_node", chain_id = cfg.l2_chain_id.id(), @@ -237,7 +223,6 @@ impl NodeCommand { .with_l1_beacon_api_url(self.l1_beacon) .with_l2_provider_rpc_url(self.l2_provider_rpc) .with_l2_engine_rpc_url(self.l2_engine_rpc) - .with_runtime_load_interval(runtime_interval) .with_p2p_config(p2p_config) .with_rpc_config(rpc_config) .with_supervisor_rpc_config(supervisor_rpc_config.unwrap_or_default()) @@ -324,6 +309,12 @@ mod tests { ] } + #[test] + fn test_node_cli_defaults() { + let args = NodeCommand::parse_from(["node"].iter().chain(default_flags().iter()).copied()); + assert_eq!(args.node_mode, NodeMode::Validator); + } + #[test] fn test_node_cli_missing_l1_eth_rpc() { let err = NodeCommand::try_parse_from(["node"]).unwrap_err(); @@ -364,21 +355,4 @@ mod tests { .unwrap_err(); assert!(err.to_string().contains("--l2-provider-rpc")); } - - #[test] - fn test_node_cli_defaults() { - let args = NodeCommand::parse_from(["node"].iter().chain(default_flags().iter()).copied()); - assert_eq!(args.l1_runtime_config_reload_interval, 600); - } - - #[test] - fn test_node_cli_runtime_config_default() { - let args = NodeCommand::parse_from( - ["node", "--l1.runtime-config-reload-interval", "0"] - .iter() - .chain(default_flags().iter()) - .copied(), - ); - assert_eq!(args.l1_runtime_config_reload_interval, 0); - } } diff --git a/crates/node/service/src/actors/mod.rs b/crates/node/service/src/actors/mod.rs index 826a944f65..a99c51713a 100644 --- a/crates/node/service/src/actors/mod.rs +++ b/crates/node/service/src/actors/mod.rs @@ -5,9 +5,6 @@ mod traits; pub use traits::{CancellableContext, NodeActor}; -mod runtime; -pub use runtime::{RuntimeActor, RuntimeContext, RuntimeState}; - mod engine; pub use engine::{ EngineActor, EngineBuilder, EngineContext, EngineError, EngineInboundData, L2Finalizer, diff --git a/crates/node/service/src/actors/runtime.rs b/crates/node/service/src/actors/runtime.rs deleted file mode 100644 index bd6699740e..0000000000 --- a/crates/node/service/src/actors/runtime.rs +++ /dev/null @@ -1,100 +0,0 @@ -//! Runtime Loading Actor - -use async_trait::async_trait; -use kona_engine::EngineClient; -use kona_sources::{RuntimeConfig, RuntimeLoader, RuntimeLoaderError}; -use op_alloy_provider::ext::engine::OpEngineApi; -use std::{sync::Arc, time::Duration}; -use tokio_util::sync::{CancellationToken, WaitForCancellationFuture}; - -use crate::{NodeActor, actors::CancellableContext}; - -/// The communication context used by the runtime actor. -#[derive(Debug)] -pub struct RuntimeContext { - /// Cancels the runtime actor. - pub cancellation: CancellationToken, -} - -impl CancellableContext for RuntimeContext { - fn cancelled(&self) -> WaitForCancellationFuture<'_> { - self.cancellation.cancelled() - } -} - -/// The Runtime Actor. -/// -/// The runtime actor is responsible for loading the runtime config -/// using the [`RuntimeLoader`]. -#[derive(Debug)] -pub struct RuntimeActor { - state: RuntimeState, -} - -/// The state of the runtime actor. -#[derive(Debug, Clone)] -pub struct RuntimeState { - /// The [`RuntimeLoader`]. - pub loader: RuntimeLoader, - /// The interval at which to load the runtime. - pub interval: Duration, - /// The client to send the updated runtime config to the EL engine. - pub client: Arc, -} - -impl RuntimeActor { - /// Constructs a new [`RuntimeActor`] from the given [`RuntimeLoader`]. - pub const fn new(state: RuntimeState) -> ((), Self) { - ((), Self { state }) - } - - fn runtime_config_update(&mut self, config: RuntimeConfig) { - let client = self.state.client.clone(); - tokio::task::spawn(async move { - debug!(target: "engine", config = ?config, "Received runtime config"); - let recommended = config.recommended_protocol_version; - let required = config.required_protocol_version; - match client.signal_superchain_v1(recommended, required).await { - Ok(v) => info!(target: "engine", ?v, "[SUPERCHAIN::SIGNAL]"), - Err(e) => { - // Since the `engine_signalSuperchainV1` endpoint is OPTIONAL, - // a warning is logged instead of an error. - warn!(target: "engine", ?e, "Failed to send superchain signal (OPTIONAL)"); - } - } - }); - } -} - -#[async_trait] -impl NodeActor for RuntimeActor { - type Error = RuntimeLoaderError; - type OutboundData = RuntimeContext; - type InboundData = (); - type Builder = RuntimeState; - - fn build(state: Self::Builder) -> (Self::InboundData, Self) { - Self::new(state) - } - - async fn start( - mut self, - RuntimeContext { cancellation }: Self::OutboundData, - ) -> Result<(), Self::Error> { - let mut interval = tokio::time::interval(self.state.interval); - - loop { - tokio::select! { - _ = cancellation.cancelled() => { - warn!(target: "runtime", "RuntimeActor received shutdown signal."); - return Ok(()); - } - _ = interval.tick() => { - let config = self.state.loader.load_latest().await?; - debug!(target: "runtime", ?config, "Loaded latest runtime config"); - self.runtime_config_update(config); - } - } - } - } -} diff --git a/crates/node/service/src/lib.rs b/crates/node/service/src/lib.rs index 8a530afa44..3d0165a019 100644 --- a/crates/node/service/src/lib.rs +++ b/crates/node/service/src/lib.rs @@ -22,10 +22,9 @@ pub use actors::{ L1WatcherRpcState, L2Finalizer, NetworkActor, NetworkActorError, NetworkBuilder, NetworkBuilderError, NetworkConfig, NetworkContext, NetworkDriver, NetworkDriverError, NetworkHandler, NetworkInboundData, NodeActor, PipelineBuilder, RpcActor, RpcActorError, - RpcContext, RuntimeActor, RuntimeContext, RuntimeState, SequencerActor, SequencerActorError, - SequencerBuilder, SequencerConfig, SequencerContext, SequencerInboundData, SupervisorActor, - SupervisorActorContext, SupervisorActorError, SupervisorExt, SupervisorInboundData, - SupervisorRpcServerExt, + RpcContext, SequencerActor, SequencerActorError, SequencerBuilder, SequencerConfig, + SequencerContext, SequencerInboundData, SupervisorActor, SupervisorActorContext, + SupervisorActorError, SupervisorExt, SupervisorInboundData, SupervisorRpcServerExt, }; mod metrics; diff --git a/crates/node/service/src/service/core.rs b/crates/node/service/src/service/core.rs index 1b5c0b8b2a..9bd4e2cbc2 100644 --- a/crates/node/service/src/service/core.rs +++ b/crates/node/service/src/service/core.rs @@ -1,7 +1,7 @@ //! The core [`RollupNodeService`] trait use crate::{ AttributesBuilderConfig, DerivationContext, EngineContext, L1WatcherRpcContext, NetworkContext, - NodeActor, NodeMode, RpcContext, RuntimeContext, SequencerContext, SequencerInboundData, + NodeActor, NodeMode, RpcContext, SequencerContext, SequencerInboundData, SupervisorActorContext, SupervisorExt, actors::{ DerivationInboundChannels, EngineInboundData, L1WatcherRpcInboundChannels, @@ -77,9 +77,6 @@ pub trait RollupNodeService { InboundData = SupervisorInboundData, >; - /// The type of runtime actor to use for the service. - type RuntimeActor: NodeActor; - /// The type of attributes builder to use for the sequener. type AttributesBuilder: AttributesBuilder + Send + Sync + 'static; @@ -106,9 +103,6 @@ pub trait RollupNodeService { /// Creates a network builder for the node. fn network_builder(&self) -> ::Builder; - /// Returns a runtime builder for the node. - fn runtime_builder(&self) -> Option<::Builder>; - /// Returns an engine builder for the node. fn engine_builder(&self) -> ::Builder; @@ -148,9 +142,6 @@ pub trait RollupNodeService { // // ) - // Create the runtime actor. - let (_, runtime) = self.runtime_builder().map(Self::RuntimeActor::build).unzip(); - // Create the engine actor. let ( EngineInboundData { @@ -187,10 +178,6 @@ pub trait RollupNodeService { spawn_and_wait!( cancellation, actors = [ - runtime.map(|r| ( - r, - RuntimeContext { cancellation: cancellation.clone() } - )), rpc.map(|r| ( r, RpcContext { diff --git a/crates/node/service/src/service/standard/builder.rs b/crates/node/service/src/service/standard/builder.rs index e788b3f006..c3147effba 100644 --- a/crates/node/service/src/service/standard/builder.rs +++ b/crates/node/service/src/service/standard/builder.rs @@ -1,9 +1,6 @@ //! Contains the builder for the [`RollupNode`]. -use crate::{ - EngineBuilder, InteropMode, NetworkConfig, NodeMode, RollupNode, SequencerConfig, - actors::RuntimeState, -}; +use crate::{EngineBuilder, InteropMode, NetworkConfig, NodeMode, RollupNode, SequencerConfig}; use alloy_primitives::Bytes; use alloy_provider::RootProvider; use alloy_rpc_client::RpcClient; @@ -43,8 +40,6 @@ pub struct RollupNodeBuilder { rpc_config: Option, /// An RPC Configuration for the supervisor rpc. supervisor_rpc_config: SupervisorRpcConfig, - /// An interval to load the runtime config. - runtime_load_interval: Option, /// The [`SequencerConfig`]. sequencer_config: Option, /// The mode to run the node in. @@ -109,11 +104,6 @@ impl RollupNodeBuilder { Self { rpc_config, ..self } } - /// Sets the runtime load interval on the [`RollupNodeBuilder`]. - pub fn with_runtime_load_interval(self, interval: std::time::Duration) -> Self { - Self { runtime_load_interval: Some(interval), ..self } - } - /// Appends the [`SequencerConfig`] to the builder. pub fn with_sequencer_config(self, sequencer_config: SequencerConfig) -> Self { Self { sequencer_config: Some(sequencer_config), ..self } @@ -156,18 +146,12 @@ impl RollupNodeBuilder { let engine_builder = EngineBuilder { config: Arc::clone(&rollup_config), l2_rpc_url, - l1_rpc_url: l1_rpc_url.clone(), + l1_rpc_url, engine_url: self.l2_engine_rpc_url.expect("missing l2 engine rpc url"), jwt_secret, mode: self.mode, }; - let runtime_builder = self.runtime_load_interval.map(|load_interval| RuntimeState { - loader: kona_sources::RuntimeLoader::new(l1_rpc_url, rollup_config.clone()), - client: engine_builder.client(), - interval: load_interval, - }); - let p2p_config = self.p2p_config.expect("P2P config not set"); let sequencer_config = self.sequencer_config.unwrap_or_default(); @@ -184,7 +168,6 @@ impl RollupNodeBuilder { l2_provider, engine_builder, rpc_builder: self.rpc_config, - runtime_builder, p2p_config, sequencer_config, // By default, the supervisor rpc config is disabled. diff --git a/crates/node/service/src/service/standard/node.rs b/crates/node/service/src/service/standard/node.rs index 32e9afd8eb..847571028e 100644 --- a/crates/node/service/src/service/standard/node.rs +++ b/crates/node/service/src/service/standard/node.rs @@ -2,9 +2,8 @@ use crate::{ DerivationActor, DerivationBuilder, EngineActor, EngineBuilder, InteropMode, L1WatcherRpc, L1WatcherRpcState, NetworkActor, NetworkBuilder, NetworkConfig, NodeMode, RollupNodeBuilder, - RollupNodeService, RpcActor, RuntimeActor, SequencerConfig, SupervisorActor, - SupervisorRpcServerExt, - actors::{RuntimeState, SequencerActor, SequencerBuilder}, + RollupNodeService, RpcActor, SequencerConfig, SupervisorActor, SupervisorRpcServerExt, + actors::{SequencerActor, SequencerBuilder}, }; use alloy_provider::RootProvider; use async_trait::async_trait; @@ -38,8 +37,6 @@ pub struct RollupNode { pub(crate) rpc_builder: Option, /// The P2P [`NetworkConfig`] for the node. pub(crate) p2p_config: NetworkConfig, - /// The [`RuntimeState`] for the runtime loading service. - pub(crate) runtime_builder: Option, /// The [`SequencerConfig`] for the node. pub(crate) sequencer_config: SequencerConfig, /// The supervisor rpc server config. @@ -66,7 +63,6 @@ impl RollupNodeService for RollupNode { type SupervisorExt = SupervisorRpcServerExt; type SupervisorActor = SupervisorActor; - type RuntimeActor = RuntimeActor; type RpcActor = RpcActor; type EngineActor = EngineActor; type NetworkActor = NetworkActor; @@ -97,10 +93,6 @@ impl RollupNodeService for RollupNode { Some(SupervisorRpcServerExt::new(handle, events_tx, control_rx)) } - fn runtime_builder(&self) -> Option { - self.runtime_builder.clone() - } - fn engine_builder(&self) -> EngineBuilder { self.engine_builder.clone() } diff --git a/docs/docs/pages/node/design/runtime.mdx b/docs/docs/pages/node/design/runtime.mdx deleted file mode 100644 index 8a881ee28e..0000000000 --- a/docs/docs/pages/node/design/runtime.mdx +++ /dev/null @@ -1,138 +0,0 @@ -# Runtime - -The Kona Node Runtime system provides dynamic configuration management and protocol version signaling for rollup nodes. It maintains up-to-date runtime parameters by monitoring L1 contracts and automatically propagating changes to the execution engine. - -:::info -[Core Purpose] -The runtime system ensures your node stays synchronized with network-wide protocol upgrades and configuration changes without requiring manual intervention or restarts. -::: - -## Architecture Overview - -The runtime system consists of three primary components that work together to maintain node configuration: - -### RuntimeConfig - -The core configuration structure containing essential runtime parameters: - -- **Unsafe Block Signer Address**: The P2P block signer address used for unsafe block validation -- **Required Protocol Version**: The minimum protocol version nodes must support -- **Recommended Protocol Version**: The preferred protocol version for optimal operation - -### RuntimeLoader - -Responsible for fetching runtime configuration from L1 smart contracts. The loader: - -- Queries the L1 System Config contract for the unsafe block signer address -- Retrieves protocol version information from the Protocol Versions contract -- Implements intelligent caching to minimize L1 calls and improve performance -- Handles configuration validation and error recovery - -:::warning -[L1 Dependency] -The runtime loader requires a reliable L1 RPC connection. Network issues or L1 node downtime can affect runtime configuration updates. -::: - -### RuntimeActor - -An autonomous actor that orchestrates the runtime system lifecycle: - -- Periodically loads the latest runtime configuration using configurable intervals -- Signals protocol version updates to the execution engine via the `engine_signalSuperchainV1` RPC method -- Manages the update cycle and handles shutdown signals gracefully -- Provides logging and metrics for monitoring runtime system health - -## Configuration Management - -The runtime system automatically discovers configuration changes by monitoring specific storage slots in L1 contracts: - -**System Config Contract**: Stores the unsafe block signer address at a deterministic storage slot. This address is used to validate blocks received through the P2P network before they're finalized on L1. - -**Protocol Versions Contract**: Contains both required and recommended protocol versions. The required version represents the minimum version needed for consensus participation, while the recommended version indicates the optimal version for new features and improvements. - -:::tip -[Caching Strategy] -The runtime loader implements an LRU cache that maps block information to runtime configurations, significantly reducing L1 query overhead during normal operation. -::: - -## Integration Patterns - -### Node Service Integration - -The runtime actor integrates seamlessly with the broader node service architecture: - -1. **Initialization**: The runtime actor starts alongside other node components during service startup -2. **Configuration Updates**: When new runtime configuration is loaded, it's automatically propagated to relevant subsystems -3. **Engine Signaling**: Protocol version updates are sent to the execution engine to ensure compatibility with network changes - -### Error Handling - -The runtime system includes comprehensive error handling for various failure scenarios: - -- **Network Errors**: Automatic retry logic for transient L1 connection issues -- **Contract Call Failures**: Graceful handling of failed storage queries with fallback behavior -- **Protocol Version Decoding**: Validation and error reporting for malformed protocol version data - -:::info -[Optional Engine Endpoint] -The `engine_signalSuperchainV1` endpoint is optional in the Engine API specification. If your execution client doesn't support this method, the runtime system will log warnings but continue operating normally. -::: - -## Monitoring and Observability - -The runtime system provides comprehensive monitoring capabilities: - -### Logging - -Runtime operations are logged with structured information including: -- Configuration loading events with timing details -- Protocol version changes and their values -- Error conditions with context for troubleshooting - -### Metrics - -When the metrics feature is enabled, the runtime system exports: -- Current runtime configuration values as gauge metrics -- Loading frequency and success rates -- Error counts by type for alerting - -## Best Practices - -### Configuration Intervals - -Choose runtime loading intervals based on your operational requirements: - -- **High-frequency trading**: Shorter intervals (30-60 seconds) for rapid protocol version awareness -- **Standard operation**: Medium intervals (5-10 minutes) for balanced responsiveness and efficiency -- **Resource-constrained environments**: Longer intervals (15-30 minutes) to minimize L1 query costs - -### Monitoring Setup - -Implement monitoring for runtime system health: - -- Alert on repeated configuration loading failures -- Monitor L1 RPC endpoint availability and performance -- Track protocol version changes for upgrade planning - -:::warning -[Protocol Version Compatibility] -Ensure your node can support the required protocol version. Running with an incompatible version may result in consensus failures or network disconnection. -::: - -## Troubleshooting - -### Common Issues - -**Configuration Loading Failures**: Often caused by L1 RPC issues or contract call failures. Check L1 endpoint health and network connectivity. - -**Missing Protocol Versions**: If the protocol versions address is not set in the rollup configuration, the system will use default values and log warnings. - -**Engine Signaling Errors**: The `engine_signalSuperchainV1` method is optional. If your execution client doesn't implement it, you'll see warnings but the system will continue functioning. - -### Debug Information - -Enable debug logging to get detailed information about: -- Runtime configuration loading timings -- Cache hit/miss ratios -- L1 contract interaction details -- Protocol version parsing and validation diff --git a/docs/sidebar.ts b/docs/sidebar.ts index 3cd8413bf2..6d9828c14a 100644 --- a/docs/sidebar.ts +++ b/docs/sidebar.ts @@ -109,8 +109,7 @@ export const sidebar: SidebarItem[] = [ { text: "Derivation", link: "/node/design/derivation" }, { text: "Engine", link: "/node/design/engine" }, { text: "P2P", link: "/node/design/p2p" }, - { text: "Sequencer", link: "/node/design/sequencer" }, - { text: "Runtime", link: "/node/design/runtime" } + { text: "Sequencer", link: "/node/design/sequencer" } ] }, {