diff --git a/Cargo.lock b/Cargo.lock index ad55506082..412ab7bfa0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -540,7 +540,6 @@ dependencies = [ name = "astria-cli" version = "0.3.1" dependencies = [ - "assert_cmd", "astria-core", "astria-sequencer-client", "clap", @@ -550,7 +549,6 @@ dependencies = [ "serde", "serde_yaml", "sha2 0.10.8", - "test-utils", "tokio", "tracing", "which", @@ -7671,15 +7669,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" -[[package]] -name = "test-utils" -version = "0.1.0" -dependencies = [ - "once_cell", - "tempfile", - "tokio", -] - [[package]] name = "tester" version = "0.9.1" diff --git a/crates/astria-cli/Cargo.toml b/crates/astria-cli/Cargo.toml index 0e2690babc..f9717fde75 100644 --- a/crates/astria-cli/Cargo.toml +++ b/crates/astria-cli/Cargo.toml @@ -30,7 +30,3 @@ which = { workspace = true } package = "astria-sequencer-client" path = "../astria-sequencer-client" features = ["http"] - -[dev-dependencies] -assert_cmd = "2.0.12" -test-utils = { path = "./test-utils" } diff --git a/crates/astria-cli/README.md b/crates/astria-cli/README.md index 151a695914..31e365a949 100644 --- a/crates/astria-cli/README.md +++ b/crates/astria-cli/README.md @@ -1,17 +1,11 @@ # Astria CLI -Astria CLI is a command line tool for interacting with the Sequencer network -and for managing your own rollup deployments. You can create a -Sequencer account, check balances, generate rollup deployment configurations, -deploy rollups, and more. +Astria CLI is a command line tool for interacting with the Sequencer network. +You can create a Sequencer account, check balances, and more. ## Dependencies * rust - -* docker - -* kubectl - -* kind - -* helm - ## Setup @@ -32,44 +26,6 @@ cargo build --release # create account on Sequencer ./target/release/astria-cli sequencer account create -# create a rollup config -./target/release/astria-cli rollup config create \ - --use-tty \ - --log-level DEBUG \ - --rollup.name steezechain \ - --rollup.network-id 42 \ - --rollup.genesis-accounts 0xaC21B97d35Bf75A7dAb16f35b111a50e78A72F30:100000000000000000000 - -# edit config -./target/release/astria-cli rollup config edit \ - --config somerollupname-rollup-config.yaml - - -# delete config -./target/release/astria-cli rollup config delete \ - --config somerollupname-rollup-config.yaml - -# create deployment from config -# FAUCET_PRIVATE_KEY - 64 character hex string. private key of account used to -# fund the faucet. This will often be the private key of an address used in -# the `rollup.genesis-accounts` argument for `rollup config create` above. -# SEQUENCER_PRIVATE_KEY - 64 character hex string. private key of account used -# to wrap transactions for submission to the sequencer. -./target/release/astria-cli rollup deployment create \ - --config somerollupname-rollup-config.yaml \ - --faucet-private-key \ - --sequencer-private-key - -# NOTE - you can also run `deployment create` with `--dry-run` to see the -# generated k8s yaml without actually creating the deployment - -# list deployments -./target/release/astria-cli rollup deployment list - -# delete deployment -./target/release/astria-cli rollup deployment delete \ - --config somerollupname-rollup-config.yaml - # get balance of account on Sequencer ./target/release/astria-cli sequencer balance get
\ --sequencer_url diff --git a/crates/astria-cli/justfile b/crates/astria-cli/justfile deleted file mode 100644 index 0588c54643..0000000000 --- a/crates/astria-cli/justfile +++ /dev/null @@ -1,11 +0,0 @@ -default: - @just --list - -set dotenv-load -set fallback - -run: - cargo run - -test: - cargo test -- --nocapture --color always diff --git a/crates/astria-cli/src/cli/mod.rs b/crates/astria-cli/src/cli/mod.rs index f2c2b2d22e..f4d07e4878 100644 --- a/crates/astria-cli/src/cli/mod.rs +++ b/crates/astria-cli/src/cli/mod.rs @@ -1,4 +1,3 @@ -pub(crate) mod rollup; pub(crate) mod sequencer; use clap::{ @@ -7,10 +6,7 @@ use clap::{ }; use color_eyre::eyre; -use crate::cli::{ - rollup::Command as RollupCommand, - sequencer::Command as SequencerCommand, -}; +use crate::cli::sequencer::Command as SequencerCommand; const DEFAULT_SEQUENCER_RPC: &str = "https://rpc.sequencer.dusk-7.devnet.astria.org"; const DEFAULT_SEQUENCER_CHAIN_ID: &str = "astria-dusk-7"; @@ -38,10 +34,6 @@ impl Cli { /// Commands that can be run #[derive(Debug, Subcommand)] pub enum Command { - Rollup { - #[command(subcommand)] - command: RollupCommand, - }, Sequencer { #[command(subcommand)] command: SequencerCommand, diff --git a/crates/astria-cli/src/commands/mod.rs b/crates/astria-cli/src/commands/mod.rs index 6336de004a..f4f7814e78 100644 --- a/crates/astria-cli/src/commands/mod.rs +++ b/crates/astria-cli/src/commands/mod.rs @@ -1,4 +1,3 @@ -mod rollup; mod sequencer; use color_eyre::{ @@ -8,11 +7,6 @@ use color_eyre::{ use tracing::instrument; use crate::cli::{ - rollup::{ - Command as RollupCommand, - ConfigCommand, - DeploymentCommand, - }, sequencer::{ AccountCommand, AddressCommand, @@ -44,24 +38,6 @@ use crate::cli::{ pub async fn run(cli: Cli) -> eyre::Result<()> { if let Some(command) = cli.command { match command { - Command::Rollup { - command, - } => match command { - RollupCommand::Config { - command, - } => match command { - ConfigCommand::Create(args) => rollup::create_config(&args).await?, - ConfigCommand::Edit(args) => rollup::edit_config(&args)?, - ConfigCommand::Delete(args) => rollup::delete_config(&args)?, - }, - RollupCommand::Deployment { - command, - } => match command { - DeploymentCommand::Create(args) => rollup::create_deployment(&args)?, - DeploymentCommand::Delete(args) => rollup::delete_deployment(&args)?, - DeploymentCommand::List => rollup::list_deployments(), - }, - }, Command::Sequencer { command, } => match command { diff --git a/crates/astria-cli/src/commands/rollup.rs b/crates/astria-cli/src/commands/rollup.rs deleted file mode 100644 index b94771226d..0000000000 --- a/crates/astria-cli/src/commands/rollup.rs +++ /dev/null @@ -1,464 +0,0 @@ -use std::{ - env::{ - self, - consts::OS, - }, - fs::File, - io::{ - Read, - Write, - }, - path::PathBuf, - process::Command, -}; - -use astria_sequencer_client::{ - Client, - HttpClient, -}; -use color_eyre::{ - eyre, - eyre::Context, -}; - -use crate::{ - cli::rollup::{ - ConfigCreateArgs, - ConfigDeleteArgs, - ConfigEditArgs, - DeploymentCreateArgs, - DeploymentDeleteArgs, - }, - types::Rollup, -}; - -/// Returns the path to the `helm` binary -fn helm_from_env() -> PathBuf { - let os_specific_hint = match OS { - "macos" => "You could try running `brew install helm` or downloading a recent release from https://github.com/helm/helm/releases", - "linux" => "You can download it from https://github.com/helm/helm/releases", - _other => "Check if there is a precompiled version for your OS at https://github.com/helm/helm/releases" - }; - let error_msg = "Could not find `helm` installation and this deployment cannot proceed without - this knowledge. If `helm` is installed and this crate had trouble finding - it, you can set the `HELM` environment variable with the specific path to your - installed `helm` binary."; - let msg = format!("{error_msg} {os_specific_hint}"); - - env::var_os("HELM") - .map(PathBuf::from) - .or_else(|| which::which("helm").ok()) - .expect(&msg) -} - -/// Updates a key in a yaml file with a new value. -/// -/// # Arguments -/// -/// * `value` - The yaml to update -/// * `key` - The key to update. Can be nested using dot notation. -/// * `new_value` - The new value to set the key to -/// -/// # Errors -/// -/// * If the key path is invalid -/// * If the last key is invalid, e.g. `a.b.c` where `c` does not exist -/// * If the last key is not a string, e.g. `a.b.0` is incorrect -/// * If the yaml cannot be updated -fn update_yaml_value( - value: &mut serde_yaml::Value, - key: &str, - new_value: &str, -) -> eyre::Result<()> { - let mut target = value; - - let keys: Vec<&str> = key.split('.').collect(); - - let keys_len_minus_one = keys - .len() - .checked_sub(1) - .expect("`key.split()` should always return at least one value"); - for &key in keys.iter().take(keys_len_minus_one) { - target = target - .get_mut(key) - .ok_or_else(|| eyre::eyre!("Invalid key path: {}", key))?; - } - - let last_key = keys - .last() - .ok_or_else(|| eyre::eyre!("Key path is empty"))?; - - if let Some(v) = target.get_mut(*last_key) { - *v = serde_yaml::Value::String(new_value.to_string()); - } else { - return Err(eyre::eyre!("Invalid last key: {}", last_key)); - } - Ok(()) -} - -/// Create a new rollup config file in the calling directory. -/// -/// # Arguments -/// -/// * `args` - The arguments passed to the command -/// -/// # Errors -/// -/// * If the config file cannot be created -/// * If the arguments cannot be serialized to yaml -/// * If the yaml cannot be written to the file -pub(crate) async fn create_config(args: &ConfigCreateArgs) -> eyre::Result<()> { - // create rollup from args - let mut conf = args.clone(); - - // Fetch the latest block from sequencer if none specified. - if conf.sequencer_initial_block_height.is_none() { - let sequencer_client = HttpClient::new(conf.sequencer_rpc.as_str()) - .wrap_err("failed constructing http sequencer client")?; - let res = sequencer_client - .latest_block() - .await - .wrap_err("failed to get sequencer block for initial sequencer height")?; - - let new_height: u64 = res.block.header.height.into(); - conf.sequencer_initial_block_height = Some(new_height); - } - - let rollup = Rollup::try_from(&conf)?; - let filename = rollup.deployment_config.get_filename(); - - // create config file - let mut output = File::create(&filename)?; - - // write args as yaml - let yaml_str: String = rollup.try_into()?; - write!(output, "{yaml_str}")?; - - println!("Created rollup config file {filename}"); - - Ok(()) -} - -/// Deletes a config file -/// -/// # Arguments -/// -/// * `args` - The arguments passed to the command -/// -/// # Errors -/// -/// * If the config file cannot be deleted -pub(crate) fn delete_config(args: &ConfigDeleteArgs) -> eyre::Result<()> { - let path = PathBuf::from(args.config_path.clone()); - std::fs::remove_file(path).wrap_err("could not delete the config file")?; - - println!("Deleted rollup config file {}", args.config_path); - - Ok(()) -} - -pub(crate) fn edit_config(args: &ConfigEditArgs) -> eyre::Result<()> { - // get file contents - let path = PathBuf::from(&args.config_path); - let mut file = File::open(&path)?; - let mut contents = String::new(); - file.read_to_string(&mut contents)?; - - let mut yaml_value: serde_yaml::Value = serde_yaml::from_str(&contents)?; - update_yaml_value(&mut yaml_value, &args.key, &args.value)?; - - // Write the updated YAML back to the file - let updated_yaml = serde_yaml::to_string(&yaml_value)?; - let mut file = File::create(&path)?; - file.write_all(updated_yaml.as_bytes())?; - - Ok(()) -} - -/// Creates a deployment from a config file -/// -/// # Arguments -/// -/// * `args` - The arguments passed to the command -/// -/// # Errors -/// -/// -/// * If the config file cannot be opened -/// * If the config file cannot be deserialized -/// * If the deployment cannot be created -/// * If the helm command fails -pub(crate) fn create_deployment(args: &DeploymentCreateArgs) -> eyre::Result<()> { - let path = PathBuf::from(args.config_path.clone()); - let file = File::open(path)?; - let rollup: Rollup = serde_yaml::from_reader(file)?; - - // call `helm install` with appropriate args. - // setting values via the generated config file. - let helm = helm_from_env(); - let mut cmd = Command::new(helm.clone()); - cmd.arg("install") - .arg("--values") - .arg(rollup.deployment_config.get_filename()) - // TODO: https://github.com/astriaorg/astria/issues/594 - // Use a secret manager or inject the private key into the environment - .arg("--set") - .arg(format!( - "config.faucet.privateKey.devContent={}", - args.faucet_private_key.clone() - )) - // TODO: https://github.com/astriaorg/astria/issues/594 - // Use a secret manager or inject the private key into the environment - .arg("--set") - .arg(format!( - "config.sequencer.privateKey.devContent={}", - args.sequencer_private_key.clone() - )) - .arg(rollup.deployment_config.get_chart_release_name()) - .arg(&args.chart_path) - .arg(format!("--namespace={}", rollup.globals_config.namespace)) - .arg("--create-namespace"); - - if args.dry_run { - cmd.arg("--dry-run"); - } - - if args.debug { - cmd.arg("--debug"); - } - - match cmd.output() { - Err(e) => { - panic!("failed deploying config: failed to invoke helm (path: {helm:?}): {e:?}"); - } - Ok(output) if !output.status.success() => { - panic!( - "failed deploying config: `helm` returned error: {}", - String::from_utf8_lossy(&output.stderr) - ); - } - Ok(output) => { - // print output - println!("{}", String::from_utf8_lossy(&output.stdout)); - } - }; - - Ok(()) -} - -/// Deletes a deployment -/// -/// # Arguments -/// -/// * `args` - The arguments passed to the command -/// -/// # Errors -/// -/// * If the config file cannot be opened -/// * If the config file cannot be deserialized -/// * If the deployment cannot be deleted -/// * If the helm command fails -pub(crate) fn delete_deployment(args: &DeploymentDeleteArgs) -> eyre::Result<()> { - let path = PathBuf::from(args.config_path.clone()); - let file = File::open(path)?; - let rollup: Rollup = serde_yaml::from_reader(file)?; - - // call `helm uninstall` with appropriate args - let helm = helm_from_env(); - let mut cmd = Command::new(helm.clone()); - cmd.arg("uninstall") - .arg(rollup.deployment_config.get_chart_release_name()) - .arg(format!("--namespace={}", rollup.globals_config.namespace)); - - match cmd.output() { - Err(e) => { - panic!("failed deleting config: failed to invoke helm (path: {helm:?}): {e:?}"); - } - Ok(output) if !output.status.success() => { - panic!( - "failed deleting config: `helm` returned error: {}", - String::from_utf8_lossy(&output.stderr) - ); - } - Ok(_) => { - println!( - "Deleted deployment created from rollup config {}", - args.config_path - ); - } - }; - - Ok(()) -} - -/// Lists all deployments -/// -/// # Errors -/// -/// * If the helm command fails -pub(crate) fn list_deployments() { - // call `helm list` with appropriate args - let helm = helm_from_env(); - let mut cmd = Command::new(helm.clone()); - // FIXME - right now it lists all helm releases, not just rollup release - cmd.arg("list").arg("-A"); - - match cmd.output() { - Err(e) => { - panic!("failed listing deployments: failed to invoke helm (path: {helm:?}): {e:?}"); - } - Ok(output) if !output.status.success() => { - panic!( - "failed listing deployments: `helm` returned error: {}", - String::from_utf8_lossy(&output.stderr) - ); - } - Ok(output) => { - // print output - println!("{}", String::from_utf8_lossy(&output.stdout)); - } - }; -} - -#[cfg(test)] -mod test { - use test_utils::with_temp_directory; - - use super::*; - - fn get_config_create_args() -> ConfigCreateArgs { - ConfigCreateArgs { - use_tty: false, - name: "test".to_string(), - network_id: 0, - execution_commit_level: "SoftOnly".to_string(), - override_genesis_extra_data: false, - bridge_address: None, - bridge_allowed_asset_denom: "nria".to_string(), - genesis_accounts: vec![], - sequencer_initial_block_height: Some(1), - sequencer_grpc: String::new(), - sequencer_rpc: String::new(), - sequencer_chain_id: "test-chain-1".to_string(), - log_level: String::new(), - hostname: String::new(), - namespace: "namespace_test".to_string(), - enable_celestia_node: false, - } - } - - #[tokio::test] - async fn test_create_config_file() { - with_temp_directory(|_dir| async { - let args = get_config_create_args(); - create_config(&args).await.unwrap(); - - let file_path = PathBuf::from("test-rollup-conf.yaml"); - assert!(file_path.exists()); - - let file = File::open(&file_path).unwrap(); - let rollup: Rollup = serde_yaml::from_reader(file).unwrap(); - assert_eq!(rollup.globals_config.namespace, args.namespace); - assert_eq!(rollup.deployment_config.get_rollup_name(), args.name); - }) - .await; - } - - #[tokio::test] - async fn test_delete_config_file() { - with_temp_directory(|_dir| async { - let file_path = PathBuf::from("test-rollup-conf.yaml"); - File::create(&file_path).unwrap(); - - let args = ConfigDeleteArgs { - config_path: file_path.to_str().unwrap().to_string(), - }; - delete_config(&args).unwrap(); - assert!(!file_path.exists()); - }) - .await; - } - - #[tokio::test] - async fn test_edit_config_file() { - with_temp_directory(|_dir| async { - let args = get_config_create_args(); - create_config(&args).await.unwrap(); - - let file_path = PathBuf::from("test-rollup-conf.yaml"); - let args = ConfigEditArgs { - config_path: file_path.to_str().unwrap().to_string(), - key: "config.rollup.name".to_string(), - value: "bugbug".to_string(), - }; - edit_config(&args).unwrap(); - - let file = File::open(&file_path).unwrap(); - let rollup: Rollup = serde_yaml::from_reader(file).unwrap(); - assert_eq!(rollup.deployment_config.get_rollup_name(), "bugbug"); - }) - .await; - } - - #[tokio::test] - async fn test_edit_config_file_errors_for_wrong_key() { - with_temp_directory(|_dir| async { - let args = get_config_create_args(); - create_config(&args).await.unwrap(); - - let file_path = PathBuf::from("test-rollup-conf.yaml"); - let args = ConfigEditArgs { - config_path: file_path.to_str().unwrap().to_string(), - key: "config.blahblah".to_string(), - value: "bugbug".to_string(), - }; - assert!(edit_config(&args).is_err()); - }) - .await; - } - - #[test] - fn test_update_yaml_value() { - let mut yaml_value: serde_yaml::Value = serde_yaml::from_str( - r" - config: - rollup: - name: test - ", - ) - .unwrap(); - - update_yaml_value(&mut yaml_value, "config.rollup.name", "bugbug").unwrap(); - - let updated: serde_yaml::Value = serde_yaml::from_str( - " - config: - rollup: - name: bugbug - ", - ) - .unwrap(); - assert_eq!(yaml_value, updated); - } - - #[test] - fn test_update_yaml_value_errors() { - let mut yaml_value: serde_yaml::Value = serde_yaml::from_str( - r" - config: - rollup: - name: test - ", - ) - .unwrap(); - - // key doesn't exist - assert!(update_yaml_value(&mut yaml_value, "nonexistent", "bugbug").is_err()); - assert!(update_yaml_value(&mut yaml_value, "config.blah", "bugbug").is_err()); - assert!(update_yaml_value(&mut yaml_value, "config.rollup.name.blah", "bugbug").is_err()); - // invalid last key - assert!(update_yaml_value(&mut yaml_value, "config.rollup.", "bugbug").is_err()); - assert!(update_yaml_value(&mut yaml_value, "config.rollup.0", "bugbug").is_err()); - assert!(update_yaml_value(&mut yaml_value, "config.rollup.[0]", "bugbug").is_err()); - } -} diff --git a/crates/astria-cli/src/lib.rs b/crates/astria-cli/src/lib.rs index 2c16dcbda6..18a4aecb56 100644 --- a/crates/astria-cli/src/lib.rs +++ b/crates/astria-cli/src/lib.rs @@ -1,3 +1,2 @@ pub mod cli; pub mod commands; -pub mod types; diff --git a/crates/astria-cli/src/types.rs b/crates/astria-cli/src/types.rs deleted file mode 100644 index 773281f3cd..0000000000 --- a/crates/astria-cli/src/types.rs +++ /dev/null @@ -1,503 +0,0 @@ -use color_eyre::eyre; -use serde::{ - Deserialize, - Serialize, -}; - -use crate::cli::rollup::{ - ConfigCreateArgs, - GenesisAccountArg, -}; - -/// Rollup contains the deployment config for a rollup -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Rollup { - #[serde(rename = "global")] - pub(crate) globals_config: GlobalsConfig, - #[serde(rename = "config")] - pub(crate) deployment_config: RollupDeploymentConfig, - #[serde(rename = "ingress")] - pub(crate) ingress_config: IngressConfig, - #[serde(rename = "celestia-node")] - pub(crate) celestia_node: CelestiaNode, - #[serde(rename = "resources")] - pub(crate) resources: CoreResources, -} - -impl TryFrom<&ConfigCreateArgs> for Rollup { - type Error = eyre::Report; - - fn try_from(args: &ConfigCreateArgs) -> eyre::Result { - let globals_config = GlobalsConfig::from(args); - let deployment_config = RollupDeploymentConfig::try_from(args)?; - let ingress_config = IngressConfig::from(args); - let celestia_node = CelestiaNode::from(args); - let resources = CoreResources::default(); - - Ok(Self { - globals_config, - deployment_config, - ingress_config, - celestia_node, - resources, - }) - } -} - -impl TryInto for Rollup { - type Error = eyre::Report; - - /// Serializes Rollup to a yaml string - fn try_into(self) -> eyre::Result { - let yaml_str = serde_yaml::to_string(&self)?; - Ok(yaml_str) - } -} - -/// Describes a rollup deployment config. Serializes to a yaml file for usage with Helm, -/// thus the `rename_all = "camelCase"` naming convention. -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RollupDeploymentConfig { - rollup: RollupConfig, - sequencer: SequencerConfig, -} - -impl RollupDeploymentConfig { - #[must_use] - pub fn get_filename(&self) -> String { - format!("{}-rollup-conf.yaml", self.rollup.name) - } - - #[must_use] - pub fn get_chart_release_name(&self) -> String { - format!("{}-rollup", self.rollup.name) - } - - #[must_use] - pub fn get_rollup_name(&self) -> String { - self.rollup.name.clone() - } -} - -/// Describes the ingress config for the rollup chart. -/// -/// Serializes to a yaml file for usage with Helm, thus the -/// `rename_all = "camelCase"` naming convention. -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct IngressConfig { - hostname: String, -} - -impl From<&ConfigCreateArgs> for IngressConfig { - fn from(args: &ConfigCreateArgs) -> Self { - Self { - hostname: args.hostname.clone(), - } - } -} - -/// Describes the globals used for rollup chart. -/// -/// Serializes to a yaml file for usage with Helm, thus the -/// `rename_all = "camelCase"` naming convention. -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct GlobalsConfig { - pub(crate) namespace: String, - #[serde(rename = "useTTY")] - use_tty: bool, - log_level: String, -} - -impl From<&ConfigCreateArgs> for GlobalsConfig { - fn from(args: &ConfigCreateArgs) -> Self { - Self { - namespace: args.namespace.clone(), - use_tty: args.use_tty, - log_level: args.log_level.clone(), - } - } -} - -/// Describes the values for Celestia Node helm chart, which is a dependency -/// of the rollup chart. -/// -/// Serializes to a yaml file for usage with Helm, thus the -/// `rename_all = "camelCase"` naming convention. -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CelestiaNode { - enabled: bool, - #[serde(rename = "config")] - celestia_node_config: CelestiaNodeConfig, -} - -impl From<&ConfigCreateArgs> for CelestiaNode { - fn from(args: &ConfigCreateArgs) -> Self { - let celestia_node_config = CelestiaNodeConfig::from(args); - - Self { - enabled: args.enable_celestia_node, - celestia_node_config, - } - } -} - -/// Describes the configuration for a Celestia Node values. -/// -/// Serializes to a yaml file for usage with Helm, thus the -/// `rename_all = "camelCase"` naming convention. -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CelestiaNodeConfig { - label_prefix: String, -} - -impl From<&ConfigCreateArgs> for CelestiaNodeConfig { - fn from(args: &ConfigCreateArgs) -> Self { - Self { - label_prefix: args.name.to_string(), - } - } -} - -impl TryFrom<&ConfigCreateArgs> for RollupDeploymentConfig { - type Error = eyre::Report; - - fn try_from(args: &ConfigCreateArgs) -> eyre::Result { - // Set to block 2 if nothing set. - let sequencer_initial_block_height = args.sequencer_initial_block_height.unwrap_or(2); - - let genesis_accounts = args - .genesis_accounts - .clone() - .into_iter() - .map(GenesisAccount::from) - .collect(); - - Ok(Self { - rollup: RollupConfig { - name: args.name.clone(), - network_id: args.network_id.to_string(), - execution_commit_level: args.execution_commit_level.to_string(), - genesis: GenesisConfig { - override_genesis_extra_data: args.override_genesis_extra_data, - bridge_address: args.bridge_address.clone(), - bridge_allowed_asset_denom: args.bridge_allowed_asset_denom.clone(), - alloc: genesis_accounts, - }, - }, - sequencer: SequencerConfig { - initial_block_height: sequencer_initial_block_height.to_string(), - grpc: args.sequencer_grpc.clone(), - rpc: args.sequencer_rpc.clone(), - chain_id: args.sequencer_chain_id.clone(), - }, - }) - } -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RollupConfig { - name: String, - // NOTE - String here because yaml will serialize large ints w/ scientific notation - network_id: String, - execution_commit_level: String, - genesis: GenesisConfig, -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct GenesisConfig { - override_genesis_extra_data: bool, - #[serde(skip_serializing_if = "Option::is_none")] - bridge_address: Option, - bridge_allowed_asset_denom: String, - alloc: Vec, -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -struct GenesisAccount { - address: String, - value: GenesisAccountValue, -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -struct GenesisAccountValue { - // NOTE - string because yaml will serialize large ints w/ scientific notation - balance: String, -} - -impl From for GenesisAccount { - fn from(arg: GenesisAccountArg) -> Self { - Self { - address: arg.address, - value: GenesisAccountValue { - balance: arg.balance.to_string(), - }, - } - } -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -struct SequencerConfig { - // NOTE - string because yaml will serialize large ints w/ scientific notation - initial_block_height: String, - rpc: String, - grpc: String, - chain_id: String, -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -pub struct CoreResources { - conductor: ServiceResources, - composer: ServiceResources, - geth: ServiceResources, -} - -impl CoreResources { - fn default() -> Self { - Self { - conductor: ServiceResources::default_low(), - composer: ServiceResources::default_low(), - geth: ServiceResources::default_high(), - } - } -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -struct ServiceResources { - requests: Resource, - limits: Resource, -} - -impl ServiceResources { - fn default_low() -> Self { - Self { - requests: Resource::default_low_request(), - limits: Resource::default_low_limit(), - } - } - - fn default_high() -> Self { - Self { - requests: Resource::default_high_request(), - limits: Resource::default_high_limit(), - } - } -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -struct Resource { - cpu: f32, - memory: String, -} - -impl Resource { - fn default_low_request() -> Self { - Self { - cpu: 0.01, - memory: "1Mi".to_string(), - } - } - - fn default_low_limit() -> Self { - Self { - cpu: 0.1, - memory: "20Mi".to_string(), - } - } - - fn default_high_request() -> Self { - Self { - cpu: 0.25, - memory: "256Mi".to_string(), - } - } - - fn default_high_limit() -> Self { - Self { - cpu: 1.0, - memory: "1Gi".to_string(), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::cli::rollup::{ - ConfigCreateArgs, - GenesisAccountArg, - }; - - #[test] - fn test_from_all_cli_args() -> eyre::Result<()> { - // Case 1: All args provided - let args = ConfigCreateArgs { - use_tty: true, - log_level: "debug".to_string(), - name: "rollup1".to_string(), - network_id: 1, - execution_commit_level: "SoftOnly".to_string(), - override_genesis_extra_data: false, - bridge_address: None, - bridge_allowed_asset_denom: "nria".to_string(), - genesis_accounts: vec![ - GenesisAccountArg { - address: "0xA5TR14".to_string(), - balance: 1_000_000_000_000_000_000, - }, - GenesisAccountArg { - address: "0x420XYZ69".to_string(), - balance: 420, - }, - ], - sequencer_initial_block_height: Some(127_689_000_000), - sequencer_grpc: "http://localhost:8080".to_string(), - sequencer_rpc: "http://localhost:8081".to_string(), - sequencer_chain_id: "test-chain-1".to_string(), - hostname: "test.com".to_string(), - namespace: "test-cluster".to_string(), - enable_celestia_node: false, - }; - - let expected_config = Rollup { - globals_config: GlobalsConfig { - use_tty: true, - namespace: "test-cluster".to_string(), - log_level: "debug".to_string(), - }, - deployment_config: RollupDeploymentConfig { - rollup: RollupConfig { - name: "rollup1".to_string(), - network_id: "1".to_string(), - execution_commit_level: "SoftOnly".to_string(), - genesis: GenesisConfig { - override_genesis_extra_data: false, - bridge_address: None, - bridge_allowed_asset_denom: "nria".to_string(), - alloc: vec![ - GenesisAccount { - address: "0xA5TR14".to_string(), - value: GenesisAccountValue { - balance: "1000000000000000000".to_string(), - }, - }, - GenesisAccount { - address: "0x420XYZ69".to_string(), - value: GenesisAccountValue { - balance: "420".to_string(), - }, - }, - ], - }, - }, - sequencer: SequencerConfig { - initial_block_height: "127689000000".to_string(), - grpc: "http://localhost:8080".to_string(), - rpc: "http://localhost:8081".to_string(), - chain_id: "test-chain-1".to_string(), - }, - }, - ingress_config: IngressConfig { - hostname: "test.com".to_string(), - }, - celestia_node: CelestiaNode { - enabled: false, - celestia_node_config: CelestiaNodeConfig { - label_prefix: "rollup1".to_string(), - }, - }, - resources: CoreResources::default(), - }; - - let result = Rollup::try_from(&args)?; - assert_eq!(result, expected_config); - - Ok(()) - } - - #[test] - fn test_from_minimum_cli_args() -> eyre::Result<()> { - // No `Option` wrapped args provided. Tests defaults that are decided - // explicitly in the `try_from` impl. - // NOTE - there are some defaults that are handled in the arg struct, - // like the sequencer ws and rpc urls, so we still must pass them in here. - let args = ConfigCreateArgs { - use_tty: false, - log_level: "info".to_string(), - name: "rollup2".to_string(), - network_id: 2_211_011_801, - execution_commit_level: "SoftOnly".to_string(), - override_genesis_extra_data: false, - bridge_address: None, - bridge_allowed_asset_denom: "nria".to_string(), - genesis_accounts: vec![GenesisAccountArg { - address: "0xA5TR14".to_string(), - balance: 10000, - }], - sequencer_initial_block_height: None, - sequencer_grpc: "http://localhost:8082".to_string(), - sequencer_rpc: "http://localhost:8083".to_string(), - sequencer_chain_id: "test-chain-1".to_string(), - hostname: "localdev.me".to_string(), - namespace: "astria-dev-cluster".to_string(), - enable_celestia_node: false, - }; - - let expected_config = Rollup { - globals_config: GlobalsConfig { - use_tty: false, - namespace: "astria-dev-cluster".to_string(), - log_level: "info".to_string(), - }, - deployment_config: RollupDeploymentConfig { - rollup: RollupConfig { - name: "rollup2".to_string(), - network_id: "2211011801".to_string(), - execution_commit_level: "SoftOnly".to_string(), - genesis: GenesisConfig { - override_genesis_extra_data: false, - bridge_address: None, - bridge_allowed_asset_denom: "nria".to_string(), - alloc: vec![GenesisAccount { - address: "0xA5TR14".to_string(), - value: GenesisAccountValue { - balance: "10000".to_string(), - }, - }], - }, - }, - sequencer: SequencerConfig { - initial_block_height: "2".to_string(), // Default value - grpc: "http://localhost:8082".to_string(), - rpc: "http://localhost:8083".to_string(), - chain_id: "test-chain-1".to_string(), - }, - }, - ingress_config: IngressConfig { - hostname: "localdev.me".to_string(), - }, - celestia_node: CelestiaNode { - enabled: false, - celestia_node_config: CelestiaNodeConfig { - label_prefix: "rollup2".to_string(), - }, - }, - resources: CoreResources::default(), - }; - - let result = Rollup::try_from(&args)?; - assert_eq!(result, expected_config); - - Ok(()) - } -} diff --git a/crates/astria-cli/test-utils/Cargo.toml b/crates/astria-cli/test-utils/Cargo.toml deleted file mode 100644 index 3ae5a38254..0000000000 --- a/crates/astria-cli/test-utils/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "test-utils" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -once_cell = { workspace = true } -tempfile = { workspace = true } -tokio = { workspace = true, features = ['sync'] } diff --git a/crates/astria-cli/test-utils/src/lib.rs b/crates/astria-cli/test-utils/src/lib.rs deleted file mode 100644 index a049c22b28..0000000000 --- a/crates/astria-cli/test-utils/src/lib.rs +++ /dev/null @@ -1,32 +0,0 @@ -use std::{ - env, - future::Future, -}; - -use once_cell::sync::Lazy; -use tempfile::TempDir; -use tokio::sync::Mutex as AsyncMutex; - -static ASYNC_CURRENT_DIR_LOCK: Lazy> = Lazy::new(|| AsyncMutex::new(())); - -/// Run an async closure with a temporary directory as the current directory. -/// This is useful for cleaning up after tests that test code that creates files. -/// -/// A mutex is required because `set_current_env` is not thread safe, which -/// causes flaky tests when run in parallel and it's called in multiple tests. -/// -/// # Panics -/// -/// Panics if the current directory cannot be set to the temporary directory. -pub async fn with_temp_directory(closure: impl FnOnce(&TempDir) -> F) -where - F: Future, -{ - // ignore poisoning - let _guard = ASYNC_CURRENT_DIR_LOCK.lock().await; - - let temp_dir = TempDir::new().unwrap(); - env::set_current_dir(&temp_dir).unwrap(); - closure(&temp_dir).await; - temp_dir.close().unwrap(); -} diff --git a/crates/astria-cli/tests/integration_test.rs b/crates/astria-cli/tests/integration_test.rs deleted file mode 100644 index ef6a84ac75..0000000000 --- a/crates/astria-cli/tests/integration_test.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::path::PathBuf; - -use assert_cmd::Command; -use test_utils::with_temp_directory; - -#[tokio::test] -async fn test_envars_are_parsed_for_config_create() { - with_temp_directory(|_dir| async { - let mut cmd = Command::cargo_bin("astria-cli").unwrap(); - - cmd.arg("rollup") - .arg("config") - .arg("create") - .env("ROLLUP_USE_TTY", "true") - .env("ROLLUP_LOG_LEVEL", "debug") - .env("ROLLUP_NAME", "testtest") - .env("ROLLUP_CHAIN_ID", "test_chain_id") - .env("ROLLUP_NETWORK_ID", "53") - .env("ROLLUP_SKIP_EMPTY_BLOCKS", "true") - .env( - "ROLLUP_GENESIS_ACCOUNTS", - "0xaC21B97d35Bf75A7dAb16f35b111a50e78A72F30:1000,\ - aC21B97d35Bf75A7dAb16f35b111a50e78A72F30:1000", - ) - .env("ROLLUP_SEQUENCER_INITIAL_BLOCK_HEIGHT", "10") - .env("ROLLUP_SEQUENCER_WEBSOCKET", "ws://localhost:8080") - .env("ROLLUP_SEQUENCER_RPC", "http://localhost:8081") - .assert() - .success(); - - assert!(PathBuf::from("testtest-rollup-conf.yaml").exists()); - }) - .await; -} - -#[tokio::test] -async fn test_error_when_incorrect_envar_values() { - with_temp_directory(|_dir| async { - let mut cmd = Command::cargo_bin("astria-cli").unwrap(); - - cmd.arg("rollup") - .arg("config") - .arg("create") - .env("ROLLUP_USE_TTY", "not_a_bool") - .env("ROLLUP_LOG_LEVEL", "debug") - .env("ROLLUP_NAME", "testtest") - .env("ROLLUP_CHAIN_ID", "test_chain_id") - .env("ROLLUP_NETWORK_ID", "not_a_number") - .env("ROLLUP_SKIP_EMPTY_BLOCKS", "true") - .env( - "ROLLUP_GENESIS_ACCOUNTS", - "0xaC21B97d35Bf75A7dAb16f35b111a50e78A72F30:1000", - ) - .env("ROLLUP_SEQUENCER_INITIAL_BLOCK_HEIGHT", "10") - .env("ROLLUP_SEQUENCER_WEBSOCKET", "ws://localhost:8080") - .env("ROLLUP_SEQUENCER_RPC", "http://localhost:8081") - .assert() - .failure(); - }) - .await; -}