diff --git a/.env.test b/.env.test index 9a93b801..c1bc7ea8 100644 --- a/.env.test +++ b/.env.test @@ -13,7 +13,6 @@ AWS_DEFAULT_REGION=localhost #### ALERTS #### -MADARA_ORCHESTRATOR_AWS_SNS_ARN_NAME=madara-orchestrator-arn MADARA_ORCHESTRATOR_AWS_SNS_ARN=arn:aws:sns:us-east-1:000000000000:madara-orchestrator-arn diff --git a/crates/orchestrator/src/cli/alert/aws_sns.rs b/crates/orchestrator/src/cli/alert/aws_sns.rs index c335cee0..93355374 100644 --- a/crates/orchestrator/src/cli/alert/aws_sns.rs +++ b/crates/orchestrator/src/cli/alert/aws_sns.rs @@ -9,6 +9,6 @@ pub struct AWSSNSCliArgs { pub aws_sns: bool, /// The name of the S3 bucket. - #[arg(env = "MADARA_ORCHESTRATOR_AWS_SNS_ARN", long, default_value = Some("madara-orchestrator-arn"))] + #[arg(env = "MADARA_ORCHESTRATOR_AWS_SNS_ARN", long, default_value = Some("arn:aws:sns:us-east-1:000000000000:madara-orchestrator-arn"))] pub sns_arn: Option, } diff --git a/crates/orchestrator/src/cli/mod.rs b/crates/orchestrator/src/cli/mod.rs index e8320fa3..c067b7db 100644 --- a/crates/orchestrator/src/cli/mod.rs +++ b/crates/orchestrator/src/cli/mod.rs @@ -1,32 +1,18 @@ -use std::str::FromStr as _; -use std::time::Duration; - use alert::AlertValidatedArgs; -use alloy::primitives::Address; use clap::{ArgGroup, Parser, Subcommand}; use cron::event_bridge::AWSEventBridgeCliArgs; use cron::CronValidatedArgs; use da::DaValidatedArgs; use database::DatabaseValidatedArgs; -use ethereum_da_client::EthereumDaValidatedArgs; -use ethereum_settlement_client::EthereumSettlementValidatedArgs; use prover::ProverValidatedArgs; use provider::aws::AWSConfigCliArgs; -use provider::{AWSConfigValidatedArgs, ProviderValidatedArgs}; +use provider::ProviderValidatedArgs; use queue::QueueValidatedArgs; -use settlement::SettlementValidatedArgs; -use sharp_service::SharpValidatedArgs; use snos::SNOSParams; -use starknet_settlement_client::StarknetSettlementValidatedArgs; use storage::StorageValidatedArgs; use url::Url; -use crate::alerts::aws_sns::AWSSNSValidatedArgs; use crate::config::ServiceParams; -use crate::cron::event_bridge::AWSEventBridgeValidatedArgs; -use crate::data_storage::aws_s3::AWSS3ValidatedArgs; -use crate::database::mongodb::MongoDBValidatedArgs; -use crate::queue::sqs::AWSSQSValidatedArgs; use crate::routes::ServerParams; use crate::telemetry::InstrumentationParams; @@ -169,192 +155,51 @@ pub struct RunCmd { impl RunCmd { pub fn validate_provider_params(&self) -> Result { - if self.aws_config_args.aws { - Ok(ProviderValidatedArgs::AWS(AWSConfigValidatedArgs { - aws_access_key_id: self.aws_config_args.aws_access_key_id.clone(), - aws_secret_access_key: self.aws_config_args.aws_secret_access_key.clone(), - aws_region: self.aws_config_args.aws_region.clone(), - })) - } else { - Err("Only AWS is supported as of now".to_string()) - } + validate_params::validate_provider_params(&self.aws_config_args) } pub fn validate_alert_params(&self) -> Result { - if self.aws_sns_args.aws_sns && self.aws_config_args.aws { - Ok(AlertValidatedArgs::AWSSNS(AWSSNSValidatedArgs { - topic_arn: self.aws_sns_args.sns_arn.clone().expect("SNS ARN is required"), - })) - } else { - Err("Only AWS SNS is supported as of now".to_string()) - } + validate_params::validate_alert_params(&self.aws_sns_args, &self.aws_config_args) } pub fn validate_queue_params(&self) -> Result { - if self.aws_sqs_args.aws_sqs && self.aws_config_args.aws { - Ok(QueueValidatedArgs::AWSSQS(AWSSQSValidatedArgs { - queue_base_url: Url::parse( - &self.aws_sqs_args.queue_base_url.clone().expect("Queue base URL is required"), - ) - .expect("Invalid queue base URL"), - sqs_prefix: self.aws_sqs_args.sqs_prefix.clone().expect("SQS prefix is required"), - sqs_suffix: self.aws_sqs_args.sqs_suffix.clone().expect("SQS suffix is required"), - })) - } else { - Err("Only AWS SQS is supported as of now".to_string()) - } + validate_params::validate_queue_params(&self.aws_sqs_args, &self.aws_config_args) } pub fn validate_storage_params(&self) -> Result { - if self.aws_s3_args.aws_s3 && self.aws_config_args.aws { - Ok(StorageValidatedArgs::AWSS3(AWSS3ValidatedArgs { - bucket_name: self.aws_s3_args.bucket_name.clone().expect("Bucket name is required"), - })) - } else { - Err("Only AWS S3 is supported as of now".to_string()) - } + validate_params::validate_storage_params(&self.aws_s3_args, &self.aws_config_args) } pub fn validate_database_params(&self) -> Result { - if self.mongodb_args.mongodb { - Ok(DatabaseValidatedArgs::MongoDB(MongoDBValidatedArgs { - connection_url: Url::parse( - &self.mongodb_args.mongodb_connection_url.clone().expect("MongoDB connection URL is required"), - ) - .expect("Invalid MongoDB connection URL"), - database_name: self - .mongodb_args - .mongodb_database_name - .clone() - .expect("MongoDB database name is required"), - })) - } else { - Err("Only MongoDB is supported as of now".to_string()) - } + validate_params::validate_database_params(&self.mongodb_args) } pub fn validate_da_params(&self) -> Result { - if self.ethereum_da_args.da_on_ethereum { - Ok(DaValidatedArgs::Ethereum(EthereumDaValidatedArgs { - ethereum_da_rpc_url: self - .ethereum_da_args - .ethereum_da_rpc_url - .clone() - .expect("Ethereum DA RPC URL is required"), - })) - } else { - Err("Only Ethereum is supported as of now".to_string()) - } + validate_params::validate_da_params(&self.ethereum_da_args) } pub fn validate_settlement_params(&self) -> Result { - if self.ethereum_args.settle_on_ethereum { - let l1_core_contract_address = Address::from_str( - &self.ethereum_args.l1_core_contract_address.clone().expect("L1 core contract address is required"), - ) - .expect("Invalid L1 core contract address"); - let starknet_operator_address = Address::from_str( - &self.ethereum_args.starknet_operator_address.clone().expect("Starknet operator address is required"), - ) - .expect("Invalid Starknet operator address"); - - let ethereum_params = EthereumSettlementValidatedArgs { - ethereum_rpc_url: self.ethereum_args.ethereum_rpc_url.clone().expect("Ethereum RPC URL is required"), - ethereum_private_key: self - .ethereum_args - .ethereum_private_key - .clone() - .expect("Ethereum private key is required"), - l1_core_contract_address, - starknet_operator_address, - }; - Ok(SettlementValidatedArgs::Ethereum(ethereum_params)) - } else if self.starknet_args.settle_on_starknet { - let starknet_params = StarknetSettlementValidatedArgs { - starknet_rpc_url: self.starknet_args.starknet_rpc_url.clone().expect("Starknet RPC URL is required"), - starknet_private_key: self - .starknet_args - .starknet_private_key - .clone() - .expect("Starknet private key is required"), - starknet_account_address: Address::from_str( - &self.starknet_args.starknet_account_address.clone().expect("Starknet account address is required"), - ) - .expect("Invalid Starknet account address"), - starknet_cairo_core_contract_address: Address::from_str( - &self - .starknet_args - .starknet_cairo_core_contract_address - .clone() - .expect("Starknet Cairo core contract address is required"), - ) - .expect("Invalid Starknet Cairo core contract address"), - starknet_finality_retry_wait_in_secs: self - .starknet_args - .starknet_finality_retry_wait_in_secs - .expect("Starknet finality retry wait in seconds is required"), - }; - Ok(SettlementValidatedArgs::Starknet(starknet_params)) - } else { - Err("Settlement layer is required".to_string()) - } + validate_params::validate_settlement_params(&self.ethereum_args, &self.starknet_args) } pub fn validate_prover_params(&self) -> Result { - if self.sharp_args.sharp { - Ok(ProverValidatedArgs::Sharp(SharpValidatedArgs { - sharp_customer_id: self.sharp_args.sharp_customer_id.clone().expect("Sharp customer ID is required"), - sharp_url: self.sharp_args.sharp_url.clone().expect("Sharp URL is required"), - sharp_user_crt: self.sharp_args.sharp_user_crt.clone().expect("Sharp user certificate is required"), - sharp_user_key: self.sharp_args.sharp_user_key.clone().expect("Sharp user key is required"), - sharp_rpc_node_url: self.sharp_args.sharp_rpc_node_url.clone().expect("Sharp RPC node URL is required"), - sharp_proof_layout: self.sharp_args.sharp_proof_layout.clone().expect("Sharp proof layout is required"), - gps_verifier_contract_address: self - .sharp_args - .gps_verifier_contract_address - .clone() - .expect("GPS verifier contract address is required"), - sharp_server_crt: self - .sharp_args - .sharp_server_crt - .clone() - .expect("Sharp server certificate is required"), - })) - } else { - Err("Only Sharp is supported as of now".to_string()) - } + validate_params::validate_prover_params(&self.sharp_args) } pub fn validate_instrumentation_params(&self) -> Result { - Ok(InstrumentationParams { - otel_service_name: self - .instrumentation_args - .otel_service_name - .clone() - .expect("Otel service name is required"), - otel_collector_endpoint: self.instrumentation_args.otel_collector_endpoint.clone(), - log_level: self.instrumentation_args.log_level, - }) + validate_params::validate_instrumentation_params(&self.instrumentation_args) } pub fn validate_server_params(&self) -> Result { - Ok(ServerParams { host: self.server_args.host.clone(), port: self.server_args.port }) + validate_params::validate_server_params(&self.server_args) } pub fn validate_service_params(&self) -> Result { - Ok(ServiceParams { - // return None if the value is empty string - max_block_to_process: self.service_args.max_block_to_process.clone().and_then(|s| { - if s.is_empty() { None } else { Some(s.parse::().expect("Failed to parse max block to process")) } - }), - min_block_to_process: self.service_args.min_block_to_process.clone().and_then(|s| { - if s.is_empty() { None } else { Some(s.parse::().expect("Failed to parse min block to process")) } - }), - }) + validate_params::validate_service_params(&self.service_args) } pub fn validate_snos_params(&self) -> Result { - Ok(SNOSParams { rpc_for_snos: self.snos_args.rpc_for_snos.clone() }) + validate_params::validate_snos_params(&self.snos_args) } } @@ -420,70 +265,144 @@ pub struct SetupCmd { impl SetupCmd { pub fn validate_provider_params(&self) -> Result { - if self.aws_config_args.aws { + validate_params::validate_provider_params(&self.aws_config_args) + } + + pub fn validate_storage_params(&self) -> Result { + validate_params::validate_storage_params(&self.aws_s3_args, &self.aws_config_args) + } + + pub fn validate_queue_params(&self) -> Result { + validate_params::validate_queue_params(&self.aws_sqs_args, &self.aws_config_args) + } + + pub fn validate_alert_params(&self) -> Result { + validate_params::validate_alert_params(&self.aws_sns_args, &self.aws_config_args) + } + + pub fn validate_cron_params(&self) -> Result { + validate_params::validate_cron_params(&self.aws_event_bridge_args, &self.aws_config_args) + } +} + +pub mod validate_params { + use std::str::FromStr as _; + use std::time::Duration; + + use alloy::primitives::Address; + use ethereum_da_client::EthereumDaValidatedArgs; + use ethereum_settlement_client::EthereumSettlementValidatedArgs; + use sharp_service::SharpValidatedArgs; + use starknet_settlement_client::StarknetSettlementValidatedArgs; + use url::Url; + + use super::alert::aws_sns::AWSSNSCliArgs; + use super::alert::AlertValidatedArgs; + use super::cron::event_bridge::AWSEventBridgeCliArgs; + use super::cron::CronValidatedArgs; + use super::da::ethereum::EthereumDaCliArgs; + use super::da::DaValidatedArgs; + use super::database::mongodb::MongoDBCliArgs; + use super::database::DatabaseValidatedArgs; + use super::instrumentation::InstrumentationCliArgs; + use super::prover::sharp::SharpCliArgs; + use super::prover::ProverValidatedArgs; + use super::provider::aws::AWSConfigCliArgs; + use super::provider::{AWSConfigValidatedArgs, ProviderValidatedArgs}; + use super::queue::aws_sqs::AWSSQSCliArgs; + use super::queue::QueueValidatedArgs; + use super::server::ServerCliArgs; + use super::service::ServiceCliArgs; + use super::settlement::ethereum::EthereumSettlementCliArgs; + use super::settlement::starknet::StarknetSettlementCliArgs; + use super::settlement::SettlementValidatedArgs; + use super::snos::{SNOSCliArgs, SNOSParams}; + use super::storage::aws_s3::AWSS3CliArgs; + use super::storage::StorageValidatedArgs; + use crate::alerts::aws_sns::AWSSNSValidatedArgs; + use crate::config::ServiceParams; + use crate::cron::event_bridge::AWSEventBridgeValidatedArgs; + use crate::data_storage::aws_s3::AWSS3ValidatedArgs; + use crate::database::mongodb::MongoDBValidatedArgs; + use crate::queue::sqs::AWSSQSValidatedArgs; + use crate::routes::ServerParams; + use crate::telemetry::InstrumentationParams; + + pub(crate) fn validate_provider_params( + aws_config_args: &AWSConfigCliArgs, + ) -> Result { + if aws_config_args.aws { Ok(ProviderValidatedArgs::AWS(AWSConfigValidatedArgs { - aws_access_key_id: self.aws_config_args.aws_access_key_id.clone(), - aws_secret_access_key: self.aws_config_args.aws_secret_access_key.clone(), - aws_region: self.aws_config_args.aws_region.clone(), + aws_access_key_id: aws_config_args.aws_access_key_id.clone(), + aws_secret_access_key: aws_config_args.aws_secret_access_key.clone(), + aws_region: aws_config_args.aws_region.clone(), })) } else { Err("Only AWS is supported as of now".to_string()) } } - pub fn validate_alert_params(&self) -> Result { - if self.aws_sns_args.aws_sns && self.aws_config_args.aws { + pub(crate) fn validate_alert_params( + aws_sns_args: &AWSSNSCliArgs, + aws_config_args: &AWSConfigCliArgs, + ) -> Result { + if aws_sns_args.aws_sns && aws_config_args.aws { Ok(AlertValidatedArgs::AWSSNS(AWSSNSValidatedArgs { - topic_arn: self.aws_sns_args.sns_arn.clone().expect("SNS ARN is required"), + topic_arn: aws_sns_args.sns_arn.clone().expect("SNS ARN is required"), })) } else { Err("Only AWS SNS is supported as of now".to_string()) } } - pub fn validate_queue_params(&self) -> Result { - if self.aws_sqs_args.aws_sqs && self.aws_config_args.aws { + pub(crate) fn validate_queue_params( + aws_sqs_args: &AWSSQSCliArgs, + aws_config_args: &AWSConfigCliArgs, + ) -> Result { + if aws_sqs_args.aws_sqs && aws_config_args.aws { Ok(QueueValidatedArgs::AWSSQS(AWSSQSValidatedArgs { - queue_base_url: Url::parse( - &self.aws_sqs_args.queue_base_url.clone().expect("Queue base URL is required"), - ) - .expect("Invalid queue base URL"), - sqs_prefix: self.aws_sqs_args.sqs_prefix.clone().expect("SQS prefix is required"), - sqs_suffix: self.aws_sqs_args.sqs_suffix.clone().expect("SQS suffix is required"), + queue_base_url: Url::parse(&aws_sqs_args.queue_base_url.clone().expect("Queue base URL is required")) + .expect("Invalid queue base URL"), + sqs_prefix: aws_sqs_args.sqs_prefix.clone().expect("SQS prefix is required"), + sqs_suffix: aws_sqs_args.sqs_suffix.clone().expect("SQS suffix is required"), })) } else { Err("Only AWS SQS is supported as of now".to_string()) } } - pub fn validate_storage_params(&self) -> Result { - if self.aws_s3_args.aws_s3 && self.aws_config_args.aws { + pub(crate) fn validate_storage_params( + aws_s3_args: &AWSS3CliArgs, + aws_config_args: &AWSConfigCliArgs, + ) -> Result { + if aws_s3_args.aws_s3 && aws_config_args.aws { Ok(StorageValidatedArgs::AWSS3(AWSS3ValidatedArgs { - bucket_name: self.aws_s3_args.bucket_name.clone().expect("Bucket name is required"), + bucket_name: aws_s3_args.bucket_name.clone().expect("Bucket name is required"), })) } else { Err("Only AWS S3 is supported as of now".to_string()) } } - pub fn validate_cron_params(&self) -> Result { - if self.aws_event_bridge_args.aws_event_bridge && self.aws_config_args.aws { + pub(crate) fn validate_cron_params( + aws_event_bridge_args: &AWSEventBridgeCliArgs, + aws_config_args: &AWSConfigCliArgs, + ) -> Result { + if aws_event_bridge_args.aws_event_bridge && aws_config_args.aws { Ok(CronValidatedArgs::AWSEventBridge(AWSEventBridgeValidatedArgs { - target_queue_name: self - .aws_event_bridge_args + target_queue_name: aws_event_bridge_args .target_queue_name .clone() .expect("Target queue name is required"), cron_time: Duration::from_secs( - self.aws_event_bridge_args + aws_event_bridge_args .cron_time .clone() .expect("Cron time is required") .parse::() .expect("Failed to parse cron time"), ), - trigger_rule_name: self - .aws_event_bridge_args + trigger_rule_name: aws_event_bridge_args .trigger_rule_name .clone() .expect("Trigger rule name is required"), @@ -492,191 +411,400 @@ impl SetupCmd { Err("Only AWS Event Bridge is supported as of now".to_string()) } } -} -// #[cfg(test)] -// pub mod test { - -// use rstest::{fixture, rstest}; -// use tracing::Level; -// use url::Url; - -// use super::alert::aws_sns::AWSSNSCliArgs; -// use super::cron::event_bridge::AWSEventBridgeCliArgs; -// use super::da::ethereum::EthereumDaCliArgs; -// use super::database::mongodb::MongoDBCliArgs; -// use super::instrumentation::InstrumentationCliArgs; -// use super::prover::sharp::SharpCliArgs; -// use super::provider::aws::AWSConfigCliArgs; -// use super::queue::aws_sqs::AWSSQSCliArgs; -// use super::server::ServerCliArgs; -// use super::service::ServiceCliArgs; -// use super::settlement::ethereum::EthereumSettlementCliArgs; -// use super::settlement::starknet::StarknetSettlementCliArgs; -// use super::snos::SNOSCliArgs; -// use super::storage::aws_s3::AWSS3CliArgs; -// use crate::cli::RunCmd; - -// // create a fixture for the CLI -// #[fixture] -// pub fn setup_cmd() -> RunCmd { -// RunCmd { -// aws_config_args: AWSConfigCliArgs { -// aws: true, -// aws_access_key_id: "".to_string(), -// aws_secret_access_key: "".to_string(), -// aws_region: "".to_string(), -// }, -// aws_event_bridge_args: AWSEventBridgeCliArgs { -// aws_event_bridge: true, -// target_queue_name: Some("".to_string()), -// cron_time: Some("12".to_string()), -// trigger_rule_name: Some("".to_string()), -// }, -// aws_s3_args: AWSS3CliArgs { aws_s3: true, bucket_name: Some("".to_string()) }, -// aws_sqs_args: AWSSQSCliArgs { -// aws_sqs: true, -// queue_base_url: Some("".to_string()), -// sqs_prefix: Some("".to_string()), -// sqs_suffix: Some("".to_string()), -// }, -// server_args: ServerCliArgs { host: "".to_string(), port: 0 }, -// aws_sns_args: AWSSNSCliArgs { aws_sns: true, sns_arn: Some("".to_string()) }, - -// instrumentation_args: InstrumentationCliArgs { -// otel_service_name: Some("".to_string()), -// otel_collector_endpoint: None, -// log_level: Level::INFO, -// }, - -// mongodb_args: MongoDBCliArgs { -// mongodb: true, -// mongodb_connection_url: Some("".to_string()), -// mongodb_database_name: Some("".to_string()), -// }, - -// madara_rpc_url: Url::parse("http://localhost:8545").unwrap(), - -// sharp_args: SharpCliArgs { -// sharp: true, -// sharp_customer_id: Some("".to_string()), -// sharp_url: Some(Url::parse("http://localhost:8545").unwrap()), -// sharp_user_crt: Some("".to_string()), -// sharp_user_key: Some("".to_string()), -// sharp_rpc_node_url: Some(Url::parse("http://localhost:8545").unwrap()), -// sharp_proof_layout: Some("".to_string()), -// gps_verifier_contract_address: Some("".to_string()), -// sharp_server_crt: Some("".to_string()), -// }, - -// starknet_args: StarknetSettlementCliArgs { -// starknet_rpc_url: Some(Url::parse("http://localhost:8545").unwrap()), -// starknet_private_key: Some("".to_string()), -// starknet_account_address: Some("".to_string()), -// starknet_cairo_core_contract_address: Some("".to_string()), -// starknet_finality_retry_wait_in_secs: Some(0), -// settle_on_starknet: false, -// }, - -// ethereum_args: EthereumSettlementCliArgs { -// ethereum_rpc_url: Some(Url::parse("http://localhost:8545").unwrap()), -// ethereum_private_key: Some("".to_string()), -// l1_core_contract_address: Some("".to_string()), -// starknet_operator_address: Some("".to_string()), -// settle_on_ethereum: true, -// }, - -// ethereum_da_args: EthereumDaCliArgs { -// da_on_ethereum: true, -// ethereum_da_rpc_url: Some(Url::parse("http://localhost:8545").unwrap()), -// }, - -// snos_args: SNOSCliArgs { rpc_for_snos: Url::parse("http://localhost:8545").unwrap() }, - -// service_args: ServiceCliArgs { -// max_block_to_process: Some("".to_string()), -// min_block_to_process: Some("".to_string()), -// }, -// } -// } - -// // Let's create a test for the CLI each validator - -// #[rstest] -// fn test_validate_provider_params(setup_cmd: RunCmd) { -// let provider_params = setup_cmd.validate_provider_params(); -// assert!(provider_params.is_ok()); -// } - -// #[rstest] -// fn test_validate_alert_params(setup_cmd: RunCmd) { -// let alert_params = setup_cmd.validate_alert_params(); -// assert!(alert_params.is_ok()); -// } - -// #[rstest] -// fn test_validate_queue_params(setup_cmd: RunCmd) { -// let queue_params = setup_cmd.validate_queue_params(); -// assert!(queue_params.is_ok()); -// } - -// #[rstest] -// fn test_validate_storage_params(setup_cmd: RunCmd) { -// let storage_params = setup_cmd.validate_storage_params(); -// assert!(storage_params.is_ok()); -// } - -// #[rstest] -// fn test_validate_database_params(setup_cmd: RunCmd) { -// let database_params = setup_cmd.validate_database_params(); -// assert!(database_params.is_ok()); -// } - -// #[rstest] -// fn test_validate_da_params(setup_cmd: RunCmd) { -// let da_params = setup_cmd.validate_da_params(); -// assert!(da_params.is_ok()); -// } - -// #[rstest] -// fn test_validate_settlement_params(setup_cmd: RunCmd) { -// let settlement_params = setup_cmd.validate_settlement_params(); -// assert!(settlement_params.is_ok()); -// } - -// #[rstest] -// fn test_validate_prover_params(setup_cmd: RunCmd) { -// let prover_params = setup_cmd.validate_prover_params(); -// assert!(prover_params.is_ok()); -// } - -// #[rstest] -// fn test_validate_cron_params(setup_cmd: RunCmd) { -// let cron_params = setup_cmd.validate_cron_params(); -// assert!(cron_params.is_ok()); -// } - -// #[rstest] -// fn test_validate_instrumentation_params(setup_cmd: RunCmd) { -// let instrumentation_params = setup_cmd.validate_instrumentation_params(); -// assert!(instrumentation_params.is_ok()); -// } - -// #[rstest] -// fn test_validate_server_params(setup_cmd: RunCmd) { -// let server_params = setup_cmd.validate_server_params(); -// assert!(server_params.is_ok()); -// } - -// #[rstest] -// fn test_validate_snos_params(setup_cmd: RunCmd) { -// let snos_params = setup_cmd.validate_snos_params(); -// assert!(snos_params.is_ok()); -// } - -// #[rstest] -// fn test_validate_service_params(setup_cmd: RunCmd) { -// let service_params = setup_cmd.validate_service_params(); -// assert!(service_params.is_ok()); -// } -// } + pub(crate) fn validate_database_params(mongodb_args: &MongoDBCliArgs) -> Result { + if mongodb_args.mongodb { + Ok(DatabaseValidatedArgs::MongoDB(MongoDBValidatedArgs { + connection_url: Url::parse( + &mongodb_args.mongodb_connection_url.clone().expect("MongoDB connection URL is required"), + ) + .expect("Invalid MongoDB connection URL"), + database_name: mongodb_args.mongodb_database_name.clone().expect("MongoDB database name is required"), + })) + } else { + Err("Only MongoDB is supported as of now".to_string()) + } + } + + pub(crate) fn validate_da_params(ethereum_da_args: &EthereumDaCliArgs) -> Result { + if ethereum_da_args.da_on_ethereum { + Ok(DaValidatedArgs::Ethereum(EthereumDaValidatedArgs { + ethereum_da_rpc_url: ethereum_da_args + .ethereum_da_rpc_url + .clone() + .expect("Ethereum DA RPC URL is required"), + })) + } else { + Err("Only Ethereum is supported as of now".to_string()) + } + } + + pub(crate) fn validate_settlement_params( + ethereum_args: &EthereumSettlementCliArgs, + starknet_args: &StarknetSettlementCliArgs, + ) -> Result { + if ethereum_args.settle_on_ethereum { + if starknet_args.settle_on_starknet { + return Err("Cannot settle on both Ethereum and Starknet".to_string()); + } + let l1_core_contract_address = Address::from_str( + ðereum_args.l1_core_contract_address.clone().expect("L1 core contract address is required"), + ) + .expect("Invalid L1 core contract address"); + let starknet_operator_address = Address::from_str( + ðereum_args.starknet_operator_address.clone().expect("Starknet operator address is required"), + ) + .expect("Invalid Starknet operator address"); + + let ethereum_params = EthereumSettlementValidatedArgs { + ethereum_rpc_url: ethereum_args.ethereum_rpc_url.clone().expect("Ethereum RPC URL is required"), + ethereum_private_key: ethereum_args + .ethereum_private_key + .clone() + .expect("Ethereum private key is required"), + l1_core_contract_address, + starknet_operator_address, + }; + Ok(SettlementValidatedArgs::Ethereum(ethereum_params)) + } else if starknet_args.settle_on_starknet { + if ethereum_args.settle_on_ethereum { + return Err("Cannot settle on both Starknet and Ethereum".to_string()); + } + let starknet_params = StarknetSettlementValidatedArgs { + starknet_rpc_url: starknet_args.starknet_rpc_url.clone().expect("Starknet RPC URL is required"), + starknet_private_key: starknet_args + .starknet_private_key + .clone() + .expect("Starknet private key is required"), + starknet_account_address: starknet_args + .starknet_account_address + .clone() + .expect("Starknet account address is required"), + starknet_cairo_core_contract_address: starknet_args + .starknet_cairo_core_contract_address + .clone() + .expect("Starknet Cairo core contract address is required"), + starknet_finality_retry_wait_in_secs: starknet_args + .starknet_finality_retry_wait_in_secs + .expect("Starknet finality retry wait in seconds is required"), + }; + Ok(SettlementValidatedArgs::Starknet(starknet_params)) + } else { + Err("Settlement layer is required".to_string()) + } + } + + pub(crate) fn validate_prover_params(sharp_args: &SharpCliArgs) -> Result { + if sharp_args.sharp { + Ok(ProverValidatedArgs::Sharp(SharpValidatedArgs { + sharp_customer_id: sharp_args.sharp_customer_id.clone().expect("Sharp customer ID is required"), + sharp_url: sharp_args.sharp_url.clone().expect("Sharp URL is required"), + sharp_user_crt: sharp_args.sharp_user_crt.clone().expect("Sharp user certificate is required"), + sharp_user_key: sharp_args.sharp_user_key.clone().expect("Sharp user key is required"), + sharp_rpc_node_url: sharp_args.sharp_rpc_node_url.clone().expect("Sharp RPC node URL is required"), + sharp_proof_layout: sharp_args.sharp_proof_layout.clone().expect("Sharp proof layout is required"), + gps_verifier_contract_address: sharp_args + .gps_verifier_contract_address + .clone() + .expect("GPS verifier contract address is required"), + sharp_server_crt: sharp_args.sharp_server_crt.clone().expect("Sharp server certificate is required"), + })) + } else { + Err("Only Sharp is supported as of now".to_string()) + } + } + + pub(crate) fn validate_instrumentation_params( + instrumentation_args: &InstrumentationCliArgs, + ) -> Result { + Ok(InstrumentationParams { + otel_service_name: instrumentation_args.otel_service_name.clone().expect("Otel service name is required"), + otel_collector_endpoint: instrumentation_args.otel_collector_endpoint.clone(), + log_level: instrumentation_args.log_level, + }) + } + + pub(crate) fn validate_server_params(server_args: &ServerCliArgs) -> Result { + Ok(ServerParams { host: server_args.host.clone(), port: server_args.port }) + } + + pub(crate) fn validate_service_params(service_args: &ServiceCliArgs) -> Result { + Ok(ServiceParams { + // return None if the value is empty string + max_block_to_process: service_args.max_block_to_process.clone().and_then(|s| { + if s.is_empty() { None } else { Some(s.parse::().expect("Failed to parse max block to process")) } + }), + min_block_to_process: service_args.min_block_to_process.clone().and_then(|s| { + if s.is_empty() { None } else { Some(s.parse::().expect("Failed to parse min block to process")) } + }), + }) + } + + pub(crate) fn validate_snos_params(snos_args: &SNOSCliArgs) -> Result { + Ok(SNOSParams { rpc_for_snos: snos_args.rpc_for_snos.clone() }) + } + + #[cfg(test)] + pub mod test { + + use rstest::rstest; + use tracing::Level; + use url::Url; + + use crate::cli::alert::aws_sns::AWSSNSCliArgs; + use crate::cli::cron::event_bridge::AWSEventBridgeCliArgs; + use crate::cli::da::ethereum::EthereumDaCliArgs; + use crate::cli::database::mongodb::MongoDBCliArgs; + use crate::cli::instrumentation::InstrumentationCliArgs; + use crate::cli::prover::sharp::SharpCliArgs; + use crate::cli::provider::aws::AWSConfigCliArgs; + use crate::cli::queue::aws_sqs::AWSSQSCliArgs; + use crate::cli::server::ServerCliArgs; + use crate::cli::service::ServiceCliArgs; + use crate::cli::settlement::ethereum::EthereumSettlementCliArgs; + use crate::cli::settlement::starknet::StarknetSettlementCliArgs; + use crate::cli::snos::SNOSCliArgs; + use crate::cli::storage::aws_s3::AWSS3CliArgs; + use crate::cli::validate_params::{ + validate_alert_params, validate_cron_params, validate_da_params, validate_database_params, + validate_instrumentation_params, validate_prover_params, validate_provider_params, validate_queue_params, + validate_server_params, validate_service_params, validate_settlement_params, validate_snos_params, + validate_storage_params, + }; + + #[rstest] + #[case(true)] + #[case(false)] + fn test_validate_provider_params(#[case] is_aws: bool) { + let aws_config_args: AWSConfigCliArgs = AWSConfigCliArgs { + aws: is_aws, + aws_access_key_id: "".to_string(), + aws_secret_access_key: "".to_string(), + aws_region: "".to_string(), + }; + + let provider_params = validate_provider_params(&aws_config_args); + if is_aws { + assert!(provider_params.is_ok()); + } else { + assert!(provider_params.is_err()); + } + } + + #[rstest] + #[case(true, true)] + #[case(true, false)] + #[case(false, true)] + #[case(false, false)] + fn test_validate_alert_params(#[case] is_aws: bool, #[case] is_sns: bool) { + let aws_config_args: AWSConfigCliArgs = AWSConfigCliArgs { + aws: is_aws, + aws_access_key_id: "".to_string(), + aws_secret_access_key: "".to_string(), + aws_region: "".to_string(), + }; + let aws_sns_args: AWSSNSCliArgs = AWSSNSCliArgs { aws_sns: is_sns, sns_arn: Some("".to_string()) }; + + let alert_params = validate_alert_params(&aws_sns_args, &aws_config_args); + if is_aws && is_sns { + assert!(alert_params.is_ok()); + } else { + assert!(alert_params.is_err()); + } + } + + #[rstest] + #[case(true, true)] + #[case(true, false)] + #[case(false, true)] + #[case(false, false)] + fn test_validate_queue_params(#[case] is_aws: bool, #[case] is_sqs: bool) { + let aws_config_args: AWSConfigCliArgs = AWSConfigCliArgs { + aws: is_aws, + aws_access_key_id: "".to_string(), + aws_secret_access_key: "".to_string(), + aws_region: "".to_string(), + }; + let aws_sqs_args: AWSSQSCliArgs = AWSSQSCliArgs { + aws_sqs: is_sqs, + queue_base_url: Some("http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000".to_string()), + sqs_prefix: Some("".to_string()), + sqs_suffix: Some("".to_string()), + }; + let queue_params = validate_queue_params(&aws_sqs_args, &aws_config_args); + if is_aws && is_sqs { + assert!(queue_params.is_ok()); + } else { + assert!(queue_params.is_err()); + } + } + + #[rstest] + #[case(true, true)] + #[case(true, false)] + #[case(false, true)] + #[case(false, false)] + fn test_validate_storage_params(#[case] is_aws: bool, #[case] is_s3: bool) { + let aws_s3_args: AWSS3CliArgs = AWSS3CliArgs { aws_s3: is_s3, bucket_name: Some("".to_string()) }; + let aws_config_args: AWSConfigCliArgs = AWSConfigCliArgs { + aws: is_aws, + aws_access_key_id: "".to_string(), + aws_secret_access_key: "".to_string(), + aws_region: "".to_string(), + }; + let storage_params = validate_storage_params(&aws_s3_args, &aws_config_args); + if is_aws && is_s3 { + assert!(storage_params.is_ok()); + } else { + assert!(storage_params.is_err()); + } + } + + #[rstest] + #[case(true)] + #[case(false)] + fn test_validate_database_params(#[case] is_mongodb: bool) { + let mongodb_args: MongoDBCliArgs = MongoDBCliArgs { + mongodb: is_mongodb, + mongodb_connection_url: Some("mongodb://localhost:27017".to_string()), + mongodb_database_name: Some("orchestrator".to_string()), + }; + let database_params = validate_database_params(&mongodb_args); + if is_mongodb { + assert!(database_params.is_ok()); + } else { + assert!(database_params.is_err()); + } + } + + #[rstest] + #[case(true)] + #[case(false)] + fn test_validate_da_params(#[case] is_ethereum: bool) { + let ethereum_da_args: EthereumDaCliArgs = EthereumDaCliArgs { + da_on_ethereum: is_ethereum, + ethereum_da_rpc_url: Some(Url::parse("http://localhost:8545").unwrap()), + }; + let da_params = validate_da_params(ðereum_da_args); + if is_ethereum { + assert!(da_params.is_ok()); + } else { + assert!(da_params.is_err()); + } + } + + #[rstest] + #[case(true, false)] + #[case(false, true)] + #[case(false, false)] + #[case(true, true)] + fn test_validate_settlement_params(#[case] is_ethereum: bool, #[case] is_starknet: bool) { + let ethereum_args: EthereumSettlementCliArgs = EthereumSettlementCliArgs { + ethereum_rpc_url: Some(Url::parse("http://localhost:8545").unwrap()), + ethereum_private_key: Some("".to_string()), + l1_core_contract_address: Some("0xE2Bb56ee936fd6433DC0F6e7e3b8365C906AA057".to_string()), + starknet_operator_address: Some("0x5b98B836969A60FEC50Fa925905Dd1D382a7db43".to_string()), + settle_on_ethereum: is_ethereum, + }; + let starknet_args: StarknetSettlementCliArgs = StarknetSettlementCliArgs { + starknet_rpc_url: Some(Url::parse("http://localhost:8545").unwrap()), + starknet_private_key: Some("".to_string()), + starknet_account_address: Some("".to_string()), + starknet_cairo_core_contract_address: Some("".to_string()), + starknet_finality_retry_wait_in_secs: Some(0), + settle_on_starknet: is_starknet, + }; + let settlement_params = validate_settlement_params(ðereum_args, &starknet_args); + if is_ethereum ^ is_starknet { + assert!(settlement_params.is_ok()); + } else { + assert!(settlement_params.is_err()); + } + } + + #[rstest] + #[case(true)] + #[case(false)] + fn test_validate_prover_params(#[case] is_sharp: bool) { + let sharp_args: SharpCliArgs = SharpCliArgs { + sharp: is_sharp, + sharp_customer_id: Some("".to_string()), + sharp_url: Some(Url::parse("http://localhost:8545").unwrap()), + sharp_user_crt: Some("".to_string()), + sharp_user_key: Some("".to_string()), + sharp_rpc_node_url: Some(Url::parse("http://localhost:8545").unwrap()), + sharp_proof_layout: Some("".to_string()), + gps_verifier_contract_address: Some("".to_string()), + sharp_server_crt: Some("".to_string()), + }; + let prover_params = validate_prover_params(&sharp_args); + if is_sharp { + assert!(prover_params.is_ok()); + } else { + assert!(prover_params.is_err()); + } + } + + #[rstest] + #[case(true)] + #[case(false)] + fn test_validate_cron_params(#[case] is_aws: bool) { + let aws_event_bridge_args: AWSEventBridgeCliArgs = AWSEventBridgeCliArgs { + aws_event_bridge: is_aws, + target_queue_name: Some(String::from("test")), + cron_time: Some(String::from("12")), + trigger_rule_name: Some(String::from("test")), + }; + let aws_config_args: AWSConfigCliArgs = AWSConfigCliArgs { + aws: is_aws, + aws_access_key_id: "".to_string(), + aws_secret_access_key: "".to_string(), + aws_region: "".to_string(), + }; + let cron_params = validate_cron_params(&aws_event_bridge_args, &aws_config_args); + if is_aws { + assert!(cron_params.is_ok()); + } else { + assert!(cron_params.is_err()); + } + } + + #[rstest] + fn test_validate_instrumentation_params() { + let instrumentation_args: InstrumentationCliArgs = InstrumentationCliArgs { + otel_service_name: Some("".to_string()), + otel_collector_endpoint: None, + log_level: Level::INFO, + }; + let instrumentation_params = validate_instrumentation_params(&instrumentation_args); + assert!(instrumentation_params.is_ok()); + } + + #[rstest] + fn test_validate_server_params() { + let server_args: ServerCliArgs = ServerCliArgs { host: "".to_string(), port: 0 }; + let server_params = validate_server_params(&server_args); + assert!(server_params.is_ok()); + } + + #[rstest] + fn test_validate_snos_params() { + let snos_args: SNOSCliArgs = SNOSCliArgs { rpc_for_snos: Url::parse("http://localhost:8545").unwrap() }; + let snos_params = validate_snos_params(&snos_args); + assert!(snos_params.is_ok()); + } + + #[rstest] + fn test_validate_service_params() { + let service_args: ServiceCliArgs = ServiceCliArgs { + max_block_to_process: Some("66645".to_string()), + min_block_to_process: Some("100".to_string()), + }; + let service_params = validate_service_params(&service_args); + assert!(service_params.is_ok()); + let service_params = service_params.unwrap(); + assert_eq!(service_params.max_block_to_process, Some(66645)); + assert_eq!(service_params.min_block_to_process, Some(100)); + } + } +} diff --git a/crates/orchestrator/src/setup/mod.rs b/crates/orchestrator/src/setup/mod.rs index 10c4e8b0..e917de3d 100644 --- a/crates/orchestrator/src/setup/mod.rs +++ b/crates/orchestrator/src/setup/mod.rs @@ -23,15 +23,15 @@ pub enum SetupConfig { } // TODO : move this to main.rs after moving to clap. -pub async fn setup_cloud(run_cmd: &SetupCmd) -> color_eyre::Result<()> { +pub async fn setup_cloud(setup_cmd: &SetupCmd) -> color_eyre::Result<()> { println!("Setting up cloud. ⏳"); // AWS - let provider_params = run_cmd.validate_provider_params().expect("Failed to validate provider params"); + let provider_params = setup_cmd.validate_provider_params().expect("Failed to validate provider params"); let provider_config = build_provider_config(&provider_params).await; // Data Storage println!("Setting up data storage. ⏳"); - let data_storage_params = run_cmd.validate_storage_params().expect("Failed to validate storage params"); + let data_storage_params = setup_cmd.validate_storage_params().expect("Failed to validate storage params"); let aws_config = provider_config.get_aws_client_or_panic(); match data_storage_params { @@ -44,7 +44,7 @@ pub async fn setup_cloud(run_cmd: &SetupCmd) -> color_eyre::Result<()> { // Queues println!("Setting up queues. ⏳"); - let queue_params = run_cmd.validate_queue_params().expect("Failed to validate queue params"); + let queue_params = setup_cmd.validate_queue_params().expect("Failed to validate queue params"); match queue_params { QueueValidatedArgs::AWSSQS(aws_sqs_params) => { let sqs = Box::new(SqsQueue::new_with_args(aws_sqs_params, aws_config)); @@ -55,7 +55,7 @@ pub async fn setup_cloud(run_cmd: &SetupCmd) -> color_eyre::Result<()> { // Cron println!("Setting up cron. ⏳"); - let cron_params = run_cmd.validate_cron_params().expect("Failed to validate cron params"); + let cron_params = setup_cmd.validate_cron_params().expect("Failed to validate cron params"); match cron_params { CronValidatedArgs::AWSEventBridge(aws_event_bridge_params) => { let aws_config = provider_config.get_aws_client_or_panic(); @@ -67,7 +67,7 @@ pub async fn setup_cloud(run_cmd: &SetupCmd) -> color_eyre::Result<()> { // Alerts println!("Setting up alerts. ⏳"); - let alert_params = run_cmd.validate_alert_params().expect("Failed to validate alert params"); + let alert_params = setup_cmd.validate_alert_params().expect("Failed to validate alert params"); match alert_params { AlertValidatedArgs::AWSSNS(aws_sns_params) => { let aws_config = provider_config.get_aws_client_or_panic(); diff --git a/crates/orchestrator/src/tests/common/mod.rs b/crates/orchestrator/src/tests/common/mod.rs index 54c43511..7e5f7c9e 100644 --- a/crates/orchestrator/src/tests/common/mod.rs +++ b/crates/orchestrator/src/tests/common/mod.rs @@ -53,8 +53,9 @@ pub async fn create_sns_arn( alert_params: &AlertValidatedArgs, ) -> Result<(), SdkError> { let AlertValidatedArgs::AWSSNS(aws_sns_params) = alert_params; + let topic_name = aws_sns_params.topic_arn.split(":").last().unwrap(); let sns_client = get_sns_client(provider_config.get_aws_client_or_panic()).await; - sns_client.create_topic().name(aws_sns_params.topic_arn.clone()).send().await?; + sns_client.create_topic().name(topic_name).send().await?; Ok(()) } diff --git a/crates/orchestrator/src/tests/config.rs b/crates/orchestrator/src/tests/config.rs index 22da06b7..811e5ec2 100644 --- a/crates/orchestrator/src/tests/config.rs +++ b/crates/orchestrator/src/tests/config.rs @@ -512,7 +512,7 @@ fn get_env_params() -> EnvParams { }); let alert_params = AlertValidatedArgs::AWSSNS(AWSSNSValidatedArgs { - topic_arn: get_env_var_or_panic("MADARA_ORCHESTRATOR_AWS_SNS_ARN_NAME"), + topic_arn: get_env_var_or_panic("MADARA_ORCHESTRATOR_AWS_SNS_ARN"), }); let settlement_params = SettlementValidatedArgs::Ethereum(EthereumSettlementValidatedArgs { diff --git a/crates/settlement-clients/ethereum/Cargo.toml b/crates/settlement-clients/ethereum/Cargo.toml index 987672f7..c0c56f92 100644 --- a/crates/settlement-clients/ethereum/Cargo.toml +++ b/crates/settlement-clients/ethereum/Cargo.toml @@ -4,8 +4,8 @@ version.workspace = true edition.workspace = true [dependencies] -alloy-primitives = { version = "0.7.7", default-features = false } alloy = { workspace = true, features = ["full", "node-bindings"] } +alloy-primitives = { version = "0.7.7", default-features = false } async-trait = { workspace = true } bytes = "1.7.2" c-kzg = { workspace = true } diff --git a/crates/settlement-clients/starknet/Cargo.toml b/crates/settlement-clients/starknet/Cargo.toml index 42be56a9..06154407 100644 --- a/crates/settlement-clients/starknet/Cargo.toml +++ b/crates/settlement-clients/starknet/Cargo.toml @@ -4,8 +4,8 @@ version.workspace = true edition.workspace = true [dependencies] -alloy-primitives = { version = "0.7.7", default-features = false } alloy = { workspace = true, features = ["full", "node-bindings"] } +alloy-primitives = { version = "0.7.7", default-features = false } appchain-core-contract-client = { workspace = true } async-trait = { workspace = true } c-kzg = { workspace = true } diff --git a/crates/settlement-clients/starknet/src/lib.rs b/crates/settlement-clients/starknet/src/lib.rs index 00d8245c..ade0d17b 100644 --- a/crates/settlement-clients/starknet/src/lib.rs +++ b/crates/settlement-clients/starknet/src/lib.rs @@ -5,7 +5,6 @@ pub mod tests; use std::sync::Arc; -use alloy_primitives::Address; use appchain_core_contract_client::clients::StarknetCoreContractClient; use appchain_core_contract_client::interfaces::core_contract::CoreContract; use async_trait::async_trait; @@ -45,8 +44,8 @@ use url::Url; pub struct StarknetSettlementValidatedArgs { pub starknet_rpc_url: Url, pub starknet_private_key: String, - pub starknet_account_address: Address, - pub starknet_cairo_core_contract_address: Address, + pub starknet_account_address: String, + pub starknet_cairo_core_contract_address: String, pub starknet_finality_retry_wait_in_secs: u64, } diff --git a/crates/settlement-clients/starknet/src/tests/test.rs b/crates/settlement-clients/starknet/src/tests/test.rs index cd0a6c85..d4860e40 100644 --- a/crates/settlement-clients/starknet/src/tests/test.rs +++ b/crates/settlement-clients/starknet/src/tests/test.rs @@ -1,10 +1,8 @@ use std::env; use std::path::Path; -use std::str::FromStr as _; use std::sync::Arc; use std::time::Duration; -use alloy_primitives::Address; use color_eyre::eyre::eyre; use rstest::{fixture, rstest}; use settlement_client_interface::SettlementClient; @@ -84,14 +82,10 @@ async fn setup(#[future] spin_up_madara: MadaraCmd) -> (LocalWalletSignerMiddlew let starknet_settlement_params: StarknetSettlementValidatedArgs = StarknetSettlementValidatedArgs { starknet_rpc_url: Url::parse(madara_process.rpc_url.as_ref()).unwrap(), starknet_private_key: get_env_var_or_panic("MADARA_ORCHESTRATOR_STARKNET_PRIVATE_KEY"), - starknet_account_address: Address::from_str(&get_env_var_or_panic( - "MADARA_ORCHESTRATOR_STARKNET_ACCOUNT_ADDRESS", - )) - .unwrap(), - starknet_cairo_core_contract_address: Address::from_str(&get_env_var_or_panic( + starknet_account_address: get_env_var_or_panic("MADARA_ORCHESTRATOR_STARKNET_ACCOUNT_ADDRESS"), + starknet_cairo_core_contract_address: get_env_var_or_panic( "MADARA_ORCHESTRATOR_STARKNET_CAIRO_CORE_CONTRACT_ADDRESS", - )) - .unwrap(), + ), starknet_finality_retry_wait_in_secs: get_env_var_or_panic( "MADARA_ORCHESTRATOR_STARKNET_FINALITY_RETRY_WAIT_IN_SECS", ) @@ -126,14 +120,10 @@ async fn test_settle(#[future] setup: (LocalWalletSignerMiddleware, MadaraCmd)) let mut starknet_settlement_params: StarknetSettlementValidatedArgs = StarknetSettlementValidatedArgs { starknet_rpc_url: madara_process.rpc_url.clone(), starknet_private_key: get_env_var_or_panic("MADARA_ORCHESTRATOR_STARKNET_PRIVATE_KEY"), - starknet_account_address: Address::from_str(&get_env_var_or_panic( - "MADARA_ORCHESTRATOR_STARKNET_ACCOUNT_ADDRESS", - )) - .unwrap(), - starknet_cairo_core_contract_address: Address::from_str(&get_env_var_or_panic( + starknet_account_address: get_env_var_or_panic("MADARA_ORCHESTRATOR_STARKNET_ACCOUNT_ADDRESS"), + starknet_cairo_core_contract_address: get_env_var_or_panic( "MADARA_ORCHESTRATOR_STARKNET_CAIRO_CORE_CONTRACT_ADDRESS", - )) - .unwrap(), + ), starknet_finality_retry_wait_in_secs: get_env_var_or_panic( "MADARA_ORCHESTRATOR_STARKNET_FINALITY_RETRY_WAIT_IN_SECS", ) @@ -170,8 +160,7 @@ async fn test_settle(#[future] setup: (LocalWalletSignerMiddleware, MadaraCmd)) let deployed_address = deploy_v1.deployed_address(); // env::set_var("STARKNET_CAIRO_CORE_CONTRACT_ADDRESS", deployed_address.to_hex_string()); - starknet_settlement_params.starknet_cairo_core_contract_address = - Address::from_str(&deployed_address.to_hex_string()).unwrap(); + starknet_settlement_params.starknet_cairo_core_contract_address = deployed_address.to_hex_string(); let InvokeTransactionResult { transaction_hash: deploy_tx_hash } = deploy_v1.send().await.expect("Unable to deploy contract"); diff --git a/e2e-tests/src/node.rs b/e2e-tests/src/node.rs index 58c50a45..0603cb40 100644 --- a/e2e-tests/src/node.rs +++ b/e2e-tests/src/node.rs @@ -37,6 +37,7 @@ pub enum OrchestratorMode { impl Orchestrator { pub fn new(mode: OrchestratorMode, mut envs: Vec<(String, String)>) -> Option { let repository_root = &get_repository_root(); + let mut address = String::new(); std::env::set_current_dir(repository_root).expect("Failed to change working directory"); let is_run_mode = mode == OrchestratorMode::Run; @@ -65,34 +66,24 @@ impl Orchestrator { command.arg("--da-on-ethereum"); command.arg("--sharp"); command.arg("--mongodb"); - - } else { - command.arg("--aws-event-bridge"); - } - // Configure run-specific settings - let address = if is_run_mode { let port = get_free_port(); let addr = format!("127.0.0.1:{}", port); envs.push(("MADARA_ORCHESTRATOR_PORT".to_string(), port.to_string())); - addr - } else { - String::new() - }; + address = addr; - command.current_dir(repository_root).envs(envs); - - // Handle stdout/stderr differently based on mode - if is_run_mode { command.stdout(Stdio::piped()).stderr(Stdio::piped()); } else { + command.arg("--aws-event-bridge"); + // For setup mode, inherit the stdio to show output directly command.stdout(Stdio::inherit()).stderr(Stdio::inherit()); } + command.current_dir(repository_root).envs(envs); + let mut process = command.spawn().expect("Failed to start process"); - // Set up stdout and stderr handling only for run mode if is_run_mode { let stdout = process.stdout.take().expect("Failed to capture stdout"); thread::spawn(move || { @@ -113,9 +104,8 @@ impl Orchestrator { } }); }); - } - - if is_run_mode { Some(Self { process, address }) } else { + Some(Self { process, address }) + } else { // Wait for the process to complete and get its exit status let status = process.wait().expect("Failed to wait for process"); if status.success() { @@ -129,9 +119,9 @@ impl Orchestrator { } } None - } + } } - + pub fn endpoint(&self) -> Url { Url::parse(&format!("http://{}", self.address)).unwrap() } diff --git a/e2e-tests/tests.rs b/e2e-tests/tests.rs index 8ff2900f..89a63ee4 100644 --- a/e2e-tests/tests.rs +++ b/e2e-tests/tests.rs @@ -45,7 +45,7 @@ struct Setup { mongo_db_instance: MongoDbServer, starknet_client: StarknetClient, sharp_client: SharpClient, - env_vector: Vec<(String, String)>, + env_vector: HashMap, } impl Setup { @@ -72,34 +72,38 @@ impl Setup { let (starknet_core_contract_address, verifier_contract_address) = anvil_setup.deploy_contracts().await; println!("✅ Anvil setup completed"); - let mut env_vec: Vec<(String, String)> = - vec![("MADARA_ORCHESTRATOR_MONGODB_CONNECTION_URL".to_string(), mongo_db_instance.endpoint().to_string())]; + let mut env_vec: HashMap = HashMap::new(); + + let env_vars = dotenvy::vars(); + for (key, value) in env_vars { + env_vec.insert(key, value); + } + + env_vec + .insert("MADARA_ORCHESTRATOR_MONGODB_CONNECTION_URL".to_string(), mongo_db_instance.endpoint().to_string()); // Adding other values to the environment variables vector - env_vec.push(("MADARA_ORCHESTRATOR_ETHEREUM_SETTLEMENT_RPC_URL".to_string(), anvil_setup.rpc_url.to_string())); - env_vec.push(("MADARA_ORCHESTRATOR_SHARP_URL".to_string(), sharp_client.url())); + env_vec.insert("MADARA_ORCHESTRATOR_ETHEREUM_SETTLEMENT_RPC_URL".to_string(), anvil_setup.rpc_url.to_string()); + env_vec.insert("MADARA_ORCHESTRATOR_SHARP_URL".to_string(), sharp_client.url()); // Adding impersonation for operator as our own address here. // As we are using test contracts thus we don't need any impersonation. // But that logic is being used in integration tests so to keep that. We // add this address here. // Anvil.addresses[0] - env_vec.push(( + env_vec.insert( "MADARA_ORCHESTRATOR_STARKNET_OPERATOR_ADDRESS".to_string(), "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266".to_string(), - )); - env_vec.push(( + ); + env_vec.insert( "MADARA_ORCHESTRATOR_GPS_VERIFIER_CONTRACT_ADDRESS".to_string(), verifier_contract_address.to_string(), - )); - env_vec.push(( + ); + env_vec.insert( "MADARA_ORCHESTRATOR_L1_CORE_CONTRACT_ADDRESS".to_string(), starknet_core_contract_address.to_string(), - )); - env_vec.push(("MADARA_ORCHESTRATOR_MAX_BLOCK_NO_TO_PROCESS".to_string(), l2_block_number)); - - let env_vec_2: Vec<(String, String)> = set_env_vars(); - env_vec.extend(env_vec_2); + ); + env_vec.insert("MADARA_ORCHESTRATOR_MAX_BLOCK_NO_TO_PROCESS".to_string(), l2_block_number); Self { mongo_db_instance, starknet_client, sharp_client, env_vector: env_vec } } @@ -118,7 +122,7 @@ impl Setup { } pub fn envs(&self) -> Vec<(String, String)> { - self.env_vector.clone() + self.env_vector.iter().map(|(k, v)| (k.clone(), v.clone())).collect() } } @@ -477,115 +481,3 @@ pub async fn setup_s3(s3_client: &Box) -> color_e s3_client.create_bucket(&get_env_var_or_panic("MADARA_ORCHESTRATOR_AWS_S3_BUCKET_NAME")).await.unwrap(); Ok(()) } - -fn set_env_vars() -> Vec<(String, String)> { - let env_vec: Vec<(String, String)> = vec![ - // AWS Config - ("AWS_ACCESS_KEY_ID".to_string(), get_env_var_or_panic("AWS_ACCESS_KEY_ID")), - ("AWS_SECRET_ACCESS_KEY".to_string(), get_env_var_or_panic("AWS_SECRET_ACCESS_KEY")), - ("AWS_REGION".to_string(), get_env_var_or_panic("AWS_REGION")), - ("AWS_ENDPOINT_URL".to_string(), get_env_var_or_panic("AWS_ENDPOINT_URL")), - ("AWS_DEFAULT_REGION".to_string(), get_env_var_or_panic("AWS_DEFAULT_REGION")), - // Alerts - ("MADARA_ORCHESTRATOR_AWS_SNS_ARN".to_string(), get_env_var_or_panic("MADARA_ORCHESTRATOR_AWS_SNS_ARN")), - // Data Availability - ( - "MADARA_ORCHESTRATOR_ETHEREUM_DA_RPC_URL".to_string(), - get_env_var_or_panic("MADARA_ORCHESTRATOR_ETHEREUM_DA_RPC_URL"), - ), - // Database - // ("MADARA_ORCHESTRATOR_MONGODB_CONNECTION_URL".to_string(), - // get_env_var_or_panic("MADARA_ORCHESTRATOR_MONGODB_CONNECTION_URL")), - ("MADARA_ORCHESTRATOR_DATABASE_NAME".to_string(), get_env_var_or_panic("MADARA_ORCHESTRATOR_DATABASE_NAME")), - // Prover - ( - "MADARA_ORCHESTRATOR_SHARP_CUSTOMER_ID".to_string(), - get_env_var_or_panic("MADARA_ORCHESTRATOR_SHARP_CUSTOMER_ID"), - ), - // ("MADARA_ORCHESTRATOR_SHARP_URL".to_string(), get_env_var_or_panic("MADARA_ORCHESTRATOR_SHARP_URL")), - ("MADARA_ORCHESTRATOR_SHARP_USER_CRT".to_string(), get_env_var_or_panic("MADARA_ORCHESTRATOR_SHARP_USER_CRT")), - ("MADARA_ORCHESTRATOR_SHARP_USER_KEY".to_string(), get_env_var_or_panic("MADARA_ORCHESTRATOR_SHARP_USER_KEY")), - ( - "MADARA_ORCHESTRATOR_SHARP_SERVER_CRT".to_string(), - get_env_var_or_panic("MADARA_ORCHESTRATOR_SHARP_SERVER_CRT"), - ), - ( - "MADARA_ORCHESTRATOR_SHARP_RPC_NODE_URL".to_string(), - get_env_var_or_panic("MADARA_ORCHESTRATOR_SHARP_RPC_NODE_URL"), - ), - ( - "MADARA_ORCHESTRATOR_SHARP_PROOF_LAYOUT".to_string(), - get_env_var_or_panic("MADARA_ORCHESTRATOR_SHARP_PROOF_LAYOUT"), - ), - // ("MADARA_ORCHESTRATOR_GPS_VERIFIER_CONTRACT_ADDRESS".to_string(), - // get_env_var_or_panic("MADARA_ORCHESTRATOR_GPS_VERIFIER_CONTRACT_ADDRESS")), - - // Queue - ("MADARA_ORCHESTRATOR_SQS_PREFIX".to_string(), get_env_var_or_panic("MADARA_ORCHESTRATOR_SQS_PREFIX")), - ("MADARA_ORCHESTRATOR_SQS_SUFFIX".to_string(), get_env_var_or_panic("MADARA_ORCHESTRATOR_SQS_SUFFIX")), - ( - "MADARA_ORCHESTRATOR_SQS_BASE_QUEUE_URL".to_string(), - get_env_var_or_panic("MADARA_ORCHESTRATOR_SQS_BASE_QUEUE_URL"), - ), - // Settlement - Ethereum - // ("MADARA_ORCHESTRATOR_ETHEREUM_SETTLEMENT_RPC_URL".to_string(), - // get_env_var_or_panic("MADARA_ORCHESTRATOR_ETHEREUM_SETTLEMENT_RPC_URL")), - ( - "MADARA_ORCHESTRATOR_ETHEREUM_PRIVATE_KEY".to_string(), - get_env_var_or_panic("MADARA_ORCHESTRATOR_ETHEREUM_PRIVATE_KEY"), - ), - // ("MADARA_ORCHESTRATOR_L1_CORE_CONTRACT_ADDRESS".to_string(), - // get_env_var_or_panic("MADARA_ORCHESTRATOR_L1_CORE_CONTRACT_ADDRESS")), - // ("MADARA_ORCHESTRATOR_STARKNET_OPERATOR_ADDRESS".to_string(), - // get_env_var_or_panic("MADARA_ORCHESTRATOR_STARKNET_OPERATOR_ADDRESS")), - - // Settlement - Starknet - ( - "MADARA_ORCHESTRATOR_STARKNET_SETTLEMENT_RPC_URL".to_string(), - get_env_var_or_panic("MADARA_ORCHESTRATOR_STARKNET_SETTLEMENT_RPC_URL"), - ), - ( - "MADARA_ORCHESTRATOR_STARKNET_PRIVATE_KEY".to_string(), - get_env_var_or_panic("MADARA_ORCHESTRATOR_STARKNET_PRIVATE_KEY"), - ), - ( - "MADARA_ORCHESTRATOR_STARKNET_ACCOUNT_ADDRESS".to_string(), - get_env_var_or_panic("MADARA_ORCHESTRATOR_STARKNET_ACCOUNT_ADDRESS"), - ), - ( - "MADARA_ORCHESTRATOR_STARKNET_CAIRO_CORE_CONTRACT_ADDRESS".to_string(), - get_env_var_or_panic("MADARA_ORCHESTRATOR_STARKNET_CAIRO_CORE_CONTRACT_ADDRESS"), - ), - ( - "MADARA_ORCHESTRATOR_STARKNET_FINALITY_RETRY_WAIT_IN_SECS".to_string(), - get_env_var_or_panic("MADARA_ORCHESTRATOR_STARKNET_FINALITY_RETRY_WAIT_IN_SECS"), - ), - // ( - // "MADARA_ORCHESTRATOR_MADARA_BINARY_PATH".to_string(), - // get_env_var_or_panic("MADARA_ORCHESTRATOR_MADARA_BINARY_PATH"), - // ), - // Storage - ( - "MADARA_ORCHESTRATOR_AWS_S3_BUCKET_NAME".to_string(), - get_env_var_or_panic("MADARA_ORCHESTRATOR_AWS_S3_BUCKET_NAME"), - ), - // Instrumentation - ( - "MADARA_ORCHESTRATOR_OTEL_SERVICE_NAME".to_string(), - get_env_var_or_panic("MADARA_ORCHESTRATOR_OTEL_SERVICE_NAME"), - ), - // Server - ("MADARA_ORCHESTRATOR_HOST".to_string(), get_env_var_or_panic("MADARA_ORCHESTRATOR_HOST")), - ("MADARA_ORCHESTRATOR_PORT".to_string(), get_env_var_or_panic("MADARA_ORCHESTRATOR_PORT")), - // Service - // ("MADARA_ORCHESTRATOR_MAX_BLOCK_NO_TO_PROCESS".to_string(), - // get_env_var_or_panic("MADARA_ORCHESTRATOR_MAX_BLOCK_NO_TO_PROCESS")), - // ( - // "MADARA_ORCHESTRATOR_MIN_BLOCK_NO_TO_PROCESS".to_string(), - // get_env_var_or_panic("MADARA_ORCHESTRATOR_MIN_BLOCK_NO_TO_PROCESS"), - // ), - // SNOS - ("MADARA_ORCHESTRATOR_RPC_FOR_SNOS".to_string(), get_env_var_or_panic("MADARA_ORCHESTRATOR_RPC_FOR_SNOS")), - ]; - env_vec -}