diff --git a/src/dfx/src/commands/replica.rs b/src/dfx/src/commands/replica.rs index 940b0a5ca5..c0e851906d 100644 --- a/src/dfx/src/commands/replica.rs +++ b/src/dfx/src/commands/replica.rs @@ -2,7 +2,7 @@ use crate::commands::canister::create_waiter; use crate::lib::environment::Environment; use crate::lib::error::{DfxError, DfxResult}; use crate::lib::message::UserMessage; -use crate::lib::replica_config::ReplicaConfig; +use crate::lib::replica_config::{ReplicaConfig, SchedulerConfig}; use clap::{App, Arg, ArgMatches, SubCommand}; use crossbeam::channel::{Receiver, Sender}; @@ -32,6 +32,20 @@ pub fn construct() -> App<'static, 'static> { .map(|_| ()) }), ) + .arg( + Arg::with_name("message-gas-max") + .help(UserMessage::ReplicaMessageGasMax.to_str()) + .long("message-gas-max") + .takes_value(true) + .default_value("5368709120"), + ) + .arg( + Arg::with_name("round-gas-max") + .help(UserMessage::ReplicaRoundGasMax.to_str()) + .long("round-gas-max") + .takes_value(true) + .default_value("26843545600"), + ) } fn ping_and_wait(frontend_url: &str) -> DfxResult { @@ -47,6 +61,32 @@ fn ping_and_wait(frontend_url: &str) -> DfxResult { .map_err(DfxError::from) } +fn get_scheduler(args: &ArgMatches<'_>) -> DfxResult { + // Get mssage gas limit. + let message_gas_max = args + .value_of("message-gas-max") + .expect("default value") + .parse() + .map_err(|err| DfxError::InvalidArgument(format!("Invalid message gas limit: {}", err)))?; + // Get round gas limit. + let round_gas_max = args + .value_of("round-gas-max") + .expect("default value") + .parse() + .map_err(|err| DfxError::InvalidArgument(format!("Invalid round gas limit: {}", err)))?; + // Check message and round gas limits. + if message_gas_max >= round_gas_max { + let err = "Round gas limit must exceed message gas limit.".to_string(); + Err(DfxError::InvalidArgument(err)) + } else { + // Return scheduler configuration. + Ok(SchedulerConfig { + exec_gas: Some(message_gas_max), + round_gas_max: Some(round_gas_max), + }) + } +} + // TODO(eftychis)/In progress: Rename to replica. /// Start the Internet Computer locally. Spawns a proxy to forward and /// manage browser requests. Responsible for running the network (one @@ -63,6 +103,8 @@ pub fn exec(env: &dyn Environment, args: &ArgMatches<'_>) -> DfxResult { .parse::() .expect("Unreachable. Port should have been validated by clap."); + let scheduler = get_scheduler(args)?; + // We are doing this here to make sure we can write to the temp // pid file. std::fs::write(&pid_file_path, "")?; @@ -79,7 +121,10 @@ pub fn exec(env: &dyn Environment, args: &ArgMatches<'_>) -> DfxResult { let (_broadcast_stop, is_killed_replica) = unbounded(); b.set_message("Generating IC local replica configuration."); - let replica_config = ReplicaConfig::new(&state_root).with_port(port).to_toml()?; + let replica_config = ReplicaConfig::new(&state_root) + .with_port(port) + .with_scheduler(scheduler) + .to_toml()?; // TODO(eftychis): we need a proper manager type when we start // spawning multiple replica processes and registry. diff --git a/src/dfx/src/lib/message.rs b/src/dfx/src/lib/message.rs index f917cb4e7e..f846bdebd3 100644 --- a/src/dfx/src/lib/message.rs +++ b/src/dfx/src/lib/message.rs @@ -76,7 +76,9 @@ user_message!( // dfx replica Replica => "Start a local replica.", + ReplicaMessageGasMax => "Maximum amount of gas a single message can consume.", ReplicaPort => "The port the local replica should listen to.", + ReplicaRoundGasMax => "Maximum amount of gas a single round can consume.", // dfx start CleanState => "Cleans state of current project.", diff --git a/src/dfx/src/lib/replica_config.rs b/src/dfx/src/lib/replica_config.rs index f32eff07bf..be1ea0f012 100644 --- a/src/dfx/src/lib/replica_config.rs +++ b/src/dfx/src/lib/replica_config.rs @@ -15,6 +15,12 @@ pub struct HttpHandlerConfig { pub write_port_to: Option, } +#[derive(Debug, Serialize)] +pub struct SchedulerConfig { + pub exec_gas: Option, + pub round_gas_max: Option, +} + #[derive(Debug, Serialize)] pub struct StateManagerConfig { pub state_root: PathBuf, @@ -22,20 +28,25 @@ pub struct StateManagerConfig { #[derive(Debug, Serialize)] pub struct ReplicaConfig { - pub state_manager: StateManagerConfig, pub http_handler: HttpHandlerConfig, + pub scheduler: SchedulerConfig, + pub state_manager: StateManagerConfig, } impl ReplicaConfig { pub fn new(state_root: &Path) -> Self { ReplicaConfig { - state_manager: StateManagerConfig { - state_root: state_root.to_path_buf(), - }, http_handler: HttpHandlerConfig { write_port_to: None, use_port: None, }, + scheduler: SchedulerConfig { + exec_gas: None, + round_gas_max: None, + }, + state_manager: StateManagerConfig { + state_root: state_root.to_path_buf(), + }, } } @@ -51,6 +62,11 @@ impl ReplicaConfig { self } + pub fn with_scheduler(&mut self, scheduler: SchedulerConfig) -> &mut Self { + self.scheduler = scheduler; + self + } + pub fn to_toml(&self) -> DfxResult { toml::to_string(&self).map_err(DfxError::CouldNotSerializeClientConfiguration) }