diff --git a/CHANGELOG.md b/CHANGELOG.md index a6b2f662d6..8fbc9e1e30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The `dfx cycles` command no longer needs nor accepts the `--cycles-ledger-canister-id ` parameter. +### chore: removed the dfx start --emulator mode + +This was deprecated in dfx 0.15.1. + ### chore: removed ic-ref from the binary cache ### chore: updated dependencies for new rust projects diff --git a/docs/cli-reference/dfx-start.md b/docs/cli-reference/dfx-start.md index 3621c67bc2..2ec382bf9d 100644 --- a/docs/cli-reference/dfx-start.md +++ b/docs/cli-reference/dfx-start.md @@ -18,7 +18,6 @@ You can use the following optional flags with the `dfx start` command. |-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `--background` | Starts the local canister execution environment and web server processes in the background and waits for a reply before returning to the shell. | | `--clean` | Starts the local canister execution environment and web server processes in a clean state by removing checkpoints from your project cache. You can use this flag to set your project cache to a new state when troubleshooting or debugging. | -| `--emulator` | Starts the [IC reference emulator](https://github.com/dfinity/ic-hs) rather than the replica. (deprecated: will be discontinued soon) | | `--enable-bitcoin` | Enables bitcoin integration. | | `--enable-canister-http` | Enables canister HTTP requests. (deprecated: now enabled by default) | | `--use-old-metering` | Enables the old metering in the local canister execution environment. Please see the forum thread for more details or to report any issues: [forum.dfinity.org/t/new-wasm-instrumentation/](https://forum.dfinity.org/t/new-wasm-instrumentation/22080) | diff --git a/src/dfx-core/src/config/model/local_server_descriptor.rs b/src/dfx-core/src/config/model/local_server_descriptor.rs index 6d59829cfa..871da03dc7 100644 --- a/src/dfx-core/src/config/model/local_server_descriptor.rs +++ b/src/dfx-core/src/config/model/local_server_descriptor.rs @@ -98,11 +98,6 @@ impl LocalServerDescriptor { self.data_directory.join("icx-proxy-pid") } - /// This file contains the listening port of the ic-ref process - pub fn ic_ref_port_path(&self) -> PathBuf { - self.data_directory.join("ic-ref.port") - } - /// This file contains the pid of the ic-btc-adapter process pub fn btc_adapter_pid_path(&self) -> PathBuf { self.data_directory.join("ic-btc-adapter-pid") @@ -297,12 +292,11 @@ impl LocalServerDescriptor { /// Gets the port of a local replica. /// /// # Prerequisites - /// - A local replica or emulator needs to be running, e.g. with `dfx start`. + /// - A local replica needs to be running, e.g. with `dfx start`. pub fn get_running_replica_port( &self, logger: Option<&Logger>, ) -> Result, NetworkConfigError> { - let emulator_port_path = self.ic_ref_port_path(); let replica_port_path = self.replica_port_path(); match read_port_from(&replica_port_path)? { @@ -312,15 +306,7 @@ impl LocalServerDescriptor { } Ok(Some(port)) } - None => match read_port_from(&emulator_port_path)? { - Some(port) => { - if let Some(logger) = logger { - info!(logger, "Found local emulator running on port {}", port); - } - Ok(Some(port)) - } - None => Ok(self.replica.port), - }, + None => Ok(self.replica.port), } } } diff --git a/src/dfx/src/actors/emulator.rs b/src/dfx/src/actors/emulator.rs deleted file mode 100644 index 241ad760d2..0000000000 --- a/src/dfx/src/actors/emulator.rs +++ /dev/null @@ -1,245 +0,0 @@ -use crate::actors::icx_proxy::signals::{PortReadySignal, PortReadySubscribe}; -use crate::actors::shutdown::{wait_for_child_or_receiver, ChildOrReceiver}; -use crate::actors::shutdown_controller::signals::outbound::Shutdown; -use crate::actors::shutdown_controller::signals::ShutdownSubscribe; -use crate::actors::shutdown_controller::ShutdownController; -use crate::lib::error::{DfxError, DfxResult}; -use actix::{ - Actor, ActorContext, ActorFutureExt, Addr, AsyncContext, Context, Handler, Recipient, - ResponseActFuture, Running, WrapFuture, -}; -use anyhow::bail; -use crossbeam::channel::{unbounded, Receiver, Sender}; -use slog::{debug, info, Logger}; -use std::path::{Path, PathBuf}; -use std::thread::JoinHandle; -use std::time::Duration; - -pub mod signals { - use actix::prelude::*; - - /// A message sent to the Emulator when the process is restarted. Since we're - /// restarting inside our own actor, this message should not be exposed. - #[derive(Message)] - #[rtype(result = "()")] - pub(super) struct EmulatorRestarted { - pub port: u16, - } -} - -/// The configuration for the emulator actor. -#[derive(Clone)] -pub struct Config { - pub ic_ref_path: PathBuf, - pub port: Option, - pub write_port_to: PathBuf, - pub shutdown_controller: Addr, - pub logger: Option, -} - -/// A emulator actor. Starts the emulator, can subscribe to a Ready signal and a -/// Killed signal. -/// This starts a thread that monitors the process and send signals to any subscriber -/// listening for restarts. The message contains the port the emulator is listening to. -/// -/// Signals -/// - PortReadySubscribe -/// Subscribe a recipient (address) to receive a EmulatorReadySignal message when -/// the emulator is ready to listen to a port. The message can be sent multiple -/// times (e.g. if the emulator crashes). -/// If a emulator is already started and another actor sends this message, a -/// EmulatorReadySignal will be sent free of charge in the same thread. -pub struct Emulator { - logger: Logger, - config: Config, - - // We keep the port to send to subscribers on subscription. - port: Option, - stop_sender: Option>, - thread_join: Option>, - - /// Ready Signal subscribers. - ready_subscribers: Vec>, -} - -impl Emulator { - pub fn new(config: Config) -> Self { - let logger = - (config.logger.clone()).unwrap_or_else(|| Logger::root(slog::Discard, slog::o!())); - Emulator { - config, - port: None, - stop_sender: None, - thread_join: None, - ready_subscribers: Vec::new(), - logger, - } - } - - fn wait_for_port_file(file_path: &Path) -> DfxResult { - let mut retries = 0; - loop { - if let Ok(content) = std::fs::read_to_string(file_path) { - if let Ok(port) = content.parse::() { - return Ok(port); - } - } - if retries >= 3000 { - bail!("Cannot start ic-ref: timed out"); - } - std::thread::sleep(Duration::from_millis(100)); - retries += 1; - } - } - - fn start_emulator(&mut self, addr: Addr) -> DfxResult { - let logger = self.logger.clone(); - - let (sender, receiver) = unbounded(); - - let handle = anyhow::Context::context( - emulator_start_thread(logger, self.config.clone(), addr, receiver), - "Failed to start emulator thread.", - )?; - - self.thread_join = Some(handle); - self.stop_sender = Some(sender); - Ok(()) - } - - fn send_ready_signal(&self, port: u16) { - for sub in &self.ready_subscribers { - sub.do_send(PortReadySignal { port }); - } - } -} - -impl Actor for Emulator { - type Context = Context; - - fn started(&mut self, ctx: &mut Self::Context) { - self.start_emulator(ctx.address()) - .expect("Could not start the emulator"); - - self.config - .shutdown_controller - .do_send(ShutdownSubscribe(ctx.address().recipient::())); - } - - fn stopping(&mut self, _ctx: &mut Self::Context) -> Running { - info!(self.logger, "Stopping ic-ref..."); - if let Some(sender) = self.stop_sender.take() { - let _ = sender.send(()); - } - - if let Some(join) = self.thread_join.take() { - let _ = join.join(); - } - - info!(self.logger, "Stopped."); - Running::Stop - } -} - -impl Handler for Emulator { - type Result = (); - - fn handle(&mut self, msg: PortReadySubscribe, _: &mut Self::Context) { - // If we have a port, send that we're already ready! Yeah! - if let Some(port) = self.port { - msg.0.do_send(PortReadySignal { port }); - } - - self.ready_subscribers.push(msg.0); - } -} - -impl Handler for Emulator { - type Result = (); - - fn handle( - &mut self, - msg: signals::EmulatorRestarted, - _ctx: &mut Self::Context, - ) -> Self::Result { - self.port = Some(msg.port); - self.send_ready_signal(msg.port); - } -} - -impl Handler for Emulator { - type Result = ResponseActFuture>; - - fn handle(&mut self, _msg: Shutdown, _ctx: &mut Self::Context) -> Self::Result { - // This is just the example for ResponseActFuture but stopping the context - Box::pin( - async {} - .into_actor(self) // converts future to ActorFuture - .map(|_, _act, ctx| { - ctx.stop(); - Ok(()) - }), - ) - } -} - -fn emulator_start_thread( - logger: Logger, - config: Config, - addr: Addr, - receiver: Receiver<()>, -) -> DfxResult> { - let thread_handler = move || { - // Start the process, then wait for the file. - let ic_ref_path = config.ic_ref_path.as_os_str(); - - // form the ic-start command here similar to emulator command - let mut cmd = std::process::Command::new(ic_ref_path); - match config.port { - Some(port) if port != 0 => cmd.args(["--listen-port", &port.to_string()]), - _ => cmd.args(["--pick-port"]), - }; - cmd.args(["--write-port-to", &config.write_port_to.to_string_lossy()]); - cmd.stdout(std::process::Stdio::inherit()); - cmd.stderr(std::process::Stdio::inherit()); - - loop { - let _ = std::fs::remove_file(&config.write_port_to); - let last_start = std::time::Instant::now(); - debug!(logger, "Starting emulator..."); - let mut child = cmd.spawn().expect("Could not start emulator."); - - let port = Emulator::wait_for_port_file(&config.write_port_to).unwrap(); - addr.do_send(signals::EmulatorRestarted { port }); - - // This waits for the child to stop, or the receiver to receive a message. - // We don't restart the emulator if done = true. - match wait_for_child_or_receiver(&mut child, &receiver) { - ChildOrReceiver::Receiver => { - debug!(logger, "Got signal to stop. Killing emulator process..."); - let _ = child.kill(); - let _ = child.wait(); - break; - } - ChildOrReceiver::Child => { - debug!(logger, "Emulator process failed."); - // If it took less than two seconds to exit, wait a bit before trying again. - if std::time::Instant::now().duration_since(last_start) < Duration::from_secs(2) - { - std::thread::sleep(Duration::from_secs(2)); - } else { - debug!( - logger, - "Last emulator seemed to have been healthy, not waiting..." - ); - } - } - } - } - }; - - std::thread::Builder::new() - .name("emulator-actor".to_owned()) - .spawn(thread_handler) - .map_err(DfxError::from) -} diff --git a/src/dfx/src/actors/mod.rs b/src/dfx/src/actors/mod.rs index ea3d5675c9..0d32bc0e55 100644 --- a/src/dfx/src/actors/mod.rs +++ b/src/dfx/src/actors/mod.rs @@ -1,9 +1,7 @@ -use crate::actors; use crate::actors::btc_adapter::signals::BtcAdapterReadySubscribe; use crate::actors::btc_adapter::BtcAdapter; use crate::actors::canister_http_adapter::signals::CanisterHttpAdapterReadySubscribe; use crate::actors::canister_http_adapter::CanisterHttpAdapter; -use crate::actors::emulator::Emulator; use crate::actors::icx_proxy::signals::PortReadySubscribe; use crate::actors::icx_proxy::{IcxProxy, IcxProxyConfig}; use crate::actors::replica::{BitcoinIntegrationConfig, Replica}; @@ -20,7 +18,6 @@ use std::path::PathBuf; pub mod btc_adapter; pub mod canister_http_adapter; -pub mod emulator; pub mod icx_proxy; pub mod replica; mod shutdown; @@ -82,36 +79,6 @@ pub fn start_canister_http_adapter_actor( Ok(CanisterHttpAdapter::new(actor_config).start().recipient()) } -#[context("Failed to start emulator actor.")] -pub fn start_emulator_actor( - env: &dyn Environment, - local_server_descriptor: &LocalServerDescriptor, - shutdown_controller: Addr, - emulator_port_path: PathBuf, -) -> DfxResult> { - let ic_ref_path = env.get_cache().get_binary_command_path("ic-ref")?; - - // Touch the port file. This ensures it is empty prior to - // handing it over to ic-ref. If we read the file and it has - // contents we shall assume it is due to our spawned ic-ref - // process. - std::fs::write(&emulator_port_path, "").with_context(|| { - format!( - "Failed to write/clear emulator port file {}.", - emulator_port_path.to_string_lossy() - ) - })?; - - let actor_config = actors::emulator::Config { - ic_ref_path, - port: local_server_descriptor.replica.port, - write_port_to: emulator_port_path, - shutdown_controller, - logger: Some(env.get_logger().clone()), - }; - Ok(actors::emulator::Emulator::new(actor_config).start()) -} - #[context("Failed to setup replica environment.")] fn setup_replica_env( local_server_descriptor: &LocalServerDescriptor, diff --git a/src/dfx/src/actors/shutdown.rs b/src/dfx/src/actors/shutdown.rs index 9610c36c83..b33668114d 100644 --- a/src/dfx/src/actors/shutdown.rs +++ b/src/dfx/src/actors/shutdown.rs @@ -17,7 +17,7 @@ pub fn wait_for_child_or_receiver( loop { // Check if either the child exited or a shutdown has been requested. // These can happen in either order in response to Ctrl-C, so increase the chance - // to notice a shutdown request even if the emulator exited quickly. + // to notice a shutdown request even if the replica exited quickly. let child_try_wait = child.try_wait(); let receiver_signalled = receiver.recv_timeout(std::time::Duration::from_millis(100)); diff --git a/src/dfx/src/commands/start.rs b/src/dfx/src/commands/start.rs index 1fdcd36230..3f0fb5c907 100644 --- a/src/dfx/src/commands/start.rs +++ b/src/dfx/src/commands/start.rs @@ -1,8 +1,8 @@ use crate::actors::icx_proxy::signals::PortReadySubscribe; use crate::actors::icx_proxy::IcxProxyConfig; use crate::actors::{ - start_btc_adapter_actor, start_canister_http_adapter_actor, start_emulator_actor, - start_icx_proxy_actor, start_replica_actor, start_shutdown_controller, + start_btc_adapter_actor, start_canister_http_adapter_actor, start_icx_proxy_actor, + start_replica_actor, start_shutdown_controller, }; use crate::config::dfx_version_str; use crate::error_invalid_argument; @@ -53,24 +53,20 @@ pub struct StartOpts { #[arg(long)] clean: bool, - /// Runs a dedicated emulator instead of the replica - #[arg(long)] - emulator: bool, - /// Address of bitcoind node. Implies --enable-bitcoin. - #[arg(long, conflicts_with("emulator"), action = ArgAction::Append)] + #[arg(long, action = ArgAction::Append)] bitcoin_node: Vec, /// enable bitcoin integration - #[arg(long, conflicts_with("emulator"))] + #[arg(long)] enable_bitcoin: bool, /// enable canister http requests - #[arg(long, conflicts_with("emulator"))] + #[arg(long)] enable_canister_http: bool, /// The delay (in milliseconds) an update call should take. Lower values may be expedient in CI. - #[arg(long, conflicts_with("emulator"), default_value_t = 600)] + #[arg(long, default_value_t = 600)] artificial_delay: u32, /// Start even if the network config was modified. @@ -142,7 +138,6 @@ pub fn exec( StartOpts { host, background, - emulator, clean, force, bitcoin_node, @@ -183,7 +178,6 @@ pub fn exec( enable_bitcoin, bitcoin_node, enable_canister_http, - emulator, domain, )?; @@ -244,7 +238,6 @@ pub fn exec( })?; let replica_port_path = empty_writable_path(local_server_descriptor.replica_port_path())?; - let emulator_port_path = empty_writable_path(local_server_descriptor.ic_ref_port_path())?; if background { send_background()?; @@ -328,11 +321,8 @@ pub fn exec( replica_config }; - let effective_config = if emulator { - CachedConfig::emulator() - } else { - CachedConfig::replica(&replica_config) - }; + let effective_config = CachedConfig::replica(&replica_config); + if !clean && !force && previous_config_path.exists() { let previous_config = load_json_file(&previous_config_path) .context("Failed to read replica configuration. Rerun with `--clean`.")?; @@ -349,15 +339,7 @@ pub fn exec( let _proxy = system.block_on(async move { let shutdown_controller = start_shutdown_controller(env)?; - let port_ready_subscribe: Recipient = if emulator { - let emulator = start_emulator_actor( - env, - local_server_descriptor, - shutdown_controller.clone(), - emulator_port_path, - )?; - emulator.recipient() - } else { + let port_ready_subscribe: Recipient = { let btc_adapter_ready_subscribe = btc_adapter_config .map(|btc_adapter_config| { start_btc_adapter_actor( @@ -426,7 +408,6 @@ pub fn exec( #[allow(clippy::large_enum_variant)] pub enum CachedReplicaConfig<'a> { Replica { config: Cow<'a, ReplicaConfig> }, - Emulator, } #[derive(Serialize, Deserialize, PartialEq, Eq)] @@ -445,12 +426,6 @@ impl<'a> CachedConfig<'a> { }, } } - pub fn emulator() -> Self { - Self { - replica_rev: replica_rev().into(), - config: CachedReplicaConfig::Emulator, - } - } } pub fn apply_command_line_parameters( @@ -461,7 +436,6 @@ pub fn apply_command_line_parameters( enable_bitcoin: bool, bitcoin_nodes: Vec, enable_canister_http: bool, - emulator: bool, domain: Vec, ) -> DfxResult { if enable_canister_http { @@ -472,13 +446,6 @@ pub fn apply_command_line_parameters( warn!(logger, "Canister HTTP suppport is enabled by default. It can be disabled through dfx.json or networks.json."); } - if emulator { - warn!( - logger, - "The --emulator parameter is deprecated and will be discontinued soon." - ); - } - let _ = network_descriptor.local_server_descriptor()?; let mut local_server_descriptor = network_descriptor.local_server_descriptor.unwrap(); diff --git a/src/dfx/src/lib/replica/status.rs b/src/dfx/src/lib/replica/status.rs index 3efc7ee84f..9b896aa045 100644 --- a/src/dfx/src/lib/replica/status.rs +++ b/src/dfx/src/lib/replica/status.rs @@ -17,12 +17,7 @@ pub async fn ping_and_wait(url: &str) -> DfxResult { let status = agent.status().await; match status { Ok(status) => { - let healthy = match &status.replica_health_status { - Some(status) if status == "healthy" => true, - None => true, // emulator doesn't report replica_health_status - _ => false, - }; - if healthy { + if matches!(&status.replica_health_status, Some(status) if status == "healthy") { break; } }