From 2e3a81cdd39f226507a0bfc2595323dee18974d4 Mon Sep 17 00:00:00 2001 From: Marios Christou Date: Fri, 3 Oct 2025 16:03:04 +0300 Subject: [PATCH] Change names from ZombieNet to Zombienet and switch from Command to Process --- crates/common/src/types/identifiers.rs | 6 +- crates/config/src/lib.rs | 18 ++- crates/core/src/lib.rs | 34 +++--- crates/node/Cargo.toml | 1 - crates/node/src/zombie.rs | 156 ++++++++----------------- 5 files changed, 76 insertions(+), 139 deletions(-) diff --git a/crates/common/src/types/identifiers.rs b/crates/common/src/types/identifiers.rs index 121e4e4..2dd8563 100644 --- a/crates/common/src/types/identifiers.rs +++ b/crates/common/src/types/identifiers.rs @@ -40,9 +40,9 @@ pub enum PlatformIdentifier { /// The revive dev node with the REVM backend with the solc compiler. ReviveDevNodeRevmSolc, /// A zombienet based Substrate/Polkadot node with the PolkaVM backend with the resolc compiler. - ZombieNetPolkavmResolc, + ZombienetPolkavmResolc, /// A zombienet based Substrate/Polkadot node with the REVM backend with the solc compiler. - ZombieNetRevmSolc, + ZombienetRevmSolc, } /// An enum of the platform identifiers of all of the platforms supported by this framework. @@ -100,7 +100,7 @@ pub enum NodeIdentifier { /// The revive dev node implementation. ReviveDevNode, /// A zombienet spawned nodes - ZombieNet, + Zombienet, } /// An enum representing the identifiers of the supported VMs. diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 736b4df..4bbfc73 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -88,8 +88,8 @@ impl AsRef for Context { } } -impl AsRef for Context { - fn as_ref(&self) -> &ZombieNetConfiguration { +impl AsRef for Context { + fn as_ref(&self) -> &ZombienetConfiguration { match self { Self::ExecuteTests(context) => context.as_ref().as_ref(), Self::ExportJsonSchema => unreachable!(), @@ -206,7 +206,7 @@ pub struct TestExecutionContext { /// Configuration parameters for the Zombienet. #[clap(flatten, next_help_heading = "Zombienet Configuration")] - pub zombienet_configuration: ZombieNetConfiguration, + pub zombienet_configuration: ZombienetConfiguration, /// Configuration parameters for the geth node. #[clap(flatten, next_help_heading = "Geth Configuration")] @@ -279,8 +279,8 @@ impl AsRef for TestExecutionContext { } } -impl AsRef for TestExecutionContext { - fn as_ref(&self) -> &ZombieNetConfiguration { +impl AsRef for TestExecutionContext { + fn as_ref(&self) -> &ZombienetConfiguration { &self.zombienet_configuration } } @@ -361,7 +361,7 @@ pub struct ResolcConfiguration { /// A set of configuration parameters for Zombienet. #[derive(Clone, Debug, Parser, Serialize)] -pub struct ZombieNetConfiguration { +pub struct ZombienetConfiguration { /// Specifies the path of the zombienet node to be used by the tool. /// /// If this is not specified, then the tool assumes that it should use the zombienet binary @@ -381,10 +381,6 @@ pub struct ZombieNetConfiguration { value_parser = parse_duration )] pub start_timeout_ms: Duration, - - /// This configures the tool to use Zombienet instead of using the revive-dev-node. - #[clap(long = "zombienet.dont-use-dev-node")] - pub use_zombienet: bool, } /// A set of configuration parameters for Geth. @@ -740,5 +736,5 @@ pub enum TestingPlatform { /// The kitchensink runtime provides the PolkaVM (PVM) based node implementation. Kitchensink, /// A polkadot/Substrate based network - ZombieNet, + Zombienet, } diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index f6188c8..88ba8f7 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -361,15 +361,15 @@ impl Platform for ReviveDevNodeRevmSolcPlatform { } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash)] -pub struct ZombieNetPolkavmResolcPlatform; +pub struct ZombienetPolkavmResolcPlatform; -impl Platform for ZombieNetPolkavmResolcPlatform { +impl Platform for ZombienetPolkavmResolcPlatform { fn platform_identifier(&self) -> PlatformIdentifier { - PlatformIdentifier::ZombieNetPolkavmResolc + PlatformIdentifier::ZombienetPolkavmResolc } fn node_identifier(&self) -> NodeIdentifier { - NodeIdentifier::ZombieNet + NodeIdentifier::Zombienet } fn vm_identifier(&self) -> VmIdentifier { @@ -385,12 +385,12 @@ impl Platform for ZombieNetPolkavmResolcPlatform { context: Context, ) -> anyhow::Result>>> { let genesis_configuration = AsRef::::as_ref(&context); - let zombie_net_path = AsRef::::as_ref(&context) + let zombienet_path = AsRef::::as_ref(&context) .path .clone(); let genesis = genesis_configuration.genesis()?.clone(); Ok(thread::spawn(move || { - let node = ZombieNode::new(zombie_net_path, context); + let node = ZombieNode::new(zombienet_path, context); let node = spawn_node(node, genesis)?; Ok(Box::new(node) as Box<_>) })) @@ -409,15 +409,15 @@ impl Platform for ZombieNetPolkavmResolcPlatform { } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash)] -pub struct ZombieNetRevmSolcPlatform; +pub struct ZombienetRevmSolcPlatform; -impl Platform for ZombieNetRevmSolcPlatform { +impl Platform for ZombienetRevmSolcPlatform { fn platform_identifier(&self) -> PlatformIdentifier { - PlatformIdentifier::ZombieNetRevmSolc + PlatformIdentifier::ZombienetRevmSolc } fn node_identifier(&self) -> NodeIdentifier { - NodeIdentifier::ZombieNet + NodeIdentifier::Zombienet } fn vm_identifier(&self) -> VmIdentifier { @@ -433,7 +433,7 @@ impl Platform for ZombieNetRevmSolcPlatform { context: Context, ) -> anyhow::Result>>> { let genesis_configuration = AsRef::::as_ref(&context); - let zombie_net_path = AsRef::::as_ref(&context) + let zombie_net_path = AsRef::::as_ref(&context) .path .clone(); let genesis = genesis_configuration.genesis()?.clone(); @@ -475,10 +475,10 @@ impl From for Box { PlatformIdentifier::ReviveDevNodeRevmSolc => { Box::new(ReviveDevNodeRevmSolcPlatform) as Box<_> } - PlatformIdentifier::ZombieNetPolkavmResolc => { - Box::new(ZombieNetPolkavmResolcPlatform) as Box<_> + PlatformIdentifier::ZombienetPolkavmResolc => { + Box::new(ZombienetPolkavmResolcPlatform) as Box<_> } - PlatformIdentifier::ZombieNetRevmSolc => Box::new(ZombieNetRevmSolcPlatform) as Box<_>, + PlatformIdentifier::ZombienetRevmSolc => Box::new(ZombienetRevmSolcPlatform) as Box<_>, } } } @@ -502,10 +502,10 @@ impl From for &dyn Platform { PlatformIdentifier::ReviveDevNodeRevmSolc => { &ReviveDevNodeRevmSolcPlatform as &dyn Platform } - PlatformIdentifier::ZombieNetPolkavmResolc => { - &ZombieNetPolkavmResolcPlatform as &dyn Platform + PlatformIdentifier::ZombienetPolkavmResolc => { + &ZombienetPolkavmResolcPlatform as &dyn Platform } - PlatformIdentifier::ZombieNetRevmSolc => &ZombieNetRevmSolcPlatform as &dyn Platform, + PlatformIdentifier::ZombienetRevmSolc => &ZombienetRevmSolcPlatform as &dyn Platform, } } } diff --git a/crates/node/Cargo.toml b/crates/node/Cargo.toml index 0c0cd9d..4c8f8ce 100644 --- a/crates/node/Cargo.toml +++ b/crates/node/Cargo.toml @@ -32,7 +32,6 @@ zombienet-sdk = { workspace = true } [dev-dependencies] temp-dir = { workspace = true } tokio = { workspace = true } -tracing-subscriber = { workspace = true } [lints] workspace = true diff --git a/crates/node/src/zombie.rs b/crates/node/src/zombie.rs index efd17ae..1b220d4 100644 --- a/crates/node/src/zombie.rs +++ b/crates/node/src/zombie.rs @@ -27,9 +27,8 @@ //! the full paths in your configuration. use std::{ - fs::{OpenOptions, create_dir_all, remove_dir_all}, - io::BufRead, - path::{Path, PathBuf}, + fs::{create_dir_all, remove_dir_all}, + path::PathBuf, pin::Pin, process::{Command, Stdio}, sync::{ @@ -68,7 +67,11 @@ use tracing::instrument; use zombienet_sdk::{LocalFileSystem, NetworkConfigBuilder, NetworkConfigExt}; use crate::{ - Node, common::FallbackGasFiller, constants::INITIAL_BALANCE, substrate::ReviveNetwork, + Node, + common::FallbackGasFiller, + constants::INITIAL_BALANCE, + process::{Process, ProcessReadinessWaitBehavior}, + substrate::ReviveNetwork, }; static NODE_COUNT: AtomicU32 = AtomicU32::new(0); @@ -89,7 +92,7 @@ pub struct ZombieNode { chain_id_filler: ChainIdFiller, network_config: Option, network: Option>, - eth_rpc_process: Option, + eth_rpc_process: Option, node_rpc_port: Option, } @@ -103,8 +106,6 @@ impl ZombieNode { const ETH_RPC_BASE_PORT: u16 = 8545; const ETH_RPC_READY_MARKER: &str = "Running JSON-RPC server"; - const ETH_RPC_STDOUT_LOG_FILE_NAME: &str = "eth_rpc_stdout.log"; - const ETH_RPC_STDERR_LOG_FILE_NAME: &str = "eth_rpc_stderr.log"; const EXPORT_CHAINSPEC_COMMAND: &str = "build-spec"; const CHAIN_SPEC_JSON_FILE: &str = "template_chainspec.json"; @@ -189,9 +190,11 @@ impl ZombieNode { } fn spawn_process(&mut self) -> anyhow::Result<()> { - let Some(network_config) = self.network_config.clone() else { - anyhow::bail!("Node not initialized, call init() first"); - }; + let network_config = self + .network_config + .clone() + .context("Node not initialized, call init() first")?; + let rt = tokio::runtime::Runtime::new().unwrap(); let network = rt.block_on(async { network_config @@ -202,103 +205,53 @@ impl ZombieNode { tracing::debug!("Zombienet network is up"); - let open_options = { - let mut options = OpenOptions::new(); - options.create(true).truncate(true).write(true); - options - }; - let node_url = format!("ws://localhost:{}", self.node_rpc_port.unwrap()); let eth_rpc_port = Self::ETH_RPC_BASE_PORT + self.id as u16; - let eth_rpc_stdout_log = format!( - "{}-{}.log", - self.eth_rpc_stdout_log_file_path().display(), - eth_rpc_port - ); - let eth_rpc_stderr_log = format!( - "{}-{}.log", - self.eth_rpc_stderr_log_file_path().display(), - eth_rpc_port + + let eth_rpc_process = Process::new( + "proxy", + self.logs_directory.as_path(), + self.eth_proxy_binary.as_path(), + |command, stdout_file, stderr_file| { + command + .arg("--node-rpc-url") + .arg(node_url) + .arg("--rpc-cors") + .arg("all") + .arg("--rpc-max-connections") + .arg(u32::MAX.to_string()) + .arg("--rpc-port") + .arg(eth_rpc_port.to_string()) + .stdout(stdout_file) + .stderr(stderr_file); + }, + ProcessReadinessWaitBehavior::TimeBoundedWaitFunction { + max_wait_duration: Duration::from_secs(30), + check_function: Box::new(|_, stderr_line| match stderr_line { + Some(line) => Ok(line.contains(Self::ETH_RPC_READY_MARKER)), + None => Ok(false), + }), + }, ); - let eth_rpc_stdout_logs_file = open_options - .clone() - .open(ð_rpc_stdout_log) - .context("Failed to open eth-rpc stdout logs file")?; - let eth_rpc_stderr_logs_file = open_options - .open(ð_rpc_stderr_log) - .context("Failed to open eth-rpc stderr logs file")?; - - let child = Command::new("eth-rpc") - .arg("--node-rpc-url") - .arg(node_url) - .arg("--rpc-cors") - .arg("all") - .arg("--rpc-max-connections") - .arg(u32::MAX.to_string()) - .arg("--rpc-port") - .arg(eth_rpc_port.to_string()) - .stdout( - eth_rpc_stdout_logs_file - .try_clone() - .context("Failed to clone eth-rpc stdout logs file")?, - ) - .stderr( - eth_rpc_stderr_logs_file - .try_clone() - .context("Failed to clone eth-rpc stderr logs file")?, - ) - .spawn() - .context("Failed to spawn eth-rpc process")?; - - // Give the node a moment to boot - let ready_result = Self::wait_ready( - Path::new(ð_rpc_stderr_log), - Self::ETH_RPC_READY_MARKER, - Duration::from_secs(60), - ); - - if let Err(error) = ready_result { - tracing::error!("eth-rpc failed to start: {error:?}"); - self.shutdown() - .context("Failed to gracefully shutdown after Substrate start error")?; - return Err(error); - }; + match eth_rpc_process { + Ok(process) => self.eth_rpc_process = Some(process), + Err(err) => { + tracing::error!(?err, "Failed to start eth proxy, shutting down gracefully"); + self.shutdown() + .context("Failed to gracefully shutdown after eth proxy start error")?; + return Err(err); + } + } tracing::info!("eth-rpc is up"); - tracing::debug!("Monitoring eth-rpc stderr logs at: {}", eth_rpc_stderr_log); - tracing::debug!("Monitoring eth-rpc stdout logs at: {}", eth_rpc_stdout_log); self.connection_string = format!("http://localhost:{}", eth_rpc_port); - self.eth_rpc_process = Some(child); self.network = Some(network); Ok(()) } - fn wait_ready(logs_file_path: &Path, marker: &str, timeout: Duration) -> anyhow::Result<()> { - let start_time = std::time::Instant::now(); - let logs_file = std::fs::OpenOptions::new() - .read(true) - .write(false) - .append(false) - .truncate(false) - .open(logs_file_path)?; - - let mut lines = std::io::BufReader::new(logs_file).lines(); - loop { - if let Some(Ok(line)) = lines.next() { - if line.contains(marker) { - return Ok(()); - } - } - - if start_time.elapsed() > timeout { - anyhow::bail!("Timeout waiting for process readiness: {marker}"); - } - } - } - fn prepare_chainspec( &mut self, template_chainspec_path: PathBuf, @@ -434,14 +387,6 @@ impl ZombieNode { .await .context("Failed to connect to parachain Ethereum RPC") } - - fn eth_rpc_stdout_log_file_path(&self) -> PathBuf { - self.logs_directory.join(Self::ETH_RPC_STDOUT_LOG_FILE_NAME) - } - - fn eth_rpc_stderr_log_file_path(&self) -> PathBuf { - self.logs_directory.join(Self::ETH_RPC_STDERR_LOG_FILE_NAME) - } } impl EthereumNode for ZombieNode { @@ -688,9 +633,7 @@ impl, P: Provider> ResolverApi impl Node for ZombieNode { fn shutdown(&mut self) -> anyhow::Result<()> { // Kill the eth_rpc process - if let Some(mut child) = self.eth_rpc_process.take() { - child.kill().context("Failed to kill eth-rpc process")?; - } + drop(self.eth_rpc_process.take()); // Destroy the network if let Some(network) = self.network.take() { @@ -753,8 +696,7 @@ mod tests { use tokio::sync::OnceCell; pub fn test_config() -> TestExecutionContext { - let mut context = TestExecutionContext::default(); - context.zombienet_configuration.use_zombienet = true; + let context = TestExecutionContext::default(); context }