|
|
@@ -1,6 +1,7 @@
|
|
|
use {
|
|
|
crate::{
|
|
|
chain::reader::{BlockNumber, BlockStatus, EntropyReader},
|
|
|
+ config::Config,
|
|
|
history::History,
|
|
|
state::MonitoredHashChainState,
|
|
|
},
|
|
|
@@ -22,9 +23,12 @@ 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 config;
|
|
|
mod explorer;
|
|
|
mod index;
|
|
|
mod live;
|
|
|
@@ -73,6 +77,8 @@ pub struct ApiState {
|
|
|
pub metrics: Arc<ApiMetrics>,
|
|
|
|
|
|
pub explorer_metrics: Arc<ExplorerMetrics>,
|
|
|
+
|
|
|
+ pub config: Config,
|
|
|
}
|
|
|
|
|
|
impl ApiState {
|
|
|
@@ -80,6 +86,7 @@ impl ApiState {
|
|
|
chains: Arc<RwLock<HashMap<ChainId, ApiBlockChainState>>>,
|
|
|
metrics_registry: Arc<RwLock<Registry>>,
|
|
|
history: Arc<History>,
|
|
|
+ config: &Config,
|
|
|
) -> ApiState {
|
|
|
let metrics = ApiMetrics {
|
|
|
http_requests: Family::default(),
|
|
|
@@ -100,6 +107,7 @@ impl ApiState {
|
|
|
explorer_metrics,
|
|
|
history,
|
|
|
metrics_registry,
|
|
|
+ config: config.clone(),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -211,6 +219,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)
|
|
|
}
|
|
|
|
|
|
@@ -230,9 +239,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},
|
|
|
},
|
|
|
@@ -311,10 +321,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;
|
|
|
|
|
|
@@ -534,4 +574,151 @@ 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<ChainConfigSummary> = 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 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(HashMap::new())),
|
|
|
+ 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<ChainConfigSummary> = 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);
|
|
|
+ }
|
|
|
}
|