From ba1582787511683fe74f871d4639586ba652f281 Mon Sep 17 00:00:00 2001 From: Aditya Arora Date: Thu, 24 Jul 2025 15:05:07 -0400 Subject: [PATCH 01/10] chore(fortuna) Config API --- apps/fortuna/src/api.rs | 4 +++- apps/fortuna/src/api/config.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 apps/fortuna/src/api/config.rs diff --git a/apps/fortuna/src/api.rs b/apps/fortuna/src/api.rs index 5f7ab2cf24..4c52b2c1e4 100644 --- a/apps/fortuna/src/api.rs +++ b/apps/fortuna/src/api.rs @@ -22,7 +22,7 @@ use { tokio::sync::RwLock, url::Url, }; -pub use {chain_ids::*, explorer::*, index::*, live::*, metrics::*, ready::*, revelation::*}; +pub use {chain_ids::*, config::*, explorer::*, index::*, live::*, metrics::*, ready::*, revelation::*}; mod chain_ids; mod explorer; @@ -31,6 +31,7 @@ mod live; mod metrics; mod ready; mod revelation; +mod config; pub type ChainId = String; pub type NetworkId = u64; @@ -211,6 +212,7 @@ pub fn routes(state: ApiState) -> Router<(), Body> { "/v1/chains/:chain_id/revelations/:sequence", get(revelation), ) + .route("/v1/chains/configs", get(get_chain_configs)) .with_state(state) } diff --git a/apps/fortuna/src/api/config.rs b/apps/fortuna/src/api/config.rs new file mode 100644 index 0000000000..4740848b1b --- /dev/null +++ b/apps/fortuna/src/api/config.rs @@ -0,0 +1,30 @@ +use crate::{api::{ApiState, RestError}, config::Config}; +use axum::{extract::State, Json}; + +#[derive(serde::Serialize)] +pub struct ChainConfigSummary { + pub name: String, + pub contract_addr: String, + pub reveal_delay_blocks: u64, + pub gas_limit: u32, + pub fee: u128, +} + +pub async fn get_chain_configs(State(_state): State) -> Result>, RestError> { + // Try to load the config file (assume default path for now) + let config = match Config::load("config.yaml") { + Ok(cfg) => cfg, + Err(_) => return Err(RestError::Unknown), + }; + let mut configs = Vec::new(); + for (name, chain) in config.chains.iter() { + configs.push(ChainConfigSummary { + name: name.clone(), + contract_addr: format!("0x{:x}", chain.contract_addr), + reveal_delay_blocks: chain.reveal_delay_blocks, + gas_limit: chain.gas_limit, + fee: chain.fee, + }); + } + Ok(Json(configs)) +} \ No newline at end of file From 11f6e6a7dc2466b617ed954d0c89e8d118507e38 Mon Sep 17 00:00:00 2001 From: Aditya Arora Date: Thu, 24 Jul 2025 15:39:47 -0400 Subject: [PATCH 02/10] update --- apps/fortuna/src/api/config.rs | 9 ++++----- apps/fortuna/src/command/run.rs | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/fortuna/src/api/config.rs b/apps/fortuna/src/api/config.rs index 4740848b1b..3a136b1f5e 100644 --- a/apps/fortuna/src/api/config.rs +++ b/apps/fortuna/src/api/config.rs @@ -1,5 +1,6 @@ use crate::{api::{ApiState, RestError}, config::Config}; use axum::{extract::State, Json}; +use anyhow::{anyhow, Error}; #[derive(serde::Serialize)] pub struct ChainConfigSummary { @@ -10,12 +11,10 @@ pub struct ChainConfigSummary { pub fee: u128, } -pub async fn get_chain_configs(State(_state): State) -> Result>, RestError> { +pub async fn get_chain_configs(State(_state): State) -> Result>, Error> { // Try to load the config file (assume default path for now) - let config = match Config::load("config.yaml") { - Ok(cfg) => cfg, - Err(_) => return Err(RestError::Unknown), - }; + let yaml_content = std::fs::read_to_string("../config.yaml").map_err(|e| anyhow!("Failed to read config file: {}", e))?; + let config: Config = serde_yaml::from_str(&yaml_content).map_err(|e| anyhow!("Failed to parse config file: {}", e))?; let mut configs = Vec::new(); for (name, chain) in config.chains.iter() { configs.push(ChainConfigSummary { diff --git a/apps/fortuna/src/command/run.rs b/apps/fortuna/src/command/run.rs index a06909de78..ca071a0c3a 100644 --- a/apps/fortuna/src/command/run.rs +++ b/apps/fortuna/src/command/run.rs @@ -85,7 +85,7 @@ pub async fn run_api( pub async fn run(opts: &RunOptions) -> Result<()> { // Load environment variables from a .env file if present - let _ = dotenv::dotenv()?; + let _ = dotenv::dotenv().map_err(|e| anyhow!("Failed to load .env file: {}", e))?; let config = Config::load(&opts.config.config)?; let secret = config.provider.secret.load()?.ok_or(anyhow!( "Please specify a provider secret in the config file." From 0eae35a760e3535b1f182f6f1486fe50303e3718 Mon Sep 17 00:00:00 2001 From: Tejas Badadare Date: Thu, 24 Jul 2025 12:50:22 -0700 Subject: [PATCH 03/10] push --- apps/fortuna/src/api.rs | 6 ++++-- apps/fortuna/src/api/config.rs | 23 ++++++++++++++++------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/apps/fortuna/src/api.rs b/apps/fortuna/src/api.rs index 4c52b2c1e4..133285854f 100644 --- a/apps/fortuna/src/api.rs +++ b/apps/fortuna/src/api.rs @@ -22,16 +22,18 @@ use { tokio::sync::RwLock, url::Url, }; -pub use {chain_ids::*, config::*, explorer::*, index::*, live::*, metrics::*, ready::*, revelation::*}; +pub use { + chain_ids::*, config::*, explorer::*, index::*, live::*, metrics::*, ready::*, revelation::*, +}; mod chain_ids; +mod config; mod explorer; mod index; mod live; mod metrics; mod ready; mod revelation; -mod config; pub type ChainId = String; pub type NetworkId = u64; diff --git a/apps/fortuna/src/api/config.rs b/apps/fortuna/src/api/config.rs index 3a136b1f5e..4f45a2ef1d 100644 --- a/apps/fortuna/src/api/config.rs +++ b/apps/fortuna/src/api/config.rs @@ -1,6 +1,8 @@ -use crate::{api::{ApiState, RestError}, config::Config}; +use crate::{ + api::{ApiState, RestError}, + config::Config, +}; use axum::{extract::State, Json}; -use anyhow::{anyhow, Error}; #[derive(serde::Serialize)] pub struct ChainConfigSummary { @@ -11,10 +13,17 @@ pub struct ChainConfigSummary { pub fee: u128, } -pub async fn get_chain_configs(State(_state): State) -> Result>, Error> { - // Try to load the config file (assume default path for now) - let yaml_content = std::fs::read_to_string("../config.yaml").map_err(|e| anyhow!("Failed to read config file: {}", e))?; - let config: Config = serde_yaml::from_str(&yaml_content).map_err(|e| anyhow!("Failed to parse config file: {}", e))?; +pub async fn get_chain_configs( + State(_state): State, +) -> anyhow::Result>, RestError> { + let yaml_content = std::fs::read_to_string("config.yaml").map_err(|e| { + tracing::error!("Failed to read config file: {}", e); + RestError::Unknown + })?; + let config: Config = serde_yaml::from_str(&yaml_content).map_err(|e| { + tracing::error!("Failed to parse config file: {}", e); + RestError::Unknown + })?; let mut configs = Vec::new(); for (name, chain) in config.chains.iter() { configs.push(ChainConfigSummary { @@ -26,4 +35,4 @@ pub async fn get_chain_configs(State(_state): State) -> Result Date: Thu, 24 Jul 2025 19:09:15 -0400 Subject: [PATCH 04/10] requested comments --- apps/fortuna/src/api.rs | 218 +++++++++++++++++- apps/fortuna/src/api/config.rs | 24 +- apps/fortuna/src/command/run.rs | 4 +- .../cosmwasm/examples/cw-contract/Cargo.lock | 8 +- 4 files changed, 232 insertions(+), 22 deletions(-) diff --git a/apps/fortuna/src/api.rs b/apps/fortuna/src/api.rs index 133285854f..019cd2ff67 100644 --- a/apps/fortuna/src/api.rs +++ b/apps/fortuna/src/api.rs @@ -1,6 +1,7 @@ use { crate::{ chain::reader::{BlockNumber, BlockStatus, EntropyReader}, + config::Config, history::History, state::MonitoredHashChainState, }, @@ -76,6 +77,9 @@ pub struct ApiState { pub metrics: Arc, pub explorer_metrics: Arc, + + /// Parsed configuration + pub config: Config, } impl ApiState { @@ -83,6 +87,7 @@ impl ApiState { chains: Arc>>, metrics_registry: Arc>, history: Arc, + config: Config, ) -> ApiState { let metrics = ApiMetrics { http_requests: Family::default(), @@ -103,6 +108,7 @@ impl ApiState { explorer_metrics, history, metrics_registry, + config, } } } @@ -234,9 +240,10 @@ mod test { crate::{ api::{ self, ApiBlockChainState, ApiState, BinaryEncoding, Blob, BlockchainState, - GetRandomValueResponse, + ChainConfigSummary, GetRandomValueResponse, }, chain::reader::{mock::MockEntropyReader, BlockStatus}, + config::Config, history::History, state::{HashChainState, MonitoredHashChainState, PebbleHashChain}, }, @@ -315,10 +322,40 @@ mod test { ApiBlockChainState::Initialized(avax_state), ); + // Create a minimal config for testing + let config = Config { + chains: HashMap::new(), + provider: crate::config::ProviderConfig { + uri: "http://localhost:8080/".to_string(), + address: PROVIDER, + private_key: crate::config::SecretString { + value: Some("0xabcd".to_string()), + file: None, + }, + secret: crate::config::SecretString { + value: Some("abcd".to_string()), + file: None, + }, + chain_length: 100000, + chain_sample_interval: 10, + fee_manager: None, + }, + keeper: crate::config::KeeperConfig { + private_key: crate::config::SecretString { + value: Some("0xabcd".to_string()), + file: None, + }, + fee_manager_private_key: None, + other_keeper_addresses: vec![], + replica_config: None, + }, + }; + let api_state = ApiState::new( Arc::new(RwLock::new(chains)), metrics_registry, Arc::new(History::new().await.unwrap()), + config, ) .await; @@ -538,4 +575,183 @@ mod test { ) .await; } + + #[tokio::test] + async fn test_chain_configs() { + let (server, _, _) = test_server().await; + + // Test the chain configs endpoint + let response = server.get("/v1/chains/configs").await; + response.assert_status(StatusCode::OK); + + // Parse the response as JSON + let configs: Vec = response.json(); + + // Verify the response structure - should be empty for test server + assert_eq!(configs.len(), 0, "Should return empty configs for test server"); + } + + #[tokio::test] + async fn test_chain_configs_with_data() { + // Create a test server with actual chain configurations + let eth_read = Arc::new(MockEntropyReader::with_requests(10, &[])); + let avax_read = Arc::new(MockEntropyReader::with_requests(10, &[])); + + let eth_state = MonitoredHashChainState::new( + ETH_CHAIN.clone(), + Default::default(), + "ethereum".into(), + PROVIDER, + ); + + let eth_state = BlockchainState { + id: "ethereum".into(), + network_id: 1, + state: Arc::new(eth_state), + contract: eth_read.clone(), + provider_address: PROVIDER, + reveal_delay_blocks: 1, + confirmed_block_status: BlockStatus::Latest, + }; + + let avax_state = MonitoredHashChainState::new( + AVAX_CHAIN.clone(), + Default::default(), + "avalanche".into(), + PROVIDER, + ); + + let avax_state = BlockchainState { + id: "avalanche".into(), + network_id: 43114, + state: Arc::new(avax_state), + contract: avax_read.clone(), + provider_address: PROVIDER, + reveal_delay_blocks: 2, + confirmed_block_status: BlockStatus::Latest, + }; + + let mut chains = HashMap::new(); + chains.insert( + "ethereum".into(), + ApiBlockChainState::Initialized(eth_state), + ); + chains.insert( + "avalanche".into(), + ApiBlockChainState::Initialized(avax_state), + ); + + // Create a config with actual chain data + let mut config_chains = HashMap::new(); + config_chains.insert( + "ethereum".to_string(), + crate::config::EthereumConfig { + geth_rpc_addr: "http://localhost:8545".to_string(), + contract_addr: Address::from_low_u64_be(0x1234), + reveal_delay_blocks: 1, + confirmed_block_status: BlockStatus::Latest, + backlog_range: 1000, + legacy_tx: false, + gas_limit: 500000, + priority_fee_multiplier_pct: 100, + escalation_policy: crate::config::EscalationPolicyConfig::default(), + min_profit_pct: 0, + target_profit_pct: 20, + max_profit_pct: 100, + min_keeper_balance: 100000000000000000, + fee: 1500000000000000, + sync_fee_only_on_register: true, + commitments: None, + max_num_hashes: None, + block_delays: vec![5], + }, + ); + config_chains.insert( + "avalanche".to_string(), + crate::config::EthereumConfig { + geth_rpc_addr: "http://localhost:9650".to_string(), + contract_addr: Address::from_low_u64_be(0x5678), + reveal_delay_blocks: 2, + confirmed_block_status: BlockStatus::Latest, + backlog_range: 1000, + legacy_tx: false, + gas_limit: 600000, + priority_fee_multiplier_pct: 100, + escalation_policy: crate::config::EscalationPolicyConfig::default(), + min_profit_pct: 0, + target_profit_pct: 20, + max_profit_pct: 100, + min_keeper_balance: 100000000000000000, + fee: 2000000000000000, + sync_fee_only_on_register: true, + commitments: None, + max_num_hashes: None, + block_delays: vec![5], + }, + ); + + let config = Config { + chains: config_chains, + provider: crate::config::ProviderConfig { + uri: "http://localhost:8080/".to_string(), + address: PROVIDER, + private_key: crate::config::SecretString { + value: Some("0xabcd".to_string()), + file: None, + }, + secret: crate::config::SecretString { + value: Some("abcd".to_string()), + file: None, + }, + chain_length: 100000, + chain_sample_interval: 10, + fee_manager: None, + }, + keeper: crate::config::KeeperConfig { + private_key: crate::config::SecretString { + value: Some("0xabcd".to_string()), + file: None, + }, + fee_manager_private_key: None, + other_keeper_addresses: vec![], + replica_config: None, + }, + }; + + let metrics_registry = Arc::new(RwLock::new(Registry::default())); + let api_state = ApiState::new( + Arc::new(RwLock::new(chains)), + metrics_registry, + Arc::new(History::new().await.unwrap()), + config, + ) + .await; + + let app = api::routes(api_state); + let server = TestServer::new(app).unwrap(); + + // Test the chain configs endpoint + let response = server.get("/v1/chains/configs").await; + response.assert_status(StatusCode::OK); + + // Parse the response as JSON + let configs: Vec = response.json(); + + // Verify we have 2 chains + assert_eq!(configs.len(), 2, "Should return 2 chain configs"); + + // Find ethereum config + let eth_config = configs.iter().find(|c| c.name == "ethereum").expect("Ethereum config not found"); + assert_eq!(eth_config.contract_addr, "0x0000000000000000000000000000000000001234"); + assert_eq!(eth_config.reveal_delay_blocks, 1); + assert_eq!(eth_config.gas_limit, 500000); + assert_eq!(eth_config.fee, 1500000000000000); + + // Find avalanche config + let avax_config = configs.iter().find(|c| c.name == "avalanche").expect("Avalanche config not found"); + assert_eq!(avax_config.contract_addr, "0x0000000000000000000000000000000000005678"); + assert_eq!(avax_config.reveal_delay_blocks, 2); + assert_eq!(avax_config.gas_limit, 600000); + assert_eq!(avax_config.fee, 2000000000000000); + } } diff --git a/apps/fortuna/src/api/config.rs b/apps/fortuna/src/api/config.rs index 4f45a2ef1d..aa430369db 100644 --- a/apps/fortuna/src/api/config.rs +++ b/apps/fortuna/src/api/config.rs @@ -1,10 +1,10 @@ -use crate::{ - api::{ApiState, RestError}, - config::Config, +use { + crate::api::{ApiState, RestError}, + axum::{extract::State, Json}, + serde::Serialize, }; -use axum::{extract::State, Json}; -#[derive(serde::Serialize)] +#[derive(Serialize, serde::Deserialize)] pub struct ChainConfigSummary { pub name: String, pub contract_addr: String, @@ -13,19 +13,9 @@ pub struct ChainConfigSummary { pub fee: u128, } -pub async fn get_chain_configs( - State(_state): State, -) -> anyhow::Result>, RestError> { - let yaml_content = std::fs::read_to_string("config.yaml").map_err(|e| { - tracing::error!("Failed to read config file: {}", e); - RestError::Unknown - })?; - let config: Config = serde_yaml::from_str(&yaml_content).map_err(|e| { - tracing::error!("Failed to parse config file: {}", e); - RestError::Unknown - })?; +pub async fn get_chain_configs(State(state): State) -> Result>, RestError> { let mut configs = Vec::new(); - for (name, chain) in config.chains.iter() { + for (name, chain) in state.config.chains.iter() { configs.push(ChainConfigSummary { name: name.clone(), contract_addr: format!("0x{:x}", chain.contract_addr), diff --git a/apps/fortuna/src/command/run.rs b/apps/fortuna/src/command/run.rs index ca071a0c3a..53f8988d5f 100644 --- a/apps/fortuna/src/command/run.rs +++ b/apps/fortuna/src/command/run.rs @@ -28,6 +28,7 @@ pub async fn run_api( chains: Arc>>, metrics_registry: Arc>, history: Arc, + config: Config, mut rx_exit: watch::Receiver, ) -> Result<()> { #[derive(OpenApi)] @@ -54,7 +55,7 @@ pub async fn run_api( )] struct ApiDoc; - let api_state = api::ApiState::new(chains, metrics_registry, history).await; + let api_state = api::ApiState::new(chains, metrics_registry, history, config).await; // Initialize Axum Router. Note the type here is a `Router` due to the use of the // `with_state` method which replaces `Body` with `State` in the type signature. @@ -170,6 +171,7 @@ pub async fn run(opts: &RunOptions) -> Result<()> { chains.clone(), metrics_registry.clone(), history, + config, rx_exit, ) .await?; diff --git a/target_chains/cosmwasm/examples/cw-contract/Cargo.lock b/target_chains/cosmwasm/examples/cw-contract/Cargo.lock index c255e5b155..b482f3fc0f 100644 --- a/target_chains/cosmwasm/examples/cw-contract/Cargo.lock +++ b/target_chains/cosmwasm/examples/cw-contract/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "ahash" @@ -485,7 +485,9 @@ dependencies = [ [[package]] name = "pyth-sdk-cw" -version = "0.1.0" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c04e9f2961bce1ef13b09afcdb5aee7d4ddde83669e5f9d2824ba422cb00de48" dependencies = [ "cosmwasm-schema", "cosmwasm-std", @@ -747,4 +749,4 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" name = "zeroize" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" \ No newline at end of file +checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" From 57ba820a0fa7d6a6482efe33631a4fdb2323191a Mon Sep 17 00:00:00 2001 From: Aditya Arora Date: Thu, 24 Jul 2025 19:11:53 -0400 Subject: [PATCH 05/10] fmt changes --- apps/fortuna/src/api.rs | 34 +++++++++++++++++++++++++--------- apps/fortuna/src/api/config.rs | 4 +++- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/apps/fortuna/src/api.rs b/apps/fortuna/src/api.rs index 019cd2ff67..f29bfc0f6c 100644 --- a/apps/fortuna/src/api.rs +++ b/apps/fortuna/src/api.rs @@ -586,9 +586,13 @@ mod test { // Parse the response as JSON let configs: Vec = response.json(); - + // Verify the response structure - should be empty for test server - assert_eq!(configs.len(), 0, "Should return empty configs for test server"); + assert_eq!( + configs.len(), + 0, + "Should return empty configs for test server" + ); } #[tokio::test] @@ -736,20 +740,32 @@ mod test { // Parse the response as JSON let configs: Vec = response.json(); - + // Verify we have 2 chains assert_eq!(configs.len(), 2, "Should return 2 chain configs"); - + // Find ethereum config - let eth_config = configs.iter().find(|c| c.name == "ethereum").expect("Ethereum config not found"); - assert_eq!(eth_config.contract_addr, "0x0000000000000000000000000000000000001234"); + let eth_config = configs + .iter() + .find(|c| c.name == "ethereum") + .expect("Ethereum config not found"); + assert_eq!( + eth_config.contract_addr, + "0x0000000000000000000000000000000000001234" + ); assert_eq!(eth_config.reveal_delay_blocks, 1); assert_eq!(eth_config.gas_limit, 500000); assert_eq!(eth_config.fee, 1500000000000000); - + // Find avalanche config - let avax_config = configs.iter().find(|c| c.name == "avalanche").expect("Avalanche config not found"); - assert_eq!(avax_config.contract_addr, "0x0000000000000000000000000000000000005678"); + let avax_config = configs + .iter() + .find(|c| c.name == "avalanche") + .expect("Avalanche config not found"); + assert_eq!( + avax_config.contract_addr, + "0x0000000000000000000000000000000000005678" + ); assert_eq!(avax_config.reveal_delay_blocks, 2); assert_eq!(avax_config.gas_limit, 600000); assert_eq!(avax_config.fee, 2000000000000000); diff --git a/apps/fortuna/src/api/config.rs b/apps/fortuna/src/api/config.rs index aa430369db..7fc00e7104 100644 --- a/apps/fortuna/src/api/config.rs +++ b/apps/fortuna/src/api/config.rs @@ -13,7 +13,9 @@ pub struct ChainConfigSummary { pub fee: u128, } -pub async fn get_chain_configs(State(state): State) -> Result>, RestError> { +pub async fn get_chain_configs( + State(state): State, +) -> Result>, RestError> { let mut configs = Vec::new(); for (name, chain) in state.config.chains.iter() { configs.push(ChainConfigSummary { From aee6404a9d8fefa8565aaa6d8b42925ead22ee8b Mon Sep 17 00:00:00 2001 From: Aditya Arora Date: Fri, 25 Jul 2025 09:36:51 -0400 Subject: [PATCH 06/10] fix --- apps/fortuna/src/api.rs | 7 +++---- apps/fortuna/src/command/run.rs | 8 ++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/fortuna/src/api.rs b/apps/fortuna/src/api.rs index f29bfc0f6c..83a7e2fc29 100644 --- a/apps/fortuna/src/api.rs +++ b/apps/fortuna/src/api.rs @@ -78,8 +78,7 @@ pub struct ApiState { pub explorer_metrics: Arc, - /// Parsed configuration - pub config: Config, + pub config: Arc, } impl ApiState { @@ -87,7 +86,7 @@ impl ApiState { chains: Arc>>, metrics_registry: Arc>, history: Arc, - config: Config, + config: Arc, ) -> ApiState { let metrics = ApiMetrics { http_requests: Family::default(), @@ -108,7 +107,7 @@ impl ApiState { explorer_metrics, history, metrics_registry, - config, + config: config.clone(), } } } diff --git a/apps/fortuna/src/command/run.rs b/apps/fortuna/src/command/run.rs index 53f8988d5f..21c1aaffa1 100644 --- a/apps/fortuna/src/command/run.rs +++ b/apps/fortuna/src/command/run.rs @@ -28,7 +28,7 @@ pub async fn run_api( chains: Arc>>, metrics_registry: Arc>, history: Arc, - config: Config, + config: Arc, mut rx_exit: watch::Receiver, ) -> Result<()> { #[derive(OpenApi)] @@ -55,7 +55,7 @@ pub async fn run_api( )] struct ApiDoc; - let api_state = api::ApiState::new(chains, metrics_registry, history, config).await; + let api_state = api::ApiState::new(chains, metrics_registry, history, config.clone()).await; // Initialize Axum Router. Note the type here is a `Router` due to the use of the // `with_state` method which replaces `Body` with `State` in the type signature. @@ -87,7 +87,7 @@ pub async fn run_api( pub async fn run(opts: &RunOptions) -> Result<()> { // Load environment variables from a .env file if present let _ = dotenv::dotenv().map_err(|e| anyhow!("Failed to load .env file: {}", e))?; - let config = Config::load(&opts.config.config)?; + let config = Arc::new(Config::load(&opts.config.config)?); let secret = config.provider.secret.load()?.ok_or(anyhow!( "Please specify a provider secret in the config file." ))?; @@ -171,7 +171,7 @@ pub async fn run(opts: &RunOptions) -> Result<()> { chains.clone(), metrics_registry.clone(), history, - config, + config.clone(), rx_exit, ) .await?; From eb8a39bf918401b2cc971a341b0c5985f882141a Mon Sep 17 00:00:00 2001 From: Aditya Arora Date: Fri, 25 Jul 2025 09:44:45 -0400 Subject: [PATCH 07/10] requested changes --- apps/fortuna/src/api.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/fortuna/src/api.rs b/apps/fortuna/src/api.rs index 83a7e2fc29..ac726c0bcb 100644 --- a/apps/fortuna/src/api.rs +++ b/apps/fortuna/src/api.rs @@ -354,7 +354,7 @@ mod test { Arc::new(RwLock::new(chains)), metrics_registry, Arc::new(History::new().await.unwrap()), - config, + Arc::new(config), ) .await; @@ -726,7 +726,7 @@ mod test { Arc::new(RwLock::new(chains)), metrics_registry, Arc::new(History::new().await.unwrap()), - config, + Arc::new(config), ) .await; From 2e0679877641558c457c06326974650408e63d8d Mon Sep 17 00:00:00 2001 From: Aditya Arora Date: Fri, 25 Jul 2025 12:26:25 -0400 Subject: [PATCH 08/10] removed state in tests --- apps/fortuna/src/api.rs | 50 +---------------------------------------- 1 file changed, 1 insertion(+), 49 deletions(-) diff --git a/apps/fortuna/src/api.rs b/apps/fortuna/src/api.rs index ac726c0bcb..5fc0668c24 100644 --- a/apps/fortuna/src/api.rs +++ b/apps/fortuna/src/api.rs @@ -596,54 +596,6 @@ mod test { #[tokio::test] async fn test_chain_configs_with_data() { - // Create a test server with actual chain configurations - let eth_read = Arc::new(MockEntropyReader::with_requests(10, &[])); - let avax_read = Arc::new(MockEntropyReader::with_requests(10, &[])); - - let eth_state = MonitoredHashChainState::new( - ETH_CHAIN.clone(), - Default::default(), - "ethereum".into(), - PROVIDER, - ); - - let eth_state = BlockchainState { - id: "ethereum".into(), - network_id: 1, - state: Arc::new(eth_state), - contract: eth_read.clone(), - provider_address: PROVIDER, - reveal_delay_blocks: 1, - confirmed_block_status: BlockStatus::Latest, - }; - - let avax_state = MonitoredHashChainState::new( - AVAX_CHAIN.clone(), - Default::default(), - "avalanche".into(), - PROVIDER, - ); - - let avax_state = BlockchainState { - id: "avalanche".into(), - network_id: 43114, - state: Arc::new(avax_state), - contract: avax_read.clone(), - provider_address: PROVIDER, - reveal_delay_blocks: 2, - confirmed_block_status: BlockStatus::Latest, - }; - - let mut chains = HashMap::new(); - chains.insert( - "ethereum".into(), - ApiBlockChainState::Initialized(eth_state), - ); - chains.insert( - "avalanche".into(), - ApiBlockChainState::Initialized(avax_state), - ); - // Create a config with actual chain data let mut config_chains = HashMap::new(); config_chains.insert( @@ -723,7 +675,7 @@ mod test { let metrics_registry = Arc::new(RwLock::new(Registry::default())); let api_state = ApiState::new( - Arc::new(RwLock::new(chains)), + Arc::new(RwLock::new(HashMap::new())), metrics_registry, Arc::new(History::new().await.unwrap()), Arc::new(config), From 26cb6785d9c656a28d6dfa8b8986fcabacb336ae Mon Sep 17 00:00:00 2001 From: Aditya Arora Date: Fri, 25 Jul 2025 12:42:48 -0400 Subject: [PATCH 09/10] arc -> & --- apps/fortuna/src/api.rs | 8 ++++---- apps/fortuna/src/command/run.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/fortuna/src/api.rs b/apps/fortuna/src/api.rs index 5fc0668c24..8e80f3cd4f 100644 --- a/apps/fortuna/src/api.rs +++ b/apps/fortuna/src/api.rs @@ -78,7 +78,7 @@ pub struct ApiState { pub explorer_metrics: Arc, - pub config: Arc, + pub config: Config, } impl ApiState { @@ -86,7 +86,7 @@ impl ApiState { chains: Arc>>, metrics_registry: Arc>, history: Arc, - config: Arc, + config: &Config, ) -> ApiState { let metrics = ApiMetrics { http_requests: Family::default(), @@ -354,7 +354,7 @@ mod test { Arc::new(RwLock::new(chains)), metrics_registry, Arc::new(History::new().await.unwrap()), - Arc::new(config), + &config, ) .await; @@ -678,7 +678,7 @@ mod test { Arc::new(RwLock::new(HashMap::new())), metrics_registry, Arc::new(History::new().await.unwrap()), - Arc::new(config), + &config, ) .await; diff --git a/apps/fortuna/src/command/run.rs b/apps/fortuna/src/command/run.rs index 21c1aaffa1..c9f630d6b7 100644 --- a/apps/fortuna/src/command/run.rs +++ b/apps/fortuna/src/command/run.rs @@ -28,7 +28,7 @@ pub async fn run_api( chains: Arc>>, metrics_registry: Arc>, history: Arc, - config: Arc, + config: &Config, mut rx_exit: watch::Receiver, ) -> Result<()> { #[derive(OpenApi)] @@ -55,7 +55,7 @@ pub async fn run_api( )] struct ApiDoc; - let api_state = api::ApiState::new(chains, metrics_registry, history, config.clone()).await; + let api_state = api::ApiState::new(chains, metrics_registry, history, config).await; // Initialize Axum Router. Note the type here is a `Router` due to the use of the // `with_state` method which replaces `Body` with `State` in the type signature. @@ -87,7 +87,7 @@ pub async fn run_api( pub async fn run(opts: &RunOptions) -> Result<()> { // Load environment variables from a .env file if present let _ = dotenv::dotenv().map_err(|e| anyhow!("Failed to load .env file: {}", e))?; - let config = Arc::new(Config::load(&opts.config.config)?); + let config = Config::load(&opts.config.config)?; let secret = config.provider.secret.load()?.ok_or(anyhow!( "Please specify a provider secret in the config file." ))?; @@ -171,7 +171,7 @@ pub async fn run(opts: &RunOptions) -> Result<()> { chains.clone(), metrics_registry.clone(), history, - config.clone(), + &config, rx_exit, ) .await?; From 4e28e7951ac74b91f9dbef2709455f6ad1fac499 Mon Sep 17 00:00:00 2001 From: Aditya Arora Date: Fri, 25 Jul 2025 13:26:07 -0400 Subject: [PATCH 10/10] bump version --- Cargo.lock | 2 +- apps/fortuna/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f41a51eba4..da57b15857 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3071,7 +3071,7 @@ dependencies = [ [[package]] name = "fortuna" -version = "8.2.2" +version = "8.2.3" dependencies = [ "anyhow", "axum 0.6.20", diff --git a/apps/fortuna/Cargo.toml b/apps/fortuna/Cargo.toml index f21ee9918d..4451a05c2b 100644 --- a/apps/fortuna/Cargo.toml +++ b/apps/fortuna/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fortuna" -version = "8.2.2" +version = "8.2.3" edition = "2021" [lib]