diff --git a/crates/blockifier/src/execution/syscalls/hint_processor.rs b/crates/blockifier/src/execution/syscalls/hint_processor.rs index 1c1a9cb9c9..df847f4c59 100644 --- a/crates/blockifier/src/execution/syscalls/hint_processor.rs +++ b/crates/blockifier/src/execution/syscalls/hint_processor.rs @@ -472,6 +472,7 @@ impl<'a> SyscallHintProcessor<'a> { let resource = match resource { Resource::L1Gas => l1_gas, Resource::L2Gas => l2_gas, + Resource::L1DataGas => todo!(), }; vec![ diff --git a/crates/gateway/src/stateless_transaction_validator.rs b/crates/gateway/src/stateless_transaction_validator.rs index b5ca99180b..b663bf5852 100644 --- a/crates/gateway/src/stateless_transaction_validator.rs +++ b/crates/gateway/src/stateless_transaction_validator.rs @@ -182,6 +182,7 @@ fn validate_resource_is_non_zero( let resource_bounds = match resource { Resource::L1Gas => resource_bounds_mapping.l1_gas, Resource::L2Gas => resource_bounds_mapping.l2_gas, + Resource::L1DataGas => todo!(), }; if resource_bounds.max_amount == 0 || resource_bounds.max_price_per_unit == 0 { return Err(StatelessTransactionValidatorError::ZeroResourceBounds { diff --git a/crates/papyrus_storage/src/serialization/serializers.rs b/crates/papyrus_storage/src/serialization/serializers.rs index 051389bdc3..95923339d9 100644 --- a/crates/papyrus_storage/src/serialization/serializers.rs +++ b/crates/papyrus_storage/src/serialization/serializers.rs @@ -355,6 +355,7 @@ auto_storage_serde! { pub enum Resource { L1Gas = 0, L2Gas = 1, + L1DataGas = 2, } pub struct ResourceBounds { pub max_amount: u64, diff --git a/crates/starknet_api/src/transaction.rs b/crates/starknet_api/src/transaction.rs index 431e5a0ddd..fc8fe2e570 100644 --- a/crates/starknet_api/src/transaction.rs +++ b/crates/starknet_api/src/transaction.rs @@ -874,6 +874,8 @@ pub enum Resource { L1Gas, #[serde(rename = "L2_GAS")] L2Gas, + #[serde(rename = "L1_DATA_GAS")] + L1DataGas, } /// Fee bounds for an execution resource. @@ -891,6 +893,13 @@ pub struct ResourceBounds { pub max_price_per_unit: u128, } +impl ResourceBounds { + /// Returns true iff both the max amount and the max amount per unit is zero. + pub fn is_zero(&self) -> bool { + self.max_amount == 0 && self.max_price_per_unit == 0 + } +} + fn u64_to_hex(value: &u64, serializer: S) -> Result where S: Serializer, @@ -923,6 +932,7 @@ where /// A mapping from execution resources to their corresponding fee bounds.. #[derive(Clone, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] +// TODO(Nimrod): Remove this struct definition. pub struct ResourceBoundsMapping(pub BTreeMap); impl TryFrom> for ResourceBoundsMapping { @@ -931,11 +941,13 @@ impl TryFrom> for ResourceBoundsMapping { resource_resource_bounds_pairs: Vec<(Resource, ResourceBounds)>, ) -> Result { let n_variants = Resource::iter().count(); + let allowed_signed_variants = [n_variants, n_variants - 1]; let unique_resources: HashSet = HashSet::from_iter(resource_resource_bounds_pairs.iter().map(|(k, _)| *k)); - if unique_resources.len() != n_variants - || resource_resource_bounds_pairs.len() != n_variants + if !allowed_signed_variants.contains(&unique_resources.len()) + || !allowed_signed_variants.contains(&resource_resource_bounds_pairs.len()) { + // TODO(Nimrod): Consider making this check more strict. Err(StarknetApiError::InvalidResourceMappingInitializer(format!( "{:?}", resource_resource_bounds_pairs @@ -946,6 +958,60 @@ impl TryFrom> for ResourceBoundsMapping { } } +pub enum ValidResourceBounds { + L1Gas(ResourceBounds), // Pre 0.13.3. Only L1 gas. L2 bounds are signed but never used. + AllResources(AllResourceBounds), +} + +pub struct AllResourceBounds { + pub l1_gas: ResourceBounds, + pub l2_gas: ResourceBounds, + pub l1_data_gas: ResourceBounds, +} + +impl AllResourceBounds { + #[allow(dead_code)] + fn get_bound(&self, resource: Resource) -> ResourceBounds { + match resource { + Resource::L1Gas => self.l1_gas, + Resource::L2Gas => self.l2_gas, + Resource::L1DataGas => self.l1_data_gas, + } + } +} + +impl TryFrom for ValidResourceBounds { + type Error = StarknetApiError; + fn try_from(resource_bounds_mapping: ResourceBoundsMapping) -> Result { + if let (Some(l1_bounds), Some(l2_bounds)) = ( + resource_bounds_mapping.0.get(&Resource::L1Gas), + resource_bounds_mapping.0.get(&Resource::L2Gas), + ) { + match resource_bounds_mapping.0.get(&Resource::L1DataGas) { + Some(data_bounds) => Ok(Self::AllResources(AllResourceBounds { + l1_gas: *l1_bounds, + l1_data_gas: *data_bounds, + l2_gas: *l2_bounds, + })), + None => { + if l2_bounds.is_zero() { + Ok(Self::L1Gas(*l1_bounds)) + } else { + Err(StarknetApiError::InvalidResourceMappingInitializer(format!( + "Missing data gas bounds but L2 gas bound is not zero: \ + {resource_bounds_mapping:?}", + ))) + } + } + } + } else { + Err(StarknetApiError::InvalidResourceMappingInitializer(format!( + "{resource_bounds_mapping:?}", + ))) + } + } +} + /// Paymaster-related data. #[derive(Clone, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] pub struct PaymasterData(pub Vec);