Skip to content
Open
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
66 changes: 48 additions & 18 deletions bin/ethlambda/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,24 @@ const ASCII_ART: &str = r#"

#[derive(Debug, clap::Parser)]
#[command(name = "ethlambda", author = "LambdaClass", version = version::CLIENT_VERSION, about = "ethlambda consensus client")]
struct CliOptions {
struct Cli {
#[command(subcommand)]
command: Commands,
}

#[derive(Debug, clap::Subcommand)]
enum Commands {
/// Run the consensus node.
Node(Box<NodeArgs>),
/// Run in Hive test-driver mode (spec-asset suites only).
///
/// Skips the consensus/p2p stack and exposes only the
/// `/lean/v0/test_driver/...` endpoints driven by the hive simulator.
TestDriver(TestDriverArgs),
}

#[derive(Debug, clap::Args)]
struct NodeArgs {
/// Path to the chain genesis config (e.g., config.yaml).
#[arg(long)]
genesis: PathBuf,
Expand Down Expand Up @@ -111,6 +128,16 @@ struct CliOptions {
data_dir: PathBuf,
}

#[derive(Debug, clap::Args)]
struct TestDriverArgs {
#[arg(long, default_value = "127.0.0.1")]
http_address: IpAddr,
#[arg(long, default_value = "5052")]
api_port: u16,
#[arg(long, default_value = "5054")]
metrics_port: u16,
}

#[tokio::main]
async fn main() -> eyre::Result<()> {
let filter = EnvFilter::builder()
Expand All @@ -119,34 +146,37 @@ async fn main() -> eyre::Result<()> {
let subscriber = Registry::default().with(tracing_subscriber::fmt::layer().with_filter(filter));
tracing::subscriber::set_global_default(subscriber).unwrap();

let options = CliOptions::parse();
let cli = Cli::parse();

// Initialize metrics
ethlambda_blockchain::metrics::init();
ethlambda_blockchain::metrics::set_node_info("ethlambda", version::CLIENT_VERSION);
ethlambda_blockchain::metrics::set_node_start_time();

let rpc_config = RpcConfig {
http_address: options.http_address,
api_port: options.api_port,
metrics_port: options.metrics_port,
};

println!("{ASCII_ART}");

info!(version = version::CLIENT_VERSION, "Starting ethlambda");

// Hive lean spec-asset suites boot the client with
// HIVE_LEAN_TEST_DRIVER=1 so it skips the consensus/p2p stack and
// exposes only the `/lean/v0/test_driver/...` endpoints driven by the
// simulator. Detected here before any config / key / genesis loading
// so the driver run doesn't touch --node-key, --custom-network-config-dir,
// or any other consensus prerequisite the hive shim doesn't bother to
// provision.
if ethlambda_rpc::test_driver::test_driver_enabled() {
info!("HIVE_LEAN_TEST_DRIVER detected; booting in test-driver mode");
return run_test_driver(rpc_config).await;
match cli.command {
Commands::TestDriver(args) => {
let rpc_config = RpcConfig {
http_address: args.http_address,
api_port: args.api_port,
metrics_port: args.metrics_port,
};
info!("Booting in test-driver mode");
return run_test_driver(rpc_config).await;
}
Commands::Node(options) => run_node(*options).await,
}
Comment on lines +160 to 171
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The return keyword in the TestDriver arm is redundant β€” the match is already the tail expression of main(), so dropping return makes both arms consistent and more idiomatic Rust.

Suggested change
match cli.command {
Commands::TestDriver(args) => {
let rpc_config = RpcConfig {
http_address: args.http_address,
api_port: args.api_port,
metrics_port: args.metrics_port,
};
info!("Booting in test-driver mode");
return run_test_driver(rpc_config).await;
}
Commands::Node(options) => run_node(*options).await,
}
match cli.command {
Commands::TestDriver(args) => {
let rpc_config = RpcConfig {
http_address: args.http_address,
api_port: args.api_port,
metrics_port: args.metrics_port,
};
info!("Booting in test-driver mode");
run_test_driver(rpc_config).await
}
Commands::Node(options) => run_node(*options).await,
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: bin/ethlambda/src/main.rs
Line: 160-171

Comment:
The `return` keyword in the `TestDriver` arm is redundant β€” the `match` is already the tail expression of `main()`, so dropping `return` makes both arms consistent and more idiomatic Rust.

```suggestion
    match cli.command {
        Commands::TestDriver(args) => {
            let rpc_config = RpcConfig {
                http_address: args.http_address,
                api_port: args.api_port,
                metrics_port: args.metrics_port,
            };
            info!("Booting in test-driver mode");
            run_test_driver(rpc_config).await
        }
        Commands::Node(options) => run_node(*options).await,
    }
```

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

}

async fn run_node(options: NodeArgs) -> eyre::Result<()> {
let rpc_config = RpcConfig {
http_address: options.http_address,
api_port: options.api_port,
metrics_port: options.metrics_port,
};

let node_p2p_key = read_hex_file_bytes(&options.node_key);
let p2p_socket = SocketAddr::new(IpAddr::from([0, 0, 0, 0]), options.gossipsub_port);
Expand Down
35 changes: 2 additions & 33 deletions crates/net/rpc/src/test_driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
//! store-mutating operations themselves are synchronous, so the write lock is
//! never held across `.await`.
//!
//! Activated by setting `HIVE_LEAN_TEST_DRIVER=1` in the container env; see
//! [`test_driver_enabled`] and the boot path in `bin/ethlambda/src/main.rs`.
//! Activated via the `test-driver` subcommand; see the boot path in
//! `bin/ethlambda/src/main.rs`.

use std::sync::Arc;

Expand Down Expand Up @@ -51,27 +51,6 @@ use serde::{Deserialize, Serialize};
use tokio::sync::RwLock;
use tracing::debug;

/// Environment variable that activates the test driver at boot time.
///
/// The hive simulator sets this to `"1"` for each spec-asset fixture run; any
/// of `"1"`, `"true"`, or `"yes"` (case-insensitive) enables the driver.
pub const TEST_DRIVER_ENV: &str = "HIVE_LEAN_TEST_DRIVER";

/// Whether the supplied env-var value should activate the driver.
fn parse_truthy_env_value(value: &str) -> bool {
matches!(
value.trim().to_ascii_lowercase().as_str(),
"1" | "true" | "yes"
)
}

/// Returns true when the binary should boot into test-driver mode.
pub fn test_driver_enabled() -> bool {
std::env::var(TEST_DRIVER_ENV)
.map(|value| parse_truthy_env_value(&value))
.unwrap_or(false)
}

/// Shared, runtime-replaceable Store backing every test-driver handler.
///
/// `fork_choice/init` swaps the contents wholesale; all other handlers either
Expand Down Expand Up @@ -429,16 +408,6 @@ fn snapshot_store(store: &Store) -> DriverSnapshot {
mod tests {
use super::*;

#[test]
fn parse_truthy_env_value_accepts_canonical_truthy_strings() {
for value in ["1", "true", "TRUE", " Yes ", "yes\n"] {
assert!(parse_truthy_env_value(value), "{value:?} should be truthy");
}
for value in ["0", "false", "no", "", " ", "1.0"] {
assert!(!parse_truthy_env_value(value), "{value:?} should be falsy");
}
}

#[test]
fn empty_driver_store_is_usable_as_seed() {
let store = empty_driver_store();
Expand Down