diff --git a/zk_toolbox/Cargo.lock b/zk_toolbox/Cargo.lock index 1401ca022904..927ef514f324 100644 --- a/zk_toolbox/Cargo.lock +++ b/zk_toolbox/Cargo.lock @@ -3949,6 +3949,7 @@ dependencies = [ "serde", "strum 0.26.2", "strum_macros 0.26.2", + "thiserror", ] [[package]] diff --git a/zk_toolbox/crates/config/src/forge_interface/deploy_ecosystem/input.rs b/zk_toolbox/crates/config/src/forge_interface/deploy_ecosystem/input.rs index 87556d36795f..585ad407b67e 100644 --- a/zk_toolbox/crates/config/src/forge_interface/deploy_ecosystem/input.rs +++ b/zk_toolbox/crates/config/src/forge_interface/deploy_ecosystem/input.rs @@ -1,6 +1,9 @@ use std::{collections::HashMap, str::FromStr}; -use ethers::types::{Address, H256}; +use ethers::{ + prelude::U256, + types::{Address, H256}, +}; use rand::Rng; use serde::{Deserialize, Serialize}; use types::ChainId; @@ -146,7 +149,7 @@ impl DeployL1Config { genesis_batch_commitment: genesis_config.genesis_batch_commitment, genesis_rollup_leaf_index: genesis_config.genesis_rollup_leaf_index, genesis_root: genesis_config.genesis_root, - latest_protocol_version: genesis_config.genesis_protocol_version, + latest_protocol_version: genesis_config.genesis_protocol_semantic_version.pack(), recursion_circuits_set_vks_hash: H256::zero(), recursion_leaf_level_vk_hash: H256::zero(), recursion_node_level_vk_hash: H256::zero(), @@ -173,7 +176,7 @@ pub struct ContractsDeployL1Config { pub genesis_root: H256, pub genesis_rollup_leaf_index: u32, pub genesis_batch_commitment: H256, - pub latest_protocol_version: u64, + pub latest_protocol_version: U256, pub recursion_node_level_vk_hash: H256, pub recursion_leaf_level_vk_hash: H256, pub recursion_circuits_set_vks_hash: H256, diff --git a/zk_toolbox/crates/config/src/genesis.rs b/zk_toolbox/crates/config/src/genesis.rs index 16f44a45c2e7..4e3d931ea0f0 100644 --- a/zk_toolbox/crates/config/src/genesis.rs +++ b/zk_toolbox/crates/config/src/genesis.rs @@ -1,6 +1,6 @@ use ethers::types::{Address, H256}; use serde::{Deserialize, Serialize}; -use types::{ChainId, L1BatchCommitDataGeneratorMode}; +use types::{ChainId, L1BatchCommitDataGeneratorMode, ProtocolSemanticVersion}; use crate::{consts::GENESIS_FILE, traits::FileConfigWithDefaultName}; @@ -16,6 +16,7 @@ pub struct GenesisConfig { pub genesis_rollup_leaf_index: u32, pub genesis_root: H256, pub genesis_protocol_version: u64, + pub genesis_protocol_semantic_version: ProtocolSemanticVersion, #[serde(flatten)] pub other: serde_json::Value, } diff --git a/zk_toolbox/crates/types/Cargo.toml b/zk_toolbox/crates/types/Cargo.toml index 2c7ceedd1f08..efd8f84d7088 100644 --- a/zk_toolbox/crates/types/Cargo.toml +++ b/zk_toolbox/crates/types/Cargo.toml @@ -16,3 +16,4 @@ ethers.workspace = true serde.workspace = true strum.workspace = true strum_macros.workspace = true +thiserror.workspace = true diff --git a/zk_toolbox/crates/types/src/lib.rs b/zk_toolbox/crates/types/src/lib.rs index a973f8bfc918..c405013990cf 100644 --- a/zk_toolbox/crates/types/src/lib.rs +++ b/zk_toolbox/crates/types/src/lib.rs @@ -2,6 +2,7 @@ mod base_token; mod chain_id; mod l1_batch_commit_data_generator_mode; mod l1_network; +mod protocol_version; mod prover_mode; mod wallet_creation; @@ -9,5 +10,6 @@ pub use base_token::*; pub use chain_id::*; pub use l1_batch_commit_data_generator_mode::*; pub use l1_network::*; +pub use protocol_version::ProtocolSemanticVersion; pub use prover_mode::*; pub use wallet_creation::*; diff --git a/zk_toolbox/crates/types/src/protocol_version.rs b/zk_toolbox/crates/types/src/protocol_version.rs new file mode 100644 index 000000000000..35ac74d3b5f8 --- /dev/null +++ b/zk_toolbox/crates/types/src/protocol_version.rs @@ -0,0 +1,93 @@ +use std::{fmt, num::ParseIntError, str::FromStr}; + +use ethers::prelude::U256; +use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; + +pub const PACKED_SEMVER_MINOR_OFFSET: u32 = 32; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct ProtocolSemanticVersion { + pub minor: u16, + pub patch: u16, +} + +impl ProtocolSemanticVersion { + const MAJOR_VERSION: u8 = 0; + + pub fn new(minor: u16, patch: u16) -> Self { + Self { minor, patch } + } + + pub fn pack(&self) -> U256 { + (U256::from(self.minor) << U256::from(PACKED_SEMVER_MINOR_OFFSET)) | U256::from(self.patch) + } +} + +impl fmt::Display for ProtocolSemanticVersion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}.{}.{}", + Self::MAJOR_VERSION, + self.minor as u16, + self.patch + ) + } +} + +#[derive(Debug, thiserror::Error)] +pub enum ParseProtocolSemanticVersionError { + #[error("invalid format")] + InvalidFormat, + #[error("non zero major version")] + NonZeroMajorVersion, + #[error("{0}")] + ParseIntError(ParseIntError), +} + +impl FromStr for ProtocolSemanticVersion { + type Err = ParseProtocolSemanticVersionError; + + fn from_str(s: &str) -> Result { + let parts: Vec<&str> = s.split('.').collect(); + if parts.len() != 3 { + return Err(ParseProtocolSemanticVersionError::InvalidFormat); + } + + let major = parts[0] + .parse::() + .map_err(ParseProtocolSemanticVersionError::ParseIntError)?; + if major != 0 { + return Err(ParseProtocolSemanticVersionError::NonZeroMajorVersion); + } + + let minor = parts[1] + .parse::() + .map_err(ParseProtocolSemanticVersionError::ParseIntError)?; + + let patch = parts[2] + .parse::() + .map_err(ParseProtocolSemanticVersionError::ParseIntError)?; + + Ok(ProtocolSemanticVersion { minor, patch }) + } +} + +impl<'de> Deserialize<'de> for ProtocolSemanticVersion { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + ProtocolSemanticVersion::from_str(&s).map_err(D::Error::custom) + } +} + +impl Serialize for ProtocolSemanticVersion { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&self.to_string()) + } +}