diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fd72fe15..f1711219d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Next release +- fix: override chain config - fix(sync): pending block retrying mechanism - fix:(tests): Add testing feature to mc-db dev dependency (#294) - feat: new crate gateway client & server diff --git a/Cargo.lock b/Cargo.lock index 373270b30..9d2719474 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5370,14 +5370,12 @@ dependencies = [ "mp-chain-config", "mp-convert", "mp-utils", - "primitive-types", "rand", "rayon", "reqwest 0.12.5", "serde", "serde_json", "serde_yaml", - "starknet-core", "starknet-providers", "starknet_api", "thiserror", @@ -5423,7 +5421,6 @@ dependencies = [ "mp-receipt", "mp-state-update", "mp-transactions", - "mp-utils", "num-traits 0.2.19", "rayon", "rstest 0.18.2", @@ -5455,7 +5452,6 @@ dependencies = [ "mp-utils", "rayon", "rocksdb", - "rstest 0.18.2", "serde", "starknet-core", "starknet-types-core", @@ -5486,7 +5482,6 @@ dependencies = [ "mp-receipt", "mp-state-update", "mp-transactions", - "mp-utils", "proptest", "proptest-derive", "rand", @@ -5507,8 +5502,6 @@ dependencies = [ "env_logger 0.11.3", "flate2", "lazy_static", - "mp-utils", - "once_cell", "reqwest 0.12.5", "rstest 0.18.2", "serde_json", @@ -5669,7 +5662,6 @@ dependencies = [ "mp-receipt", "mp-state-update", "mp-transactions", - "mp-utils", "paste", "rstest 0.18.2", "serde_json", @@ -5698,18 +5690,13 @@ dependencies = [ "mp-class", "mp-convert", "mp-gateway", - "mp-receipt", "mp-transactions", "mp-utils", - "num-traits 0.2.19", - "rand", - "rayon", "regex", "reqwest 0.12.5", "rstest 0.18.2", "serde_json", "starknet-core", - "starknet-providers", "starknet-types-core", "starknet_api", "tempfile", @@ -5831,10 +5818,8 @@ dependencies = [ "anyhow", "blockifier", "lazy_static", - "log", "mp-utils", "primitive-types", - "reqwest 0.12.5", "rstest 0.18.2", "serde", "serde_json", @@ -5848,7 +5833,6 @@ dependencies = [ name = "mp-class" version = "0.7.0" dependencies = [ - "anyhow", "blockifier", "cairo-lang-starknet 1.0.0-alpha.6", "cairo-lang-starknet 1.0.0-rc0", @@ -5865,7 +5849,6 @@ dependencies = [ "num-bigint", "serde", "serde_json", - "sha3", "starknet-core", "starknet-providers", "starknet-types-core", @@ -5914,7 +5897,6 @@ dependencies = [ "bincode 1.3.3", "blockifier", "cairo-vm", - "log", "mp-convert", "rstest 0.18.2", "serde", @@ -5971,6 +5953,7 @@ dependencies = [ "rayon", "rstest 0.18.2", "serde", + "serde_yaml", "tokio", "url", ] diff --git a/configs/chain_config.example.yaml b/configs/chain_config.example.yaml index 1c40f0524..b21df8cab 100644 --- a/configs/chain_config.example.yaml +++ b/configs/chain_config.example.yaml @@ -10,7 +10,7 @@ native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201 parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" # Paths to JSON files containing blockifier's constants for different versions -versioned_constants: +versioned_constants_path: "0.13.0": "crates/primitives/chain_config/resources/versioned_constants_13_0.json" "0.13.1": "crates/primitives/chain_config/resources/versioned_constants_13_1.json" "0.13.1.1": "crates/primitives/chain_config/resources/versioned_constants_13_1_1.json" diff --git a/configs/presets/devnet.yaml b/configs/presets/devnet.yaml index ff994280c..743dc5442 100644 --- a/configs/presets/devnet.yaml +++ b/configs/presets/devnet.yaml @@ -2,7 +2,6 @@ chain_name: "Madara" chain_id: "MADARA_DEVNET" native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" -versioned_constants: eth_core_contract_address: "0xE2Bb56ee936fd6433DC0F6e7e3b8365C906AA057" latest_protocol_version: "0.13.2" block_time: "30s" diff --git a/configs/presets/integration.yaml b/configs/presets/integration.yaml index ef7e271dd..eb071072a 100644 --- a/configs/presets/integration.yaml +++ b/configs/presets/integration.yaml @@ -2,7 +2,6 @@ chain_name: "Starknet Sepolia" chain_id: "SN_INTEGRATION_SEPOLIA" native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" -versioned_constants: eth_core_contract_address: "0x4737c0c1B4D5b1A687B42610DdabEE781152359c" latest_protocol_version: "0.13.2" block_time: "30s" @@ -26,5 +25,5 @@ bouncer_config: message_segment_length: 18446744073709551615 n_events: 18446744073709551615 state_diff_size: 131072 -sequencer_address: "0x0" +sequencer_address: "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8" max_nonce_for_validation_skip: 2 diff --git a/configs/presets/mainnet.yaml b/configs/presets/mainnet.yaml index 7a75f0aaa..5c24b7f3c 100644 --- a/configs/presets/mainnet.yaml +++ b/configs/presets/mainnet.yaml @@ -2,7 +2,6 @@ chain_name: "Starknet Mainnet" chain_id: "SN_MAIN" native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" -versioned_constants: eth_core_contract_address: "0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4" latest_protocol_version: "0.13.2" block_time: "30s" @@ -26,5 +25,5 @@ bouncer_config: message_segment_length: 18446744073709551615 n_events: 18446744073709551615 state_diff_size: 131072 -sequencer_address: "0x0" +sequencer_address: "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8" max_nonce_for_validation_skip: 2 diff --git a/configs/presets/sepolia.yaml b/configs/presets/sepolia.yaml index 886552bc5..868a5e36e 100644 --- a/configs/presets/sepolia.yaml +++ b/configs/presets/sepolia.yaml @@ -2,7 +2,6 @@ chain_name: "Starknet Sepolia" chain_id: "SN_SEPOLIA" native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" -versioned_constants: eth_core_contract_address: "0xE2Bb56ee936fd6433DC0F6e7e3b8365C906AA057" latest_protocol_version: "0.13.2" block_time: "30s" @@ -26,5 +25,5 @@ bouncer_config: message_segment_length: 18446744073709551615 n_events: 18446744073709551615 state_diff_size: 131072 -sequencer_address: "0x0" +sequencer_address: "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8" max_nonce_for_validation_skip: 2 diff --git a/crates/client/block_import/Cargo.toml b/crates/client/block_import/Cargo.toml index b9e1481d1..c827e619a 100644 --- a/crates/client/block_import/Cargo.toml +++ b/crates/client/block_import/Cargo.toml @@ -31,7 +31,6 @@ mp-convert.workspace = true mp-receipt.workspace = true mp-state-update.workspace = true mp-transactions.workspace = true -mp-utils.workspace = true bonsai-trie.workspace = true starknet-core.workspace = true diff --git a/crates/client/db/Cargo.toml b/crates/client/db/Cargo.toml index 0fe66a000..95438cfef 100644 --- a/crates/client/db/Cargo.toml +++ b/crates/client/db/Cargo.toml @@ -35,7 +35,6 @@ bincode = { workspace = true } log = { workspace = true, default-features = true } rayon = { workspace = true } rocksdb.workspace = true -rstest = { workspace = true } serde = { workspace = true } tempfile = { workspace = true, optional = true } thiserror = { workspace = true } diff --git a/crates/client/devnet/Cargo.toml b/crates/client/devnet/Cargo.toml index e8185e9a8..5d9ef7693 100644 --- a/crates/client/devnet/Cargo.toml +++ b/crates/client/devnet/Cargo.toml @@ -37,7 +37,6 @@ mp-convert.workspace = true mp-receipt.workspace = true mp-state-update.workspace = true mp-transactions.workspace = true -mp-utils.workspace = true # Starknet blockifier.workspace = true diff --git a/crates/client/rpc/Cargo.toml b/crates/client/rpc/Cargo.toml index 168bc38bb..a4241c513 100644 --- a/crates/client/rpc/Cargo.toml +++ b/crates/client/rpc/Cargo.toml @@ -31,7 +31,6 @@ mp-convert = { workspace = true, default-features = true } mp-receipt = { workspace = true } mp-state-update = { workspace = true } mp-transactions = { workspace = true } -mp-utils = { workspace = true } # Starknet blockifier = { workspace = true, default-features = true } diff --git a/crates/client/sync/Cargo.toml b/crates/client/sync/Cargo.toml index 24e55b2f4..e4b417838 100644 --- a/crates/client/sync/Cargo.toml +++ b/crates/client/sync/Cargo.toml @@ -28,13 +28,11 @@ mp-chain-config.workspace = true mp-class.workspace = true mp-convert.workspace = true mp-gateway.workspace = true -mp-receipt.workspace = true mp-transactions.workspace = true mp-utils.workspace = true # Starknet starknet-core.workspace = true -starknet-providers.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true @@ -43,9 +41,6 @@ starknet_api.workspace = true anyhow.workspace = true futures = { workspace = true, default-features = true } log.workspace = true -num-traits.workspace = true -rand.workspace = true -rayon.workspace = true reqwest.workspace = true serde_json.workspace = true thiserror.workspace = true diff --git a/crates/node/Cargo.toml b/crates/node/Cargo.toml index 3868cf29d..6c540f437 100644 --- a/crates/node/Cargo.toml +++ b/crates/node/Cargo.toml @@ -35,7 +35,6 @@ mp-utils = { workspace = true } # Starknet blockifier = { workspace = true } -starknet-core = { workspace = true } starknet-providers = { workspace = true } starknet_api = { workspace = true } @@ -54,7 +53,6 @@ hyper.workspace = true ip_network.workspace = true jsonrpsee.workspace = true log = { workspace = true } -primitive-types.workspace = true rand = { workspace = true } rayon.workspace = true reqwest = { workspace = true } diff --git a/crates/node/src/cli/chain_config_overrides.rs b/crates/node/src/cli/chain_config_overrides.rs index f16633ebe..6673a41b9 100644 --- a/crates/node/src/cli/chain_config_overrides.rs +++ b/crates/node/src/cli/chain_config_overrides.rs @@ -1,73 +1,51 @@ use std::time::Duration; -use anyhow::Context; +use anyhow::{bail, Context}; +use blockifier::bouncer::BouncerConfig; +use clap::Parser; use serde::{Deserialize, Serialize}; use serde_yaml::Value; use starknet_api::core::{ChainId, ContractAddress}; use mp_block::H160; -use mp_chain_config::{ChainConfig, StarknetVersion}; -use mp_utils::parsers::parse_key_value; +use mp_chain_config::{ + deserialize_bouncer_config, deserialize_starknet_version, serialize_bouncer_config, serialize_starknet_version, + ChainConfig, StarknetVersion, +}; +use mp_utils::parsers::parse_key_value_yaml; +use mp_utils::serde::{deserialize_duration, serialize_duration}; /// Override chain config parameters. -/// Format: "--chain-config-override chain_id=NEW_MADARA --chain-config-override chain_name=NEW_NAME" -#[derive(clap::Parser, Clone, Debug)] +/// Format: "--chain-config-override chain_id=SN_MADARA,chain_name=MADARA,block_time=1.5" +#[derive(Parser, Clone, Debug)] pub struct ChainConfigOverrideParams { - #[clap(long = "chain-config-override", value_parser = parse_key_value, number_of_values = 1)] - pub overrides: Vec<(String, String)>, + #[clap(long = "chain-config-override", value_parser = parse_key_value_yaml, use_value_delimiter = true, value_delimiter = ',')] + pub overrides: Vec<(String, Value)>, } -impl ChainConfigOverrideParams { - pub fn override_chain_config(&self, chain_config: ChainConfig) -> anyhow::Result { - let overridable = OverridableChainConfig::from(&chain_config); - let mut config_value = - serde_yaml::to_value(overridable).context("Failed to convert OverridableChainConfig to Value")?; - - if let Value::Mapping(ref mut map) = config_value { - for (key, value) in &self.overrides { - if !map.contains_key(Value::String(key.clone())) { - return Err(anyhow::anyhow!("The field '{}' is not overridable for the Chain Config.", key)); - } - map.insert(Value::String(key.clone()), Value::String(value.clone())); - } - } else { - return Err(anyhow::anyhow!("Unexpected chain config structure.")); - } - - let updated_overridable: OverridableChainConfig = - serde_yaml::from_value(config_value).context("Failed to convert Value back to OverridableChainConfig")?; - - Ok(ChainConfig { - versioned_constants: chain_config.versioned_constants, - bouncer_config: chain_config.bouncer_config, - ..updated_overridable.into() - }) - } -} - -/// Part of the Chain Config that we can override. -// We need this proxy structure to implement Serialize - -// which is not possible on the original ChainConfig because the bouncer config and -// the versioned constants don't implement it. -// Since we don't want to override those values anyway, we can create this wrapper. #[derive(Debug, Serialize, Deserialize)] -pub struct OverridableChainConfig { +pub struct ChainConfigOverridesInner { pub chain_name: String, pub chain_id: ChainId, pub native_fee_token_address: ContractAddress, pub parent_fee_token_address: ContractAddress, + #[serde(deserialize_with = "deserialize_starknet_version", serialize_with = "serialize_starknet_version")] pub latest_protocol_version: StarknetVersion, + #[serde(deserialize_with = "deserialize_duration", serialize_with = "serialize_duration")] pub block_time: Duration, + #[serde(deserialize_with = "deserialize_duration", serialize_with = "serialize_duration")] pub pending_block_update_time: Duration, pub execution_batch_size: usize, + #[serde(deserialize_with = "deserialize_bouncer_config", serialize_with = "serialize_bouncer_config")] + pub bouncer_config: BouncerConfig, pub sequencer_address: ContractAddress, pub max_nonce_for_validation_skip: u64, pub eth_core_contract_address: H160, } -impl From<&ChainConfig> for OverridableChainConfig { +impl From<&ChainConfig> for ChainConfigOverridesInner { fn from(config: &ChainConfig) -> Self { - OverridableChainConfig { + Self { chain_name: config.chain_name.clone(), chain_id: config.chain_id.clone(), native_fee_token_address: config.native_fee_token_address, @@ -76,6 +54,7 @@ impl From<&ChainConfig> for OverridableChainConfig { block_time: config.block_time, pending_block_update_time: config.pending_block_update_time, execution_batch_size: config.execution_batch_size, + bouncer_config: config.bouncer_config.clone(), sequencer_address: config.sequencer_address, max_nonce_for_validation_skip: config.max_nonce_for_validation_skip, eth_core_contract_address: config.eth_core_contract_address, @@ -83,22 +62,58 @@ impl From<&ChainConfig> for OverridableChainConfig { } } -impl From for ChainConfig { - fn from(overridable: OverridableChainConfig) -> Self { - ChainConfig { - chain_name: overridable.chain_name, - chain_id: overridable.chain_id, - native_fee_token_address: overridable.native_fee_token_address, - parent_fee_token_address: overridable.parent_fee_token_address, - latest_protocol_version: overridable.latest_protocol_version, - block_time: overridable.block_time, - pending_block_update_time: overridable.pending_block_update_time, - execution_batch_size: overridable.execution_batch_size, - sequencer_address: overridable.sequencer_address, - max_nonce_for_validation_skip: overridable.max_nonce_for_validation_skip, - eth_core_contract_address: overridable.eth_core_contract_address, - versioned_constants: Default::default(), - bouncer_config: Default::default(), +impl ChainConfigOverrideParams { + pub fn override_chain_config(&self, chain_config: ChainConfig) -> anyhow::Result { + let mut chain_config_overrides = serde_yaml::to_value(ChainConfigOverridesInner::from(&chain_config)) + .context("Failed to convert ChainConfig to Value")?; + + for (key, value) in &self.overrides { + // Split the key by '.' to handle nested fields + let key_parts = key.split('.').collect::>(); + + // Navigate to the last field in the path + let mut current_value = &mut chain_config_overrides; + for part in key_parts.iter().take(key_parts.len() - 1) { + current_value = match current_value.get_mut(part) { + Some(v) => v, + None => bail!("Invalid chain config override key path: {}", key), + }; + } + + // Set the value to the final field in the path + let last_key = + key_parts.last().with_context(|| format!("Invalid chain config override key path: {}", key))?; + match current_value.get_mut(*last_key) { + Some(field) => { + *field = value.clone(); + } + None => { + bail!("Invalid chain config override key path: {}", key); + } + } } + + let chain_config_overrides: ChainConfigOverridesInner = serde_yaml::from_value(chain_config_overrides) + .context("Failed to convert Value to ChainConfigOverridesInner")?; + + println!("chain_config_overrides: {:#?}", chain_config_overrides); + + let versioned_constants = chain_config.versioned_constants; + + Ok(ChainConfig { + chain_name: chain_config_overrides.chain_name, + chain_id: chain_config_overrides.chain_id, + native_fee_token_address: chain_config_overrides.native_fee_token_address, + parent_fee_token_address: chain_config_overrides.parent_fee_token_address, + latest_protocol_version: chain_config_overrides.latest_protocol_version, + block_time: chain_config_overrides.block_time, + pending_block_update_time: chain_config_overrides.pending_block_update_time, + execution_batch_size: chain_config_overrides.execution_batch_size, + bouncer_config: chain_config_overrides.bouncer_config, + sequencer_address: chain_config_overrides.sequencer_address, + max_nonce_for_validation_skip: chain_config_overrides.max_nonce_for_validation_skip, + eth_core_contract_address: chain_config_overrides.eth_core_contract_address, + versioned_constants, + }) } } diff --git a/crates/primitives/chain_config/Cargo.toml b/crates/primitives/chain_config/Cargo.toml index 9043fa669..46008f821 100644 --- a/crates/primitives/chain_config/Cargo.toml +++ b/crates/primitives/chain_config/Cargo.toml @@ -21,11 +21,11 @@ mp-utils.workspace = true # Other anyhow = { workspace = true } lazy_static = { workspace = true } -log = { workspace = true } primitive-types.workspace = true -reqwest = { workspace = true } -rstest = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } serde_yaml = { workspace = true } thiserror = { workspace = true } + +[dev-dependencies] +rstest = { workspace = true } diff --git a/crates/primitives/chain_config/src/chain_config.rs b/crates/primitives/chain_config/src/chain_config.rs index 3cdbccbc0..5a2435474 100644 --- a/crates/primitives/chain_config/src/chain_config.rs +++ b/crates/primitives/chain_config/src/chain_config.rs @@ -1,3 +1,4 @@ +use std::fmt; // Note: We are NOT using fs read for constants, as they NEED to be included in the resulting // binary. Otherwise, using the madara binary without cloning the repo WILL crash, and that's very very bad. // The binary needs to be self contained! We need to be able to ship madara as a single binary, without @@ -17,7 +18,8 @@ use blockifier::bouncer::{BouncerWeights, BuiltinCount}; use blockifier::{bouncer::BouncerConfig, versioned_constants::VersionedConstants}; use lazy_static::__Deref; use primitive_types::H160; -use serde::{Deserialize, Deserializer}; +use serde::de::{MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; use starknet_api::core::{ChainId, ContractAddress, PatriciaKey}; use starknet_types_core::felt::Felt; @@ -64,6 +66,7 @@ pub struct ChainConfig { pub parent_fee_token_address: ContractAddress, /// BTreeMap ensures order. + #[serde(default)] pub versioned_constants: ChainVersionedConstants, #[serde(deserialize_with = "deserialize_starknet_version")] @@ -104,7 +107,24 @@ pub struct ChainConfig { impl ChainConfig { pub fn from_yaml(path: &Path) -> anyhow::Result { let config_str = fs::read_to_string(path)?; - serde_yaml::from_str(&config_str).context("While deserializing chain config") + let config_value: serde_yaml::Value = + serde_yaml::from_str(&config_str).context("While deserializing chain config")?; + + let versioned_constants_file_paths: BTreeMap = + serde_yaml::from_value(config_value.get("versioned_constants_path").cloned().unwrap_or_default()) + .context("While deserializing versioned constants file paths")?; + + let versioned_constants = { + // add the defaults VersionedConstants + let mut versioned_constants = ChainVersionedConstants::default(); + versioned_constants.merge(ChainVersionedConstants::from_file(versioned_constants_file_paths)?); + versioned_constants + }; + + let chain_config: ChainConfig = + serde_yaml::from_str(&config_str).context("While deserializing chain config")?; + + Ok(ChainConfig { versioned_constants, ..chain_config }) } /// Verify that the chain config is valid for block production. @@ -247,6 +267,36 @@ impl ChainConfig { #[derive(Debug)] pub struct ChainVersionedConstants(pub BTreeMap); +impl<'de> Deserialize<'de> for ChainVersionedConstants { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ChainVersionedConstantsVisitor; + + impl<'de> Visitor<'de> for ChainVersionedConstantsVisitor { + type Value = ChainVersionedConstants; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a map of StarknetVersion to VersionedConstants") + } + + fn visit_map(self, mut access: M) -> Result + where + M: MapAccess<'de>, + { + let mut map = BTreeMap::new(); + while let Some((key, value)) = access.next_entry::()? { + map.insert(key.parse().map_err(serde::de::Error::custom)?, value); + } + Ok(ChainVersionedConstants(map)) + } + } + + deserializer.deserialize_map(ChainVersionedConstantsVisitor) + } +} + impl From<[(StarknetVersion, VersionedConstants); N]> for ChainVersionedConstants { fn from(arr: [(StarknetVersion, VersionedConstants); N]) -> Self { ChainVersionedConstants(arr.into()) @@ -273,49 +323,27 @@ impl ChainVersionedConstants { pub fn merge(&mut self, other: Self) { self.0.extend(other.0); } -} -/// Replaces the versioned_constants files definition in the yaml by the content of the -/// jsons. -impl<'de> Deserialize<'de> for ChainVersionedConstants { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let file_paths: BTreeMap = Deserialize::deserialize(deserializer)?; + pub fn from_file(version_with_path: BTreeMap) -> Result { let mut result = BTreeMap::new(); - for (version, path) in file_paths { + for (version, path) in version_with_path { // Change the current directory to Madara root - let mut file = File::open(Path::new(&path)) - .with_context(|| format!("Failed to open file: {}", path)) - .map_err(serde::de::Error::custom)?; + let mut file = File::open(Path::new(&path)).with_context(|| format!("Failed to open file: {}", path))?; let mut contents = String::new(); - file.read_to_string(&mut contents) - .with_context(|| format!("Failed to read contents of file: {}", path)) - .map_err(serde::de::Error::custom)?; + file.read_to_string(&mut contents).with_context(|| format!("Failed to read contents of file: {}", path))?; - let constants: VersionedConstants = serde_json::from_str(&contents) - .with_context(|| format!("Failed to parse JSON in file: {}", path)) - .map_err(serde::de::Error::custom)?; + let constants: VersionedConstants = + serde_json::from_str(&contents).with_context(|| format!("Failed to parse JSON in file: {}", path))?; - let parsed_version = version - .parse() - .with_context(|| format!("Failed to parse version string: {}", version)) - .map_err(serde::de::Error::custom)?; + let parsed_version = + version.parse().with_context(|| format!("Failed to parse version string: {}", version))?; result.insert(parsed_version, constants); } - // insert the default versioned constants - let all_versionned_constants = { - let mut all_versionned_constants = ChainVersionedConstants::default(); - all_versionned_constants.merge(ChainVersionedConstants(result)); - all_versionned_constants - }; - - Ok(all_versionned_constants) + Ok(ChainVersionedConstants(result)) } } @@ -327,6 +355,13 @@ where StarknetVersion::from_str(&s).map_err(serde::de::Error::custom) } +pub fn serialize_starknet_version(version: &StarknetVersion, serializer: S) -> Result +where + S: serde::Serializer, +{ + version.to_string().serialize(serializer) +} + // TODO: this is workaround because BouncerConfig doesn't derive Deserialize in blockifier pub fn deserialize_bouncer_config<'de, D>(deserializer: D) -> Result where @@ -341,6 +376,18 @@ where Ok(BouncerConfig { block_max_capacity: helper.block_max_capacity }) } +pub fn serialize_bouncer_config(config: &BouncerConfig, serializer: S) -> Result +where + S: serde::Serializer, +{ + #[derive(Serialize)] + struct BouncerConfigHelper<'a> { + block_max_capacity: &'a BouncerWeights, + } + + BouncerConfigHelper { block_max_capacity: &config.block_max_capacity }.serialize(serializer) +} + #[cfg(test)] mod tests { use blockifier::{transaction::transaction_types::TransactionType, versioned_constants::ResourceCost}; @@ -432,7 +479,13 @@ mod tests { assert_eq!(chain_config.bouncer_config.block_max_capacity.state_diff_size, 131072); assert_eq!(chain_config.bouncer_config.block_max_capacity.builtin_count.add_mod, 18446744073709551615); - assert_eq!(chain_config.sequencer_address, ContractAddress::try_from(Felt::from_str("0x0").unwrap()).unwrap()); + assert_eq!( + chain_config.sequencer_address, + ContractAddress::try_from( + Felt::from_str("0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8").unwrap() + ) + .unwrap() + ); assert_eq!(chain_config.max_nonce_for_validation_skip, 2); assert_eq!( chain_config.eth_core_contract_address, diff --git a/crates/primitives/class/Cargo.toml b/crates/primitives/class/Cargo.toml index 103324bb6..f9d33b05d 100644 --- a/crates/primitives/class/Cargo.toml +++ b/crates/primitives/class/Cargo.toml @@ -31,13 +31,11 @@ starknet-core = { workspace = true } starknet-types-core = { workspace = true } # Other -anyhow = { workspace = true } flate2 = { workspace = true } lazy_static = { workspace = true } num-bigint = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } -sha3 = { workspace = true } thiserror = { workspace = true } [dev-dependencies] diff --git a/crates/primitives/receipt/Cargo.toml b/crates/primitives/receipt/Cargo.toml index 6c30ecedf..b25d02475 100644 --- a/crates/primitives/receipt/Cargo.toml +++ b/crates/primitives/receipt/Cargo.toml @@ -25,7 +25,6 @@ starknet-providers = { workspace = true } starknet-types-core = { workspace = true } starknet_api = { workspace = true } # Other -log = { workspace = true } serde = { workspace = true, features = ["derive"] } [dev-dependencies] diff --git a/crates/primitives/utils/Cargo.toml b/crates/primitives/utils/Cargo.toml index 672af82d5..799c81cfe 100644 --- a/crates/primitives/utils/Cargo.toml +++ b/crates/primitives/utils/Cargo.toml @@ -20,5 +20,6 @@ futures.workspace = true rayon.workspace = true rstest = { workspace = true } serde.workspace = true +serde_yaml.workspace = true tokio = { workspace = true, features = ["signal"] } url.workspace = true diff --git a/crates/primitives/utils/src/parsers.rs b/crates/primitives/utils/src/parsers.rs index 2047630ec..6619c9993 100644 --- a/crates/primitives/utils/src/parsers.rs +++ b/crates/primitives/utils/src/parsers.rs @@ -1,15 +1,22 @@ -use anyhow::{anyhow, bail}; +use anyhow::{anyhow, bail, ensure}; +use serde_yaml::Value; use std::time::Duration; use url::Url; -/// Parses a "key=value" string & returns a [(String, String)] tuple. -pub fn parse_key_value(s: &str) -> anyhow::Result<(String, String)> { +/// Parses a "key=value" string & returns a [(String, Value)] tuple. +pub fn parse_key_value_yaml(s: &str) -> anyhow::Result<(String, Value)> { let mut parts = s.splitn(2, '='); - let key = parts.next().ok_or_else(|| anyhow::anyhow!("Invalid key-value pair"))?; - let value = parts.next().ok_or_else(|| anyhow::anyhow!("Invalid key-value pair"))?; - Ok((key.to_string(), value.to_string())) + let key = parts.next().ok_or_else(|| anyhow!("Missing key in key-value pair"))?.trim(); + let value = parts.next().ok_or_else(|| anyhow!("Missing value in key-value pair"))?.trim(); + + ensure!(!key.trim().is_empty(), "Key cannot be empty"); + + // If the value starts with "0x", treat it as a string (to avoid parsing Felt values as numbers) + let value = if value.starts_with("0x") { Value::String(value.to_string()) } else { serde_yaml::from_str(value)? }; + + Ok((key.to_string(), value)) } /// Parse a string URL & returns it as [Url]. diff --git a/crates/primitives/utils/src/serde.rs b/crates/primitives/utils/src/serde.rs index 50b73753b..a3be87c18 100644 --- a/crates/primitives/utils/src/serde.rs +++ b/crates/primitives/utils/src/serde.rs @@ -11,3 +11,14 @@ where let s = String::deserialize(deserializer)?; parse_duration(&s).map_err(serde::de::Error::custom) } + +pub fn serialize_duration(duration: &Duration, serializer: S) -> Result +where + S: serde::Serializer, +{ + if duration.as_secs_f64().fract() == 0.0 { + serializer.serialize_str(&format!("{}s", duration.as_secs())) + } else { + serializer.serialize_str(&format!("{}ms", duration.as_millis())) + } +} diff --git a/crates/tests/Cargo.toml b/crates/tests/Cargo.toml index 899a11307..af860fa7f 100644 --- a/crates/tests/Cargo.toml +++ b/crates/tests/Cargo.toml @@ -8,16 +8,10 @@ version.workspace = true license.workspace = true [dependencies] - -# Madara - -mp-utils.workspace = true - anyhow.workspace = true env_logger.workspace = true flate2 = "1.0.30" lazy_static.workspace = true -once_cell = { workspace = true } reqwest.workspace = true rstest.workspace = true serde_json = { workspace = true }