From cf538276daa4988c1c7898cf37ade915bd0d55b6 Mon Sep 17 00:00:00 2001 From: Omar Abdulla Date: Tue, 14 Oct 2025 19:39:13 +0300 Subject: [PATCH] Allow for substrate-based nodes to be managed by the user --- crates/config/src/lib.rs | 18 +++++++ .../src/differential_benchmarks/driver.rs | 51 +------------------ crates/core/src/lib.rs | 10 ++++ .../src/node_implementations/substrate.rs | 18 ++++++- crates/node/src/provider_utils/provider.rs | 2 +- 5 files changed, 48 insertions(+), 51 deletions(-) diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index b671be1..08d4c9f 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -812,6 +812,24 @@ pub struct EthRpcConfiguration { value_parser = parse_duration )] pub start_timeout_ms: Duration, + + /// Specifies the connection string of an existing node that's not managed by the framework. + /// + /// If this argument is specified then the framework will not spawn certain nodes itself but + /// rather it will opt to using the existing node's through their provided connection strings. + /// + /// This means that if `ConcurrencyConfiguration.number_of_nodes` is 10 and we only specify the + /// connection strings of 2 nodes here, then nodes 0 and 1 will use the provided connection + /// strings and nodes 2 through 10 (exclusive) will all be spawned and managed by the framework. + /// + /// Thus, if you want all of the transactions and tests to happen against the node that you + /// spawned and manage then you need to specify a `ConcurrencyConfiguration.number_of_nodes` of + /// 1. + #[clap( + id = "revive-dev-node.existing-rpc-url", + long = "revive-dev-node.existing-rpc-url" + )] + pub existing_rpc_url: Vec, } /// A set of configuration parameters for the genesis. diff --git a/crates/core/src/differential_benchmarks/driver.rs b/crates/core/src/differential_benchmarks/driver.rs index 080e043..eb21fcc 100644 --- a/crates/core/src/differential_benchmarks/driver.rs +++ b/crates/core/src/differential_benchmarks/driver.rs @@ -31,8 +31,8 @@ use revive_dt_common::{ use revive_dt_format::{ metadata::{ContractInstance, ContractPathAndIdent}, steps::{ - AllocateAccountStep, BalanceAssertionStep, Calldata, EtherValue, FunctionCallStep, Method, - RepeatStep, Step, StepAddress, StepIdx, StepPath, StorageEmptyAssertionStep, + AllocateAccountStep, Calldata, EtherValue, FunctionCallStep, Method, RepeatStep, Step, + StepIdx, StepPath, }, traits::{ResolutionContext, ResolverApi}, }; @@ -428,26 +428,6 @@ where Ok(()) } - #[instrument(level = "info", skip_all, fields(driver_id = self.driver_id))] - pub async fn execute_balance_assertion( - &mut self, - _: &StepPath, - _: &BalanceAssertionStep, - ) -> anyhow::Result { - // Kept empty intentionally for the benchmark driver. - Ok(1) - } - - #[instrument(level = "info", skip_all, fields(driver_id = self.driver_id), err(Debug))] - async fn execute_storage_empty_assertion_step( - &mut self, - _: &StepPath, - _: &StorageEmptyAssertionStep, - ) -> Result { - // Kept empty intentionally for the benchmark driver. - Ok(1) - } - #[instrument(level = "info", skip_all, fields(driver_id = self.driver_id), err(Debug))] async fn execute_repeat_step( &mut self, @@ -671,33 +651,6 @@ where Ok((address, abi, receipt)) } - - #[instrument(level = "info", fields(driver_id = self.driver_id), skip_all)] - async fn step_address_auto_deployment( - &mut self, - step_address: &StepAddress, - ) -> Result
{ - match step_address { - StepAddress::Address(address) => Ok(*address), - StepAddress::ResolvableAddress(resolvable) => { - let Some(instance) = resolvable - .strip_suffix(".address") - .map(ContractInstance::new) - else { - bail!("Not an address variable"); - }; - - self.get_or_deploy_contract_instance( - &instance, - FunctionCallStep::default_caller_address(), - None, - None, - ) - .await - .map(|v| v.0) - } - } - } // endregion:Contract Deployment // region:Resolution & Resolver diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 9542fa4..97f3d56 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -207,6 +207,7 @@ impl Platform for KitchensinkPolkavmResolcPlatform { SubstrateNode::KITCHENSINK_EXPORT_CHAINSPEC_COMMAND, None, context, + &[], ); let node = spawn_node(node, genesis)?; Ok(Box::new(node) as Box<_>) @@ -270,6 +271,7 @@ impl Platform for KitchensinkRevmSolcPlatform { SubstrateNode::KITCHENSINK_EXPORT_CHAINSPEC_COMMAND, None, context, + &[], ); let node = spawn_node(node, genesis)?; Ok(Box::new(node) as Box<_>) @@ -324,10 +326,13 @@ impl Platform for ReviveDevNodePolkavmResolcPlatform { ) -> anyhow::Result>>> { let genesis_configuration = AsRef::::as_ref(&context); let revive_dev_node_configuration = AsRef::::as_ref(&context); + let eth_rpc_configuration = AsRef::::as_ref(&context); let revive_dev_node_path = revive_dev_node_configuration.path.clone(); let revive_dev_node_consensus = revive_dev_node_configuration.consensus.clone(); + let eth_rpc_connection_strings = eth_rpc_configuration.existing_rpc_url.clone(); + let genesis = genesis_configuration.genesis()?.clone(); Ok(thread::spawn(move || { let node = SubstrateNode::new( @@ -335,6 +340,7 @@ impl Platform for ReviveDevNodePolkavmResolcPlatform { SubstrateNode::REVIVE_DEV_NODE_EXPORT_CHAINSPEC_COMMAND, Some(revive_dev_node_consensus), context, + ð_rpc_connection_strings, ); let node = spawn_node(node, genesis)?; Ok(Box::new(node) as Box<_>) @@ -389,10 +395,13 @@ impl Platform for ReviveDevNodeRevmSolcPlatform { ) -> anyhow::Result>>> { let genesis_configuration = AsRef::::as_ref(&context); let revive_dev_node_configuration = AsRef::::as_ref(&context); + let eth_rpc_configuration = AsRef::::as_ref(&context); let revive_dev_node_path = revive_dev_node_configuration.path.clone(); let revive_dev_node_consensus = revive_dev_node_configuration.consensus.clone(); + let eth_rpc_connection_strings = eth_rpc_configuration.existing_rpc_url.clone(); + let genesis = genesis_configuration.genesis()?.clone(); Ok(thread::spawn(move || { let node = SubstrateNode::new( @@ -400,6 +409,7 @@ impl Platform for ReviveDevNodeRevmSolcPlatform { SubstrateNode::REVIVE_DEV_NODE_EXPORT_CHAINSPEC_COMMAND, Some(revive_dev_node_consensus), context, + ð_rpc_connection_strings, ); let node = spawn_node(node, genesis)?; Ok(Box::new(node) as Box<_>) diff --git a/crates/node/src/node_implementations/substrate.rs b/crates/node/src/node_implementations/substrate.rs index dbdde95..6ff9de5 100644 --- a/crates/node/src/node_implementations/substrate.rs +++ b/crates/node/src/node_implementations/substrate.rs @@ -99,6 +99,7 @@ impl SubstrateNode { context: impl AsRef + AsRef + AsRef, + existing_connection_strings: &[String], ) -> Self { let working_directory_path = AsRef::::as_ref(&context).as_path(); @@ -112,12 +113,17 @@ impl SubstrateNode { let base_directory = substrate_directory.join(id.to_string()); let logs_directory = base_directory.join(Self::LOGS_DIRECTORY); + let rpc_url = existing_connection_strings + .get(id as usize) + .cloned() + .unwrap_or_default(); + Self { id, node_binary: node_path, eth_proxy_binary: eth_rpc_path.to_path_buf(), export_chainspec_command: export_chainspec_command.to_string(), - rpc_url: String::new(), + rpc_url, base_directory, logs_directory, substrate_process: None, @@ -130,6 +136,10 @@ impl SubstrateNode { } fn init(&mut self, _: Genesis) -> anyhow::Result<&mut Self> { + if !self.rpc_url.is_empty() { + return Ok(self); + } + let _ = remove_dir_all(self.base_directory.as_path()); let _ = clear_directory(&self.base_directory); let _ = clear_directory(&self.logs_directory); @@ -158,6 +168,10 @@ impl SubstrateNode { } fn spawn_process(&mut self) -> anyhow::Result<()> { + if !self.rpc_url.is_empty() { + return Ok(()); + } + let substrate_rpc_port = Self::BASE_SUBSTRATE_RPC_PORT + self.id as u16; let proxy_rpc_port = Self::BASE_PROXY_RPC_PORT + self.id as u16; @@ -772,6 +786,7 @@ mod tests { SubstrateNode::KITCHENSINK_EXPORT_CHAINSPEC_COMMAND, None, &context, + &[], ); node.init(context.genesis_configuration.genesis().unwrap().clone()) .expect("Failed to initialize the node") @@ -838,6 +853,7 @@ mod tests { SubstrateNode::KITCHENSINK_EXPORT_CHAINSPEC_COMMAND, None, &context, + &[], ); // Call `init()` diff --git a/crates/node/src/provider_utils/provider.rs b/crates/node/src/provider_utils/provider.rs index ba7a2c5..f10b3b6 100644 --- a/crates/node/src/provider_utils/provider.rs +++ b/crates/node/src/provider_utils/provider.rs @@ -44,7 +44,7 @@ where // requests at any point of time and no more than that. This is done in an effort to stabilize // the framework from some of the interment issues that we've been seeing related to RPC calls. static GLOBAL_CONCURRENCY_LIMITER_LAYER: LazyLock = - LazyLock::new(|| ConcurrencyLimiterLayer::new(1000)); + LazyLock::new(|| ConcurrencyLimiterLayer::new(500)); let client = ClientBuilder::default() .layer(GLOBAL_CONCURRENCY_LIMITER_LAYER.clone())