diff --git a/Cargo.lock b/Cargo.lock index b0c5b4b40..c126a7fac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -241,6 +241,46 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bollard" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f03db470b3c0213c47e978da93200259a1eb4dae2e5512cba9955e2b540a6fc6" +dependencies = [ + "base64 0.21.7", + "bollard-stubs", + "bytes", + "futures-core", + "futures-util", + "hex", + "http 0.2.11", + "hyper", + "hyperlocal", + "log", + "pin-project-lite", + "serde", + "serde_derive", + "serde_json", + "serde_repr", + "serde_urlencoded", + "thiserror", + "tokio", + "tokio-util", + "url", + "winapi", +] + +[[package]] +name = "bollard-stubs" +version = "1.43.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58071e8fd9ec1e930efd28e3a90c1251015872a2ce49f81f36421b86466932e" +dependencies = [ + "serde", + "serde_repr", + "serde_with", +] + [[package]] name = "bstr" version = "1.9.0" @@ -1060,6 +1100,17 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "futures-sink" version = "0.3.30" @@ -1080,6 +1131,7 @@ checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -2106,6 +2158,19 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "hyperlocal" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fafdf7b2b2de7c9784f76e02c0935e65a8117ec3b768644379983ab333ac98c" +dependencies = [ + "futures-util", + "hex", + "hyper", + "pin-project", + "tokio", +] + [[package]] name = "iana-time-zone" version = "0.1.60" @@ -3327,6 +3392,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "serde_spanned" version = "0.6.5" @@ -3520,6 +3596,7 @@ dependencies = [ "assert_fs", "async-trait", "base64 0.21.7", + "bollard", "cargo_metadata", "chrono", "clap", @@ -3531,9 +3608,11 @@ dependencies = [ "dotenvy", "ed25519-dalek 2.0.0", "ethnum", + "futures-util", "gix", "heck 0.4.1", "hex", + "home", "http 0.2.11", "hyper", "hyper-tls", diff --git a/cmd/soroban-cli/Cargo.toml b/cmd/soroban-cli/Cargo.toml index 846b4a36a..f5ef2b1b0 100644 --- a/cmd/soroban-cli/Cargo.toml +++ b/cmd/soroban-cli/Cargo.toml @@ -106,6 +106,9 @@ ureq = { version = "2.9.1", features = ["json"] } tempfile = "3.8.1" toml_edit = "0.21.0" rust-embed = { version = "8.2.0", features = ["debug-embed"] } +bollard = "0.15.0" +futures-util = "0.3.30" +home = "0.5.9" # For hyper-tls [target.'cfg(unix)'.dependencies] openssl = { version = "=0.10.55", features = ["vendored"] } diff --git a/cmd/soroban-cli/src/commands/config/mod.rs b/cmd/soroban-cli/src/commands/config/mod.rs index be76e77f9..3c5f4cca4 100644 --- a/cmd/soroban-cli/src/commands/config/mod.rs +++ b/cmd/soroban-cli/src/commands/config/mod.rs @@ -38,7 +38,7 @@ impl Cmd { pub async fn run(&self) -> Result<(), Error> { match &self { Cmd::Identity(identity) => identity.run().await?, - Cmd::Network(network) => network.run()?, + Cmd::Network(network) => network.run().await?, } Ok(()) } diff --git a/cmd/soroban-cli/src/commands/mod.rs b/cmd/soroban-cli/src/commands/mod.rs index ae3ac3ecb..4924ef5ee 100644 --- a/cmd/soroban-cli/src/commands/mod.rs +++ b/cmd/soroban-cli/src/commands/mod.rs @@ -96,7 +96,7 @@ impl Root { Cmd::Contract(contract) => contract.run(&self.global_args).await?, Cmd::Events(events) => events.run().await?, Cmd::Lab(lab) => lab.run().await?, - Cmd::Network(network) => network.run()?, + Cmd::Network(network) => network.run().await?, Cmd::Version(version) => version.run(), Cmd::Keys(id) => id.run().await?, Cmd::Config(c) => c.run().await?, diff --git a/cmd/soroban-cli/src/commands/network/mod.rs b/cmd/soroban-cli/src/commands/network/mod.rs index a1c021722..b4a145f13 100644 --- a/cmd/soroban-cli/src/commands/network/mod.rs +++ b/cmd/soroban-cli/src/commands/network/mod.rs @@ -17,6 +17,9 @@ pub const LOCAL_NETWORK_PASSPHRASE: &str = "Standalone Network ; February 2017"; pub mod add; pub mod ls; pub mod rm; +pub mod shared; +pub mod start; +pub mod stop; #[derive(Debug, Parser)] pub enum Cmd { @@ -26,6 +29,17 @@ pub enum Cmd { Rm(rm::Cmd), /// List networks Ls(ls::Cmd), + /// Start network + /// + /// Start a container running a Stellar node, RPC, API, and friendbot (faucet). + /// + /// soroban network start [OPTIONS] + /// + /// By default, when starting a testnet container, without any optional arguments, it will run the equivalent of the following docker command: + /// docker run --rm -p 8000:8000 --name stellar stellar/quickstart:testing --testnet --enable-soroban-rpc + Start(start::Cmd), + /// Stop a network started with `network start`. For example, if you ran `soroban network start local`, you can use `soroban network stop local` to stop it. + Stop(stop::Cmd), } #[derive(thiserror::Error, Debug)] @@ -39,6 +53,12 @@ pub enum Error { #[error(transparent)] Ls(#[from] ls::Error), + #[error(transparent)] + Start(#[from] start::Error), + + #[error(transparent)] + Stop(#[from] stop::Error), + #[error(transparent)] Config(#[from] locator::Error), @@ -61,11 +81,13 @@ pub enum Error { } impl Cmd { - pub fn run(&self) -> Result<(), Error> { + pub async fn run(&self) -> Result<(), Error> { match self { Cmd::Add(cmd) => cmd.run()?, Cmd::Rm(new) => new.run()?, Cmd::Ls(cmd) => cmd.run()?, + Cmd::Start(cmd) => cmd.run().await?, + Cmd::Stop(cmd) => cmd.run().await?, }; Ok(()) } diff --git a/cmd/soroban-cli/src/commands/network/shared.rs b/cmd/soroban-cli/src/commands/network/shared.rs new file mode 100644 index 000000000..9da8a1bea --- /dev/null +++ b/cmd/soroban-cli/src/commands/network/shared.rs @@ -0,0 +1,150 @@ +use core::fmt; + +use bollard::{ClientVersion, Docker}; +use clap::ValueEnum; +#[allow(unused_imports)] +// Need to add this for windows, since we are only using this crate for the unix fn try_docker_desktop_socket +use home::home_dir; + +pub const DOCKER_HOST_HELP: &str = "Optional argument to override the default docker host. This is useful when you are using a non-standard docker host path for your Docker-compatible container runtime, e.g. Docker Desktop defaults to $HOME/.docker/run/docker.sock instead of /var/run/docker.sock"; + +// DEFAULT_DOCKER_HOST is from the bollard crate on the main branch, which has not been released yet: https://github.com/fussybeaver/bollard/blob/0972b1aac0ad5c08798e100319ddd0d2ee010365/src/docker.rs#L64 +#[cfg(unix)] +pub const DEFAULT_DOCKER_HOST: &str = "unix:///var/run/docker.sock"; + +#[cfg(windows)] +pub const DEFAULT_DOCKER_HOST: &str = "npipe:////./pipe/docker_engine"; + +// DEFAULT_TIMEOUT and API_DEFAULT_VERSION are from the bollard crate +const DEFAULT_TIMEOUT: u64 = 120; +const API_DEFAULT_VERSION: &ClientVersion = &ClientVersion { + major_version: 1, + minor_version: 40, +}; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("⛔ ️Failed to start container: {0}")] + BollardErr(#[from] bollard::errors::Error), + + #[error("URI scheme is not supported: {uri}")] + UnsupportedURISchemeError { uri: String }, +} + +#[derive(ValueEnum, Debug, Clone, PartialEq)] +pub enum Network { + Local, + Testnet, + Futurenet, + Pubnet, +} + +impl fmt::Display for Network { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let variant_str = match self { + Network::Local => "local", + Network::Testnet => "testnet", + Network::Futurenet => "futurenet", + Network::Pubnet => "pubnet", + }; + + write!(f, "{variant_str}") + } +} + +pub async fn connect_to_docker(docker_host: &Option) -> Result { + // if no docker_host is provided, use the default docker host: + // "unix:///var/run/docker.sock" on unix machines + // "npipe:////./pipe/docker_engine" on windows machines + + let host = docker_host + .clone() + .unwrap_or(DEFAULT_DOCKER_HOST.to_string()); + + // this is based on the `connect_with_defaults` method which has not yet been released in the bollard crate + // https://github.com/fussybeaver/bollard/blob/0972b1aac0ad5c08798e100319ddd0d2ee010365/src/docker.rs#L660 + let connection = match host.clone() { + // if tcp or http, use connect_with_http_defaults + // if unix and host starts with "unix://" use connect_with_unix + // if windows and host starts with "npipe://", use connect_with_named_pipe + // else default to connect_with_unix + h if h.starts_with("tcp://") || h.starts_with("http://") => { + Docker::connect_with_http_defaults() + } + #[cfg(unix)] + h if h.starts_with("unix://") => { + Docker::connect_with_unix(&h, DEFAULT_TIMEOUT, API_DEFAULT_VERSION) + } + #[cfg(windows)] + h if h.starts_with("npipe://") => { + Docker::connect_with_named_pipe(&h, DEFAULT_TIMEOUT, API_DEFAULT_VERSION) + } + _ => { + return Err(Error::UnsupportedURISchemeError { + uri: host.to_string(), + }); + } + }?; + + match check_docker_connection(&connection).await { + Ok(()) => Ok(connection), + // If we aren't able to connect with the defaults, or with the provided docker_host + // try to connect with the default docker desktop socket since that is a common use case for devs + #[allow(unused_variables)] + Err(e) => { + // if on unix, try to connect to the default docker desktop socket + #[cfg(unix)] + { + let docker_desktop_connection = try_docker_desktop_socket(&host)?; + match check_docker_connection(&docker_desktop_connection).await { + Ok(()) => Ok(docker_desktop_connection), + Err(err) => Err(err)?, + } + } + + #[cfg(windows)] + { + Err(e)? + } + } + } +} + +#[cfg(unix)] +fn try_docker_desktop_socket(host: &str) -> Result { + let default_docker_desktop_host = + format!("{}/.docker/run/docker.sock", home_dir().unwrap().display()); + println!("Failed to connect to DOCKER_HOST: {host}.\nTrying to connect to the default Docker Desktop socket at {default_docker_desktop_host}."); + + Docker::connect_with_unix( + &default_docker_desktop_host, + DEFAULT_TIMEOUT, + API_DEFAULT_VERSION, + ) +} + +// When bollard is not able to connect to the docker daemon, it returns a generic ConnectionRefused error +// This method attempts to connect to the docker daemon and returns a more specific error message +async fn check_docker_connection(docker: &Docker) -> Result<(), bollard::errors::Error> { + // This is a bit hacky, but the `client_addr` field is not directly accessible from the `Docker` struct, but we can access it from the debug string representation of the `Docker` struct + let docker_debug_string = format!("{docker:#?}"); + let start_of_client_addr = docker_debug_string.find("client_addr: ").unwrap(); + let end_of_client_addr = docker_debug_string[start_of_client_addr..] + .find(',') + .unwrap(); + // Extract the substring containing the value of client_addr + let client_addr = &docker_debug_string + [start_of_client_addr + "client_addr: ".len()..start_of_client_addr + end_of_client_addr] + .trim() + .trim_matches('"'); + + match docker.version().await { + Ok(_version) => Ok(()), + Err(err) => { + println!( + "⛔️ Failed to connect to the Docker daemon at {client_addr:?}. Is the docker daemon running?\nℹ️ Running a local Stellar network requires a Docker-compatible container runtime.\nℹ️ Please note that if you are using Docker Desktop, you may need to utilize the `--docker-host` flag to pass in the location of the docker socket on your machine.\n" + ); + Err(err) + } + } +} diff --git a/cmd/soroban-cli/src/commands/network/start.rs b/cmd/soroban-cli/src/commands/network/start.rs new file mode 100644 index 000000000..e4b6825ab --- /dev/null +++ b/cmd/soroban-cli/src/commands/network/start.rs @@ -0,0 +1,188 @@ +use std::collections::HashMap; + +use bollard::{ + container::{Config, CreateContainerOptions, StartContainerOptions}, + image::CreateImageOptions, + service::{HostConfig, PortBinding}, +}; +use futures_util::TryStreamExt; + +use crate::commands::network::shared::{ + connect_to_docker, Error as ConnectionError, Network, DOCKER_HOST_HELP, +}; + +const DEFAULT_PORT_MAPPING: &str = "8000:8000"; +const DOCKER_IMAGE: &str = "docker.io/stellar/quickstart"; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("⛔ ️Failed to connect to docker: {0}")] + ConnectionError(#[from] ConnectionError), + + #[error("⛔ ️Failed to create container: {0}")] + BollardErr(#[from] bollard::errors::Error), +} + +#[derive(Debug, clap::Parser, Clone)] +pub struct Cmd { + /// Network to start + pub network: Network, + + #[arg(short = 'd', long, help = DOCKER_HOST_HELP, env = "DOCKER_HOST")] + pub docker_host: Option, + + /// Optional argument to specify the limits for the local network only + #[arg(short = 'l', long)] + pub limits: Option, + + /// Argument to specify the HOST_PORT:CONTAINER_PORT mapping + #[arg(short = 'p', long, num_args = 1.., default_value = DEFAULT_PORT_MAPPING)] + pub ports_mapping: Vec, + + /// Optional argument to override the default docker image tag for the given network + #[arg(short = 't', long)] + pub image_tag_override: Option, + + /// Optional argument to specify the protocol version for the local network only + #[arg(short = 'v', long)] + pub protocol_version: Option, +} + +impl Cmd { + pub async fn run(&self) -> Result<(), Error> { + println!("ℹ️ Starting {} network", &self.network); + run_docker_command(self).await + } +} + +async fn run_docker_command(cmd: &Cmd) -> Result<(), Error> { + let docker = connect_to_docker(&cmd.docker_host).await?; + + let image = get_image_name(cmd); + docker + .create_image( + Some(CreateImageOptions { + from_image: image.clone(), + ..Default::default() + }), + None, + None, + ) + .try_collect::>() + .await?; + + let container_args = get_container_args(cmd); + let port_mapping = get_port_mapping(cmd); + + let config = Config { + image: Some(image), + cmd: Some(container_args), + attach_stdout: Some(true), + attach_stderr: Some(true), + host_config: Some(HostConfig { + auto_remove: Some(true), + port_bindings: Some(port_mapping), + ..Default::default() + }), + ..Default::default() + }; + + let container_name = format!("stellar-{}", cmd.network); + let create_container_response = docker + .create_container( + Some(CreateContainerOptions { + name: container_name.clone(), + ..Default::default() + }), + config, + ) + .await?; + + docker + .start_container( + &create_container_response.id, + None::>, + ) + .await?; + println!("✅ Container started: {container_name}"); + let stop_message = format!( + "ℹ️ To stop this container run: soroban network stop {network} {additional_flags}", + network = &cmd.network, + additional_flags = if cmd.docker_host.is_some() { + format!("--docker-host {}", cmd.docker_host.as_ref().unwrap()) + } else { + String::new() + } + ); + println!("{stop_message}"); + Ok(()) +} + +fn get_container_args(cmd: &Cmd) -> Vec { + [ + format!("--{}", cmd.network), + "--enable-soroban-rpc".to_string(), + get_protocol_version_arg(cmd), + get_limits_arg(cmd), + ] + .iter() + .filter(|&s| !s.is_empty()) + .cloned() + .collect() +} + +fn get_image_name(cmd: &Cmd) -> String { + // this can be overriden with the `-t` flag + let mut image_tag = match cmd.network { + Network::Testnet => "testing", + Network::Futurenet => "future", + _ => "latest", // default to latest for local and pubnet + }; + + if cmd.image_tag_override.is_some() { + let override_tag = cmd.image_tag_override.as_ref().unwrap(); + println!("Overriding docker image tag to use '{override_tag}' instead of '{image_tag}'"); + + image_tag = override_tag; + } + + format!("{DOCKER_IMAGE}:{image_tag}") +} + +// The port mapping in the bollard crate is formatted differently than the docker CLI. In the docker CLI, we usually specify exposed ports as `-p HOST_PORT:CONTAINER_PORT`. But with the bollard crate, it is expecting the port mapping to be a map of the container port (with the protocol) to the host port. +fn get_port_mapping(cmd: &Cmd) -> HashMap>> { + let mut port_mapping_hash = HashMap::new(); + for port_mapping in &cmd.ports_mapping { + let ports_vec: Vec<&str> = port_mapping.split(':').collect(); + let from_port = ports_vec[0]; + let to_port = ports_vec[1]; + + port_mapping_hash.insert( + format!("{to_port}/tcp"), + Some(vec![PortBinding { + host_ip: None, + host_port: Some(from_port.to_string()), + }]), + ); + } + + port_mapping_hash +} + +fn get_protocol_version_arg(cmd: &Cmd) -> String { + if cmd.network == Network::Local && cmd.protocol_version.is_some() { + let version = cmd.protocol_version.as_ref().unwrap(); + format!("--protocol-version {version}") + } else { + String::new() + } +} + +fn get_limits_arg(cmd: &Cmd) -> String { + if cmd.network == Network::Local && cmd.limits.is_some() { + let limits = cmd.limits.as_ref().unwrap(); + format!("--limits {limits}") + } else { + String::new() + } +} diff --git a/cmd/soroban-cli/src/commands/network/stop.rs b/cmd/soroban-cli/src/commands/network/stop.rs new file mode 100644 index 000000000..3a7443aed --- /dev/null +++ b/cmd/soroban-cli/src/commands/network/stop.rs @@ -0,0 +1,29 @@ +use crate::commands::network::shared::{ + connect_to_docker, Error as ConnectionError, Network, DOCKER_HOST_HELP, +}; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Failed to stop container: {0}")] + StopContainerError(#[from] ConnectionError), +} + +#[derive(Debug, clap::Parser, Clone)] +pub struct Cmd { + /// Network to stop + pub network: Network, + + #[arg(short = 'd', long, help = DOCKER_HOST_HELP, env = "DOCKER_HOST")] + pub docker_host: Option, +} + +impl Cmd { + pub async fn run(&self) -> Result<(), Error> { + let container_name = format!("stellar-{}", self.network); + let docker = connect_to_docker(&self.docker_host).await?; + println!("ℹ️ Stopping container: {container_name}"); + docker.stop_container(&container_name, None).await.unwrap(); + println!("✅ Container stopped: {container_name}"); + Ok(()) + } +} diff --git a/docs/soroban-cli-full-docs.md b/docs/soroban-cli-full-docs.md index f912eecb1..5600db277 100644 --- a/docs/soroban-cli-full-docs.md +++ b/docs/soroban-cli-full-docs.md @@ -11,6 +11,8 @@ This document contains the help content for the `soroban` command-line program. * [`soroban config network add`↴](#soroban-config-network-add) * [`soroban config network rm`↴](#soroban-config-network-rm) * [`soroban config network ls`↴](#soroban-config-network-ls) +* [`soroban config network start`↴](#soroban-config-network-start) +* [`soroban config network stop`↴](#soroban-config-network-stop) * [`soroban config identity`↴](#soroban-config-identity) * [`soroban config identity add`↴](#soroban-config-identity-add) * [`soroban config identity address`↴](#soroban-config-identity-address) @@ -65,6 +67,8 @@ This document contains the help content for the `soroban` command-line program. * [`soroban network add`↴](#soroban-network-add) * [`soroban network rm`↴](#soroban-network-rm) * [`soroban network ls`↴](#soroban-network-ls) +* [`soroban network start`↴](#soroban-network-start) +* [`soroban network stop`↴](#soroban-network-stop) * [`soroban version`↴](#soroban-version) ## `soroban` @@ -182,6 +186,8 @@ Configure different networks. Depraecated, use `soroban network` instead * `add` — Add a new network * `rm` — Remove a network * `ls` — List networks +* `start` — Start network +* `stop` — Stop a network started with `network start`. For example, if you ran `soroban network start local`, you can use `soroban network stop local` to stop it @@ -247,6 +253,56 @@ List networks +## `soroban config network start` + +Start network + +Start a container running a Stellar node, RPC, API, and friendbot (faucet). + +soroban network start [OPTIONS] + +By default, when starting a testnet container, without any optional arguments, it will run the equivalent of the following docker command: docker run --rm -p 8000:8000 --name stellar stellar/quickstart:testing --testnet --enable-soroban-rpc + +**Usage:** `soroban config network start [OPTIONS] ` + +###### **Arguments:** + +* `` — Network to start + + Possible values: `local`, `testnet`, `futurenet`, `pubnet` + + +###### **Options:** + +* `-d`, `--docker-host ` — Optional argument to override the default docker host. This is useful when you are using a non-standard docker host path for your Docker-compatible container runtime, e.g. Docker Desktop defaults to $HOME/.docker/run/docker.sock instead of /var/run/docker.sock +* `-l`, `--limits ` — Optional argument to specify the limits for the local network only +* `-p`, `--ports-mapping ` — Argument to specify the HOST_PORT:CONTAINER_PORT mapping + + Default value: `8000:8000` +* `-t`, `--image-tag-override ` — Optional argument to override the default docker image tag for the given network +* `-v`, `--protocol-version ` — Optional argument to specify the protocol version for the local network only + + + +## `soroban config network stop` + +Stop a network started with `network start`. For example, if you ran `soroban network start local`, you can use `soroban network stop local` to stop it + +**Usage:** `soroban config network stop [OPTIONS] ` + +###### **Arguments:** + +* `` — Network to stop + + Possible values: `local`, `testnet`, `futurenet`, `pubnet` + + +###### **Options:** + +* `-d`, `--docker-host ` — Optional argument to override the default docker host. This is useful when you are using a non-standard docker host path for your Docker-compatible container runtime, e.g. Docker Desktop defaults to $HOME/.docker/run/docker.sock instead of /var/run/docker.sock + + + ## `soroban config identity` Identity management. Deprecated, use `soroban keys` instead @@ -1502,6 +1558,8 @@ Start and configure networks * `add` — Add a new network * `rm` — Remove a network * `ls` — List networks +* `start` — Start network +* `stop` — Stop a network started with `network start`. For example, if you ran `soroban network start local`, you can use `soroban network stop local` to stop it @@ -1567,6 +1625,56 @@ List networks +## `soroban network start` + +Start network + +Start a container running a Stellar node, RPC, API, and friendbot (faucet). + +soroban network start [OPTIONS] + +By default, when starting a testnet container, without any optional arguments, it will run the equivalent of the following docker command: docker run --rm -p 8000:8000 --name stellar stellar/quickstart:testing --testnet --enable-soroban-rpc + +**Usage:** `soroban network start [OPTIONS] ` + +###### **Arguments:** + +* `` — Network to start + + Possible values: `local`, `testnet`, `futurenet`, `pubnet` + + +###### **Options:** + +* `-d`, `--docker-host ` — Optional argument to override the default docker host. This is useful when you are using a non-standard docker host path for your Docker-compatible container runtime, e.g. Docker Desktop defaults to $HOME/.docker/run/docker.sock instead of /var/run/docker.sock +* `-l`, `--limits ` — Optional argument to specify the limits for the local network only +* `-p`, `--ports-mapping ` — Argument to specify the HOST_PORT:CONTAINER_PORT mapping + + Default value: `8000:8000` +* `-t`, `--image-tag-override ` — Optional argument to override the default docker image tag for the given network +* `-v`, `--protocol-version ` — Optional argument to specify the protocol version for the local network only + + + +## `soroban network stop` + +Stop a network started with `network start`. For example, if you ran `soroban network start local`, you can use `soroban network stop local` to stop it + +**Usage:** `soroban network stop [OPTIONS] ` + +###### **Arguments:** + +* `` — Network to stop + + Possible values: `local`, `testnet`, `futurenet`, `pubnet` + + +###### **Options:** + +* `-d`, `--docker-host ` — Optional argument to override the default docker host. This is useful when you are using a non-standard docker host path for your Docker-compatible container runtime, e.g. Docker Desktop defaults to $HOME/.docker/run/docker.sock instead of /var/run/docker.sock + + + ## `soroban version` Print version information