From 5f91cc823f3811fea57e22a3984ccf4afbb61d99 Mon Sep 17 00:00:00 2001 From: Ivan Frolov Date: Tue, 16 Jul 2024 13:27:15 -0400 Subject: [PATCH 1/6] feat: added checks for config variables --- config.toml | 2 +- configuration/src/configs/database.rs | 6 +- configuration/src/configs/general.rs | 28 +++++-- configuration/src/configs/mod.rs | 115 ++++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 12 deletions(-) diff --git a/config.toml b/config.toml index 6ce50d85..e53a7a8e 100644 --- a/config.toml +++ b/config.toml @@ -11,7 +11,7 @@ redis_url = "${REDIS_URL}" [general.rpc_server] server_port = "${SERVER_PORT}" max_gas_burnt = "${MAX_GAS_BURNT}" -contract_code_cache_size = "${CONTRACT_CODE_CAHCE_SIZE}" +contract_code_cache_size = "${CONTRACT_CODE_CACHE_SIZE}" block_cache_size = "${BLOCK_CACHE_SIZE}" shadow_data_consistency_rate = "${SHADOW_DATA_CONSISTENCY_RATE}" prefetch_state_size_limit = "${PREFETCH_STATE_SIZE_LIMIT}" diff --git a/configuration/src/configs/database.rs b/configuration/src/configs/database.rs index 2572ee9a..6b381913 100644 --- a/configuration/src/configs/database.rs +++ b/configuration/src/configs/database.rs @@ -1,4 +1,4 @@ -use crate::configs::deserialize_data_or_env; +use crate::configs::{deserialize_data_or_env, deserialize_url_or_env}; use near_lake_framework::near_indexer_primitives::near_primitives; // Database connection URL @@ -9,7 +9,7 @@ type DatabaseConnectUrl = String; pub struct ShardDatabaseConfig { #[serde(deserialize_with = "deserialize_data_or_env")] pub shard_id: u64, - #[serde(deserialize_with = "deserialize_data_or_env")] + #[serde(deserialize_with = "deserialize_url_or_env")] pub database_url: DatabaseConnectUrl, } @@ -35,7 +35,7 @@ impl DatabaseConfig { #[derive(serde_derive::Deserialize, Debug, Clone, Default)] pub struct CommonDatabaseConfig { - #[serde(deserialize_with = "deserialize_data_or_env")] + #[serde(deserialize_with = "deserialize_url_or_env")] pub database_url: DatabaseConnectUrl, #[serde(default)] pub shards: Vec, diff --git a/configuration/src/configs/general.rs b/configuration/src/configs/general.rs index 6f6f9056..57a77601 100644 --- a/configuration/src/configs/general.rs +++ b/configuration/src/configs/general.rs @@ -3,7 +3,10 @@ use std::str::FromStr; use serde_derive::Deserialize; use crate::configs::{ - deserialize_data_or_env, deserialize_optional_data_or_env, required_value_or_panic, + deserialize_data_or_env, deserialize_optional_block_cache_size_or_env, + deserialize_optional_contract_code_cache_size_or_env, deserialize_optional_data_or_env, + deserialize_optional_shadow_data_consistency_rate_or_env, deserialize_optional_url_or_env, + required_value_or_panic, }; #[derive(Debug, Clone)] @@ -53,13 +56,13 @@ pub struct GeneralNearStateIndexerConfig { pub struct CommonGeneralConfig { #[serde(deserialize_with = "deserialize_data_or_env")] pub chain_id: ChainId, - #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] + #[serde(deserialize_with = "deserialize_optional_url_or_env", default)] pub near_rpc_url: Option, - #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] + #[serde(deserialize_with = "deserialize_optional_url_or_env", default)] pub near_archival_rpc_url: Option, - #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] + #[serde(deserialize_with = "deserialize_optional_url_or_env", default)] pub referer_header_value: Option, - #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] + #[serde(deserialize_with = "deserialize_optional_url_or_env", default)] pub redis_url: Option, #[serde(default)] pub rpc_server: CommonGeneralRpcServerConfig, @@ -101,11 +104,20 @@ pub struct CommonGeneralRpcServerConfig { pub server_port: Option, #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] pub max_gas_burnt: Option, - #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] + #[serde( + deserialize_with = "deserialize_optional_contract_code_cache_size_or_env", + default + )] pub contract_code_cache_size: Option, - #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] + #[serde( + deserialize_with = "deserialize_optional_block_cache_size_or_env", + default + )] pub block_cache_size: Option, - #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] + #[serde( + deserialize_with = "deserialize_optional_shadow_data_consistency_rate_or_env", + default + )] pub shadow_data_consistency_rate: Option, #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] pub prefetch_state_size_limit: Option, diff --git a/configuration/src/configs/mod.rs b/configuration/src/configs/mod.rs index 01951366..cbb9f0b4 100644 --- a/configuration/src/configs/mod.rs +++ b/configuration/src/configs/mod.rs @@ -59,6 +59,35 @@ where serde_json::from_value::(value).map_err(serde::de::Error::custom) } +fn deserialize_url_or_env<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + let value = serde_json::Value::deserialize(deserializer)?; + if let serde_json::Value::String(value) = &value { + if let Some(caps) = RE_NAME_ENV.captures(value) { + let env_value = + get_env_var::(&caps["env_name"]).map_err(serde::de::Error::custom)?; + if url::Url::parse(&env_value).is_ok() { + return Ok(env_value); + } else { + tracing::warn!("Failed to deserialize_url_or_env: Environment variable value should be a valid URL"); + return Err(serde::de::Error::custom( + "Environment variable value should be a valid URL", + )); + } + } + } + + let value = serde_json::from_value::(value).map_err(serde::de::Error::custom)?; + if url::Url::parse(&value).is_ok() { + Ok(value) + } else { + tracing::warn!("Failed to deserialize_url_or_env: Value should be a valid URL"); + Err(serde::de::Error::custom("Value should be a valid URL")) + } +} + fn deserialize_optional_data_or_env<'de, D, T>(data: D) -> Result, D::Error> where D: serde::Deserializer<'de>, @@ -74,6 +103,92 @@ where }) } +fn deserialize_optional_url_or_env<'de, D>(data: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + Ok(match deserialize_data_or_env::(data) { + Ok(value) => { + if url::Url::parse(&value).is_ok() { + Some(value.to_string()) + } else { + tracing::warn!( + "Failed to deserialize_optional_url_or_env: Value should be a valid URL" + ); + None + } + } + Err(err) => { + tracing::warn!("Failed to deserialize_optional_url_or_env: {:?}", err); + None + } + }) +} + +fn deserialize_optional_contract_code_cache_size_or_env<'de, D>( + data: D, +) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + Ok(match deserialize_data_or_env(data) { + Ok(value) => { + if value >= 0.0 { + Some(value) + } else { + tracing::warn!("Failed to deserialize_optional_contract_code_cache_size_or_env: Value should be greater than or equal to 0"); + None + } + } + Err(err) => { + tracing::warn!("Failed to deserialize_optional_data_or_env: {:?}", err); + None + } + }) +} + +fn deserialize_optional_block_cache_size_or_env<'de, D>(data: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + Ok(match deserialize_data_or_env(data) { + Ok(value) => { + if value >= 0.0 { + Some(value) + } else { + tracing::warn!("Failed to deserialize_optional_block_cache_size_or_env: Value should be greater than or equal to 0"); + None + } + } + Err(err) => { + tracing::warn!("Failed to deserialize_optional_data_or_env: {:?}", err); + None + } + }) +} + +fn deserialize_optional_shadow_data_consistency_rate_or_env<'de, D>( + data: D, +) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + Ok(match deserialize_data_or_env(data) { + Ok(value) => { + if (0.0..=100.0).contains(&value) { + Some(value) + } else { + tracing::warn!("Failed to deserialize_optional_shadow_data_consistency_rate_or_env: Value should be in range 0.0..100.0"); + None + } + } + Err(err) => { + tracing::warn!("Failed to deserialize_optional_data_or_env: {:?}", err); + None + } + }) +} + #[derive(Deserialize, Debug, Clone, Default)] pub struct CommonConfig { pub general: general::CommonGeneralConfig, From 17893ddbb23a163d60c7bafb833bae137ef9973a Mon Sep 17 00:00:00 2001 From: Ivan Frolov Date: Tue, 16 Jul 2024 17:25:35 -0400 Subject: [PATCH 2/6] refactor: used `validator` crate for config validation --- Cargo.lock | 31 +++++++ configuration/Cargo.toml | 1 + configuration/src/configs/database.rs | 15 ++-- configuration/src/configs/general.rs | 45 +++++----- configuration/src/configs/mod.rs | 120 +------------------------- configuration/src/lib.rs | 9 ++ 6 files changed, 78 insertions(+), 143 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 70d20764..a4f97ec0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1610,6 +1610,7 @@ dependencies = [ "tracing-stackdriver", "tracing-subscriber", "url", + "validator", ] [[package]] @@ -8813,6 +8814,36 @@ dependencies = [ "getrandom 0.2.15", ] +[[package]] +name = "validator" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db79c75af171630a3148bd3e6d7c4f42b6a9a014c2945bc5ed0020cbb8d9478e" +dependencies = [ + "idna", + "once_cell", + "regex", + "serde", + "serde_derive", + "serde_json", + "url", + "validator_derive", +] + +[[package]] +name = "validator_derive" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55591299b7007f551ed1eb79a684af7672c19c3193fb9e0a31936987bb2438ec" +dependencies = [ + "darling 0.20.10", + "once_cell", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.71", +] + [[package]] name = "valuable" version = "0.1.0" diff --git a/configuration/Cargo.toml b/configuration/Cargo.toml index f1024e18..c9902522 100644 --- a/configuration/Cargo.toml +++ b/configuration/Cargo.toml @@ -19,6 +19,7 @@ regex = "1.10.2" serde = "1.0.145" serde_derive = "1.0.145" serde_json = "1.0.108" +validator = { version = "0.18.1", features = ["derive"] } opentelemetry = { version = "0.19", features = ["rt-tokio-current-thread"] } opentelemetry-jaeger = { version = "0.18", features = [ "rt-tokio-current-thread", diff --git a/configuration/src/configs/database.rs b/configuration/src/configs/database.rs index 6b381913..e61fefc9 100644 --- a/configuration/src/configs/database.rs +++ b/configuration/src/configs/database.rs @@ -1,15 +1,18 @@ -use crate::configs::{deserialize_data_or_env, deserialize_url_or_env}; +use crate::configs::deserialize_data_or_env; +use validator::Validate; + use near_lake_framework::near_indexer_primitives::near_primitives; // Database connection URL // Example: "postgres://user:password@localhost:5432/dbname" type DatabaseConnectUrl = String; -#[derive(serde_derive::Deserialize, Debug, Clone, Default)] +#[derive(Validate, serde_derive::Deserialize, Debug, Clone, Default)] pub struct ShardDatabaseConfig { #[serde(deserialize_with = "deserialize_data_or_env")] pub shard_id: u64, - #[serde(deserialize_with = "deserialize_url_or_env")] + #[validate(url(message = "Invalid database shard URL"))] + #[serde(deserialize_with = "deserialize_data_or_env")] pub database_url: DatabaseConnectUrl, } @@ -33,10 +36,12 @@ impl DatabaseConfig { } } -#[derive(serde_derive::Deserialize, Debug, Clone, Default)] +#[derive(Validate, serde_derive::Deserialize, Debug, Clone, Default)] pub struct CommonDatabaseConfig { - #[serde(deserialize_with = "deserialize_url_or_env")] + #[validate(url(message = "Invalid database URL"))] + #[serde(deserialize_with = "deserialize_data_or_env")] pub database_url: DatabaseConnectUrl, + #[validate(nested)] #[serde(default)] pub shards: Vec, } diff --git a/configuration/src/configs/general.rs b/configuration/src/configs/general.rs index 57a77601..66a2c0bc 100644 --- a/configuration/src/configs/general.rs +++ b/configuration/src/configs/general.rs @@ -1,12 +1,10 @@ use std::str::FromStr; use serde_derive::Deserialize; +use validator::Validate; use crate::configs::{ - deserialize_data_or_env, deserialize_optional_block_cache_size_or_env, - deserialize_optional_contract_code_cache_size_or_env, deserialize_optional_data_or_env, - deserialize_optional_shadow_data_consistency_rate_or_env, deserialize_optional_url_or_env, - required_value_or_panic, + deserialize_data_or_env, deserialize_optional_data_or_env, required_value_or_panic, }; #[derive(Debug, Clone)] @@ -52,18 +50,23 @@ pub struct GeneralNearStateIndexerConfig { pub concurrency: usize, } -#[derive(Deserialize, Debug, Clone, Default)] +#[derive(Validate, Deserialize, Debug, Clone, Default)] pub struct CommonGeneralConfig { #[serde(deserialize_with = "deserialize_data_or_env")] pub chain_id: ChainId, - #[serde(deserialize_with = "deserialize_optional_url_or_env", default)] + #[validate(url(message = "Invalid NEAR RPC URL"))] + #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] pub near_rpc_url: Option, - #[serde(deserialize_with = "deserialize_optional_url_or_env", default)] + #[validate(url(message = "Invalid NEAR Archival RPC URL"))] + #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] pub near_archival_rpc_url: Option, - #[serde(deserialize_with = "deserialize_optional_url_or_env", default)] + #[validate(url(message = "Invalid referer header value"))] + #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] pub referer_header_value: Option, - #[serde(deserialize_with = "deserialize_optional_url_or_env", default)] + #[validate(url(message = "Invalid Redis URL"))] + #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] pub redis_url: Option, + #[validate(nested)] #[serde(default)] pub rpc_server: CommonGeneralRpcServerConfig, #[serde(default)] @@ -98,26 +101,24 @@ impl FromStr for ChainId { } } -#[derive(Deserialize, Debug, Clone)] +#[derive(Validate, Deserialize, Debug, Clone)] pub struct CommonGeneralRpcServerConfig { #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] pub server_port: Option, #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] pub max_gas_burnt: Option, - #[serde( - deserialize_with = "deserialize_optional_contract_code_cache_size_or_env", - default - )] + #[validate(range(min = 0.0, message = "Contract code cache size must be greater than 0"))] + #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] pub contract_code_cache_size: Option, - #[serde( - deserialize_with = "deserialize_optional_block_cache_size_or_env", - default - )] + #[validate(range(min = 0.0, message = "Block cache size must be greater than 0"))] + #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] pub block_cache_size: Option, - #[serde( - deserialize_with = "deserialize_optional_shadow_data_consistency_rate_or_env", - default - )] + #[validate(range( + min = 0.0, + max = 100.0, + message = "Shadow data consistency rate must be between 0 and 100" + ))] + #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] pub shadow_data_consistency_rate: Option, #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] pub prefetch_state_size_limit: Option, diff --git a/configuration/src/configs/mod.rs b/configuration/src/configs/mod.rs index cbb9f0b4..f7064d66 100644 --- a/configuration/src/configs/mod.rs +++ b/configuration/src/configs/mod.rs @@ -4,6 +4,7 @@ use near_lake_framework::{ near_indexer_primitives, near_indexer_primitives::views::StateChangeValueView, }; use serde::Deserialize; +use validator::Validate; pub(crate) mod database; pub(crate) mod general; @@ -59,35 +60,6 @@ where serde_json::from_value::(value).map_err(serde::de::Error::custom) } -fn deserialize_url_or_env<'de, D>(deserializer: D) -> Result -where - D: serde::Deserializer<'de>, -{ - let value = serde_json::Value::deserialize(deserializer)?; - if let serde_json::Value::String(value) = &value { - if let Some(caps) = RE_NAME_ENV.captures(value) { - let env_value = - get_env_var::(&caps["env_name"]).map_err(serde::de::Error::custom)?; - if url::Url::parse(&env_value).is_ok() { - return Ok(env_value); - } else { - tracing::warn!("Failed to deserialize_url_or_env: Environment variable value should be a valid URL"); - return Err(serde::de::Error::custom( - "Environment variable value should be a valid URL", - )); - } - } - } - - let value = serde_json::from_value::(value).map_err(serde::de::Error::custom)?; - if url::Url::parse(&value).is_ok() { - Ok(value) - } else { - tracing::warn!("Failed to deserialize_url_or_env: Value should be a valid URL"); - Err(serde::de::Error::custom("Value should be a valid URL")) - } -} - fn deserialize_optional_data_or_env<'de, D, T>(data: D) -> Result, D::Error> where D: serde::Deserializer<'de>, @@ -103,98 +75,14 @@ where }) } -fn deserialize_optional_url_or_env<'de, D>(data: D) -> Result, D::Error> -where - D: serde::Deserializer<'de>, -{ - Ok(match deserialize_data_or_env::(data) { - Ok(value) => { - if url::Url::parse(&value).is_ok() { - Some(value.to_string()) - } else { - tracing::warn!( - "Failed to deserialize_optional_url_or_env: Value should be a valid URL" - ); - None - } - } - Err(err) => { - tracing::warn!("Failed to deserialize_optional_url_or_env: {:?}", err); - None - } - }) -} - -fn deserialize_optional_contract_code_cache_size_or_env<'de, D>( - data: D, -) -> Result, D::Error> -where - D: serde::Deserializer<'de>, -{ - Ok(match deserialize_data_or_env(data) { - Ok(value) => { - if value >= 0.0 { - Some(value) - } else { - tracing::warn!("Failed to deserialize_optional_contract_code_cache_size_or_env: Value should be greater than or equal to 0"); - None - } - } - Err(err) => { - tracing::warn!("Failed to deserialize_optional_data_or_env: {:?}", err); - None - } - }) -} - -fn deserialize_optional_block_cache_size_or_env<'de, D>(data: D) -> Result, D::Error> -where - D: serde::Deserializer<'de>, -{ - Ok(match deserialize_data_or_env(data) { - Ok(value) => { - if value >= 0.0 { - Some(value) - } else { - tracing::warn!("Failed to deserialize_optional_block_cache_size_or_env: Value should be greater than or equal to 0"); - None - } - } - Err(err) => { - tracing::warn!("Failed to deserialize_optional_data_or_env: {:?}", err); - None - } - }) -} - -fn deserialize_optional_shadow_data_consistency_rate_or_env<'de, D>( - data: D, -) -> Result, D::Error> -where - D: serde::Deserializer<'de>, -{ - Ok(match deserialize_data_or_env(data) { - Ok(value) => { - if (0.0..=100.0).contains(&value) { - Some(value) - } else { - tracing::warn!("Failed to deserialize_optional_shadow_data_consistency_rate_or_env: Value should be in range 0.0..100.0"); - None - } - } - Err(err) => { - tracing::warn!("Failed to deserialize_optional_data_or_env: {:?}", err); - None - } - }) -} - -#[derive(Deserialize, Debug, Clone, Default)] +#[derive(Validate, Deserialize, Debug, Clone, Default)] pub struct CommonConfig { + #[validate(nested)] pub general: general::CommonGeneralConfig, #[serde(default)] pub rightsizing: rightsizing::CommonRightsizingConfig, pub lake_config: lake::CommonLakeConfig, + #[validate(nested)] pub database: database::CommonDatabaseConfig, // Set as default to avoid breaking changes // This options needs only for tx_indexer and rpc_server diff --git a/configuration/src/lib.rs b/configuration/src/lib.rs index 4f9b7340..aa32968c 100644 --- a/configuration/src/lib.rs +++ b/configuration/src/lib.rs @@ -2,6 +2,8 @@ use std::path::PathBuf; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; +use validator::Validate; + mod configs; pub use crate::configs::database::DatabaseConfig; @@ -18,6 +20,13 @@ where let path_root = find_configs_root().await?; load_env(path_root.clone()).await?; let common_config = read_toml_file(path_root).await?; + + if let Err(validation_errors) = common_config.validate() { + for error in validation_errors.0.values() { + tracing::warn!("Failed to validate config: {error:?}"); + } + } + Ok(T::from_common_config(common_config)) } From f2d3686771ba44ffaf1a209193814f75dcfd8a3e Mon Sep 17 00:00:00 2001 From: Ivan Frolov Date: Tue, 16 Jul 2024 19:25:28 -0400 Subject: [PATCH 3/6] chore: simplified formatting --- configuration/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/configuration/src/lib.rs b/configuration/src/lib.rs index aa32968c..2c0aa4af 100644 --- a/configuration/src/lib.rs +++ b/configuration/src/lib.rs @@ -22,9 +22,7 @@ where let common_config = read_toml_file(path_root).await?; if let Err(validation_errors) = common_config.validate() { - for error in validation_errors.0.values() { - tracing::warn!("Failed to validate config: {error:?}"); - } + tracing::warn!("Failed to validate config: {validation_errors}"); } Ok(T::from_common_config(common_config)) From 88d8d7d6fce0c8747e5b6936fe3a33591a09c6db Mon Sep 17 00:00:00 2001 From: Ivan Frolov Date: Wed, 17 Jul 2024 10:10:48 -0400 Subject: [PATCH 4/6] chore: reordered imports --- configuration/src/configs/database.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configuration/src/configs/database.rs b/configuration/src/configs/database.rs index e61fefc9..68a77109 100644 --- a/configuration/src/configs/database.rs +++ b/configuration/src/configs/database.rs @@ -1,7 +1,7 @@ -use crate::configs::deserialize_data_or_env; +use near_lake_framework::near_indexer_primitives::near_primitives; use validator::Validate; -use near_lake_framework::near_indexer_primitives::near_primitives; +use crate::configs::deserialize_data_or_env; // Database connection URL // Example: "postgres://user:password@localhost:5432/dbname" From 0bc630b80be96053bf98459993751b963851223e Mon Sep 17 00:00:00 2001 From: Ivan Frolov Date: Wed, 17 Jul 2024 10:11:16 -0400 Subject: [PATCH 5/6] feat: panic on error instead of logging --- configuration/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configuration/src/lib.rs b/configuration/src/lib.rs index 2c0aa4af..2ccf7d75 100644 --- a/configuration/src/lib.rs +++ b/configuration/src/lib.rs @@ -22,7 +22,7 @@ where let common_config = read_toml_file(path_root).await?; if let Err(validation_errors) = common_config.validate() { - tracing::warn!("Failed to validate config: {validation_errors}"); + panic!("Failed to validate config: {validation_errors}"); } Ok(T::from_common_config(common_config)) From a479047e21f3aded61e5c149b877ad29a2ac2bc3 Mon Sep 17 00:00:00 2001 From: Ivan Frolov Date: Wed, 17 Jul 2024 10:11:42 -0400 Subject: [PATCH 6/6] chore: provided better message error --- configuration/src/configs/general.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/configuration/src/configs/general.rs b/configuration/src/configs/general.rs index 66a2c0bc..eb60e9c3 100644 --- a/configuration/src/configs/general.rs +++ b/configuration/src/configs/general.rs @@ -107,10 +107,16 @@ pub struct CommonGeneralRpcServerConfig { pub server_port: Option, #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] pub max_gas_burnt: Option, - #[validate(range(min = 0.0, message = "Contract code cache size must be greater than 0"))] + #[validate(range( + min = 0.0, + message = "Contract code cache size must be greater than or equal to 0" + ))] #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] pub contract_code_cache_size: Option, - #[validate(range(min = 0.0, message = "Block cache size must be greater than 0"))] + #[validate(range( + min = 0.0, + message = "Block cache size must be greater than or equal to 0" + ))] #[serde(deserialize_with = "deserialize_optional_data_or_env", default)] pub block_cache_size: Option, #[validate(range(