diff --git a/config/sequencer/default_config.json b/config/sequencer/default_config.json index f15c0a54d8e..39f574b22fd 100644 --- a/config/sequencer/default_config.json +++ b/config/sequencer/default_config.json @@ -1,54 +1,4 @@ { - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.add_mod": { - "description": "Max number of add mod builtin usage in a block.", - "privacy": "Public", - "value": 156250 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.bitwise": { - "description": "Max number of bitwise builtin usage in a block.", - "privacy": "Public", - "value": 39062 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.ec_op": { - "description": "Max number of EC operation builtin usage in a block.", - "privacy": "Public", - "value": 2441 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.ecdsa": { - "description": "Max number of ECDSA builtin usage in a block.", - "privacy": "Public", - "value": 1220 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.keccak": { - "description": "Max number of keccak builtin usage in a block.", - "privacy": "Public", - "value": 1220 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.mul_mod": { - "description": "Max number of mul mod builtin usage in a block.", - "privacy": "Public", - "value": 156250 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.pedersen": { - "description": "Max number of pedersen builtin usage in a block.", - "privacy": "Public", - "value": 78125 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.poseidon": { - "description": "Max number of poseidon builtin usage in a block.", - "privacy": "Public", - "value": 78125 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.range_check": { - "description": "Max number of range check builtin usage in a block.", - "privacy": "Public", - "value": 156250 - }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.builtin_count.range_check96": { - "description": "Max number of range check 96 builtin usage in a block.", - "privacy": "Public", - "value": 156250 - }, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.l1_gas": { "description": "An upper bound on the total l1_gas used in a block.", "privacy": "Public", @@ -64,15 +14,10 @@ "privacy": "Public", "value": 5000 }, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_steps": { - "description": "An upper bound on the total number of steps in a block.", - "privacy": "Public", - "value": 2500000 - }, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": { "description": "An upper bound on the total sierra_gas used in a block.", "privacy": "Public", - "value": 250000000 + "value": 400000000 }, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.state_diff_size": { "description": "An upper bound on the total state diff size in a block.", diff --git a/crates/blockifier/src/blockifier/transaction_executor.rs b/crates/blockifier/src/blockifier/transaction_executor.rs index e5a7ac11a13..baea3aa64c4 100644 --- a/crates/blockifier/src/blockifier/transaction_executor.rs +++ b/crates/blockifier/src/blockifier/transaction_executor.rs @@ -123,6 +123,7 @@ impl TransactionExecutor { &tx_state_changes_keys, &tx_execution_info.summarize(&self.block_context.versioned_constants), &tx_execution_info.receipt.resources, + &self.block_context.versioned_constants, )?; transactional_state.commit(); diff --git a/crates/blockifier/src/bouncer.rs b/crates/blockifier/src/bouncer.rs index 29a05432a16..02865067188 100644 --- a/crates/blockifier/src/bouncer.rs +++ b/crates/blockifier/src/bouncer.rs @@ -19,7 +19,8 @@ use crate::state::cached_state::{StateChangesKeys, StorageEntry}; use crate::state::state_api::StateReader; use crate::transaction::errors::TransactionExecutionError; use crate::transaction::objects::{ExecutionResourcesTraits, TransactionExecutionResult}; -use crate::utils::usize_from_u64; +use crate::utils::{u64_from_usize, usize_from_u64}; +use crate::versioned_constants::VersionedConstants; #[cfg(test)] #[path = "bouncer_test.rs"] @@ -49,7 +50,7 @@ macro_rules! impl_checked_ops { }; } -pub type HashMapWrapper = HashMap; +pub type BuiltinCounterMap = HashMap; #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] pub struct BouncerConfig { @@ -94,25 +95,15 @@ impl SerializeConfig for BouncerConfig { #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] /// Represents the execution resources counted throughout block creation. pub struct BouncerWeights { - pub builtin_count: BuiltinCount, pub l1_gas: usize, pub message_segment_length: usize, pub n_events: usize, - pub n_steps: usize, pub state_diff_size: usize, pub sierra_gas: GasAmount, } impl BouncerWeights { - impl_checked_ops!( - builtin_count, - l1_gas, - message_segment_length, - n_events, - n_steps, - state_diff_size, - sierra_gas - ); + impl_checked_ops!(l1_gas, message_segment_length, n_events, state_diff_size, sierra_gas); pub fn has_room(&self, other: Self) -> bool { self.checked_sub(other).is_some() @@ -121,11 +112,9 @@ impl BouncerWeights { pub fn max() -> Self { Self { l1_gas: usize::MAX, - n_steps: usize::MAX, message_segment_length: usize::MAX, state_diff_size: usize::MAX, n_events: usize::MAX, - builtin_count: BuiltinCount::max(), sierra_gas: GasAmount::MAX, } } @@ -133,10 +122,8 @@ impl BouncerWeights { pub fn empty() -> Self { Self { n_events: 0, - builtin_count: BuiltinCount::empty(), l1_gas: 0, message_segment_length: 0, - n_steps: 0, state_diff_size: 0, sierra_gas: GasAmount::ZERO, } @@ -148,25 +135,22 @@ impl Default for BouncerWeights { fn default() -> Self { Self { l1_gas: 2500000, - n_steps: 2500000, message_segment_length: 3700, n_events: 5000, state_diff_size: 4000, - builtin_count: BuiltinCount::default(), - sierra_gas: GasAmount(250000000), + sierra_gas: GasAmount(400000000), } } } impl SerializeConfig for BouncerWeights { fn dump(&self) -> BTreeMap { - let mut dump = append_sub_config_name(self.builtin_count.dump(), "builtin_count"); - dump.append(&mut BTreeMap::from([ser_param( + let mut dump = BTreeMap::from([ser_param( "l1_gas", &self.l1_gas, "An upper bound on the total l1_gas used in a block.", ParamPrivacyInput::Public, - )])); + )]); dump.append(&mut BTreeMap::from([ser_param( "message_segment_length", &self.message_segment_length, @@ -179,12 +163,6 @@ impl SerializeConfig for BouncerWeights { "An upper bound on the total number of events generated in a block.", ParamPrivacyInput::Public, )])); - dump.append(&mut BTreeMap::from([ser_param( - "n_steps", - &self.n_steps, - "An upper bound on the total number of steps in a block.", - ParamPrivacyInput::Public, - )])); dump.append(&mut BTreeMap::from([ser_param( "state_diff_size", &self.state_diff_size, @@ -205,234 +183,17 @@ impl std::fmt::Display for BouncerWeights { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, - "BouncerWeights {{ l1_gas: {}, n_steps: {}, message_segment_length: {}, n_events: {}, \ - state_diff_size: {}, builtin_count: {}, sierra_gas: {} }}", + "BouncerWeights {{ l1_gas: {}, message_segment_length: {}, n_events: {}, \ + state_diff_size: {}, sierra_gas: {} }}", self.l1_gas, - self.n_steps, self.message_segment_length, self.n_events, self.state_diff_size, - self.builtin_count, self.sierra_gas ) } } -#[derive( - Clone, - Copy, - Debug, - derive_more::Add, - derive_more::AddAssign, - derive_more::Sub, - Deserialize, - PartialEq, - Serialize, -)] -pub struct BuiltinCount { - pub add_mod: usize, - pub bitwise: usize, - pub ecdsa: usize, - pub ec_op: usize, - pub keccak: usize, - pub mul_mod: usize, - pub pedersen: usize, - pub poseidon: usize, - pub range_check: usize, - pub range_check96: usize, -} - -macro_rules! impl_all_non_zero { - ($($field:ident),+) => { - pub fn all_non_zero(&self) -> bool { - $( self.$field != 0 )&&+ - } - }; -} - -macro_rules! impl_builtin_variants { - ($($field:ident),+) => { - impl_checked_ops!($($field),+); - impl_all_non_zero!($($field),+); - }; -} - -impl BuiltinCount { - impl_builtin_variants!( - add_mod, - bitwise, - ec_op, - ecdsa, - keccak, - mul_mod, - pedersen, - poseidon, - range_check, - range_check96 - ); - - pub fn max() -> Self { - Self { - add_mod: usize::MAX, - bitwise: usize::MAX, - ecdsa: usize::MAX, - ec_op: usize::MAX, - keccak: usize::MAX, - mul_mod: usize::MAX, - pedersen: usize::MAX, - poseidon: usize::MAX, - range_check: usize::MAX, - range_check96: usize::MAX, - } - } - - pub fn empty() -> Self { - Self { - add_mod: 0, - bitwise: 0, - ecdsa: 0, - ec_op: 0, - keccak: 0, - mul_mod: 0, - pedersen: 0, - poseidon: 0, - range_check: 0, - range_check96: 0, - } - } -} - -impl From for BuiltinCount { - fn from(mut data: HashMapWrapper) -> Self { - // TODO(yael 24/3/24): replace the unwrap_or_default with expect, once the - // ExecutionResources contains all the builtins. - // The keccak config we get from python is not always present. - let builtin_count = Self { - add_mod: data.remove(&BuiltinName::add_mod).unwrap_or_default(), - bitwise: data.remove(&BuiltinName::bitwise).unwrap_or_default(), - ecdsa: data.remove(&BuiltinName::ecdsa).unwrap_or_default(), - ec_op: data.remove(&BuiltinName::ec_op).unwrap_or_default(), - keccak: data.remove(&BuiltinName::keccak).unwrap_or_default(), - mul_mod: data.remove(&BuiltinName::mul_mod).unwrap_or_default(), - pedersen: data.remove(&BuiltinName::pedersen).unwrap_or_default(), - poseidon: data.remove(&BuiltinName::poseidon).unwrap_or_default(), - range_check: data.remove(&BuiltinName::range_check).unwrap_or_default(), - range_check96: data.remove(&BuiltinName::range_check96).unwrap_or_default(), - }; - assert!( - data.is_empty(), - "The following keys do not exist in BuiltinCount: {:?} ", - data.keys() - ); - builtin_count - } -} - -impl std::fmt::Display for BuiltinCount { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "BuiltinCount {{ add_mod: {}, bitwise: {}, ecdsa: {}, ec_op: {}, keccak: {}, mul_mod: \ - {}, pedersen: {}, poseidon: {}, range_check: {}, range_check96: {} }}", - self.add_mod, - self.bitwise, - self.ecdsa, - self.ec_op, - self.keccak, - self.mul_mod, - self.pedersen, - self.poseidon, - self.range_check, - self.range_check96 - ) - } -} - -impl Default for BuiltinCount { - // TODO: update the default values once the actual production values are known. - fn default() -> Self { - Self { - add_mod: 156250, - bitwise: 39062, - ecdsa: 1220, - ec_op: 2441, - keccak: 1220, - mul_mod: 156250, - pedersen: 78125, - poseidon: 78125, - range_check: 156250, - range_check96: 156250, - } - } -} - -impl SerializeConfig for BuiltinCount { - fn dump(&self) -> BTreeMap { - BTreeMap::from_iter([ - ser_param( - "add_mod", - &self.add_mod, - "Max number of add mod builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "bitwise", - &self.bitwise, - "Max number of bitwise builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "ecdsa", - &self.ecdsa, - "Max number of ECDSA builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "ec_op", - &self.ec_op, - "Max number of EC operation builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "keccak", - &self.keccak, - "Max number of keccak builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "mul_mod", - &self.mul_mod, - "Max number of mul mod builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "pedersen", - &self.pedersen, - "Max number of pedersen builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "poseidon", - &self.poseidon, - "Max number of poseidon builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "range_check", - &self.range_check, - "Max number of range check builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ser_param( - "range_check96", - &self.range_check96, - "Max number of range check 96 builtin usage in a block.", - ParamPrivacyInput::Public, - ), - ]) - } -} - #[derive(Debug, PartialEq)] #[cfg_attr(test, derive(Clone))] pub struct Bouncer { @@ -473,6 +234,7 @@ impl Bouncer { tx_state_changes_keys: &StateChangesKeys, tx_execution_summary: &ExecutionSummary, tx_resources: &TransactionResources, + versioned_constants: &VersionedConstants, ) -> TransactionExecutorResult<()> { // The countings here should be linear in the transactional state changes and execution info // rather than the cumulative state attributes. @@ -493,6 +255,7 @@ impl Bouncer { n_marginal_visited_storage_entries, tx_resources, &marginal_state_changes_keys, + versioned_constants, )?; // Check if the transaction can fit the current block available capacity. @@ -542,12 +305,67 @@ impl Bouncer { } } +fn n_steps_to_sierra_gas(n_steps: usize, versioned_constants: &VersionedConstants) -> GasAmount { + let n_steps_u64 = u64_from_usize(n_steps); + let gas_per_step = versioned_constants.os_constants.gas_costs.base.step_gas_cost; + let n_steps_gas_cost = n_steps_u64.checked_mul(gas_per_step).unwrap_or_else(|| { + panic!( + "Multiplication overflow while converting steps to gas. steps: {}, gas per step: {}.", + n_steps, gas_per_step + ) + }); + GasAmount(n_steps_gas_cost) +} + +fn vm_resources_to_sierra_gas( + resources: ExecutionResources, + versioned_constants: &VersionedConstants, +) -> GasAmount { + let builtins_gas_cost = + builtins_to_sierra_gas(&resources.prover_builtins(), versioned_constants); + let n_steps_gas_cost = n_steps_to_sierra_gas(resources.total_n_steps(), versioned_constants); + n_steps_gas_cost.checked_add(builtins_gas_cost).unwrap_or_else(|| { + panic!( + "Addition overflow while converting vm resources to gas. steps gas: {}, builtins gas: \ + {}.", + n_steps_gas_cost, builtins_gas_cost + ) + }) +} + +pub fn builtins_to_sierra_gas( + builtin_counts: &BuiltinCounterMap, + versioned_constants: &VersionedConstants, +) -> GasAmount { + let gas_costs = &versioned_constants.os_constants.gas_costs.builtins; + + let total_gas = builtin_counts + .iter() + .try_fold(0u64, |accumulated_gas, (&builtin, &count)| { + let builtin_gas_cost = gas_costs + .get_builtin_gas_cost(&builtin) + .unwrap_or_else(|err| panic!("Failed to get gas cost: {}", err)); + let builtin_count_u64 = u64_from_usize(count); + let builtin_total_cost = builtin_count_u64.checked_mul(builtin_gas_cost)?; + accumulated_gas.checked_add(builtin_total_cost) + }) + .unwrap_or_else(|| { + panic!( + "Overflow occurred while converting built-in resources to gas. Builtins: {:?}", + builtin_counts + ) + }); + + GasAmount(total_gas) +} + pub fn get_tx_weights( state_reader: &S, executed_class_hashes: &HashSet, n_visited_storage_entries: usize, tx_resources: &TransactionResources, state_changes_keys: &StateChangesKeys, + versioned_constants: &VersionedConstants, ) -> TransactionExecutionResult { let message_resources = &tx_resources.starknet_resources.messages; let message_starknet_l1gas = usize_from_u64(message_resources.get_starknet_gas_cost().l1_gas.0) @@ -557,15 +375,22 @@ pub fn get_tx_weights( additional_os_resources += &get_particia_update_resources(n_visited_storage_entries); let vm_resources = &additional_os_resources + &tx_resources.computation.vm_resources; + let sierra_gas = tx_resources.computation.sierra_gas; + let vm_resources_gas = vm_resources_to_sierra_gas(vm_resources, versioned_constants); + let sierra_gas_with_vm = sierra_gas.checked_add(vm_resources_gas).unwrap_or_else(|| { + panic!( + "Addition overflow while converting vm resources to gas. current gas: {}, vm as gas: \ + {}.", + sierra_gas, vm_resources_gas + ) + }); Ok(BouncerWeights { l1_gas: message_starknet_l1gas, message_segment_length: message_resources.message_segment_length, n_events: tx_resources.starknet_resources.archival_data.event_summary.n_events, - n_steps: vm_resources.total_n_steps(), - builtin_count: BuiltinCount::from(vm_resources.prover_builtins()), state_diff_size: get_onchain_data_segment_length(&state_changes_keys.count()), - sierra_gas: tx_resources.computation.sierra_gas, + sierra_gas: sierra_gas_with_vm, }) } @@ -609,6 +434,7 @@ pub fn verify_tx_weights_within_max_capacity( tx_resources: &TransactionResources, tx_state_changes_keys: &StateChangesKeys, bouncer_config: &BouncerConfig, + versioned_constants: &VersionedConstants, ) -> TransactionExecutionResult<()> { let tx_weights = get_tx_weights( state_reader, @@ -616,6 +442,7 @@ pub fn verify_tx_weights_within_max_capacity( tx_execution_summary.visited_storage_entries.len(), tx_resources, tx_state_changes_keys, + versioned_constants, )?; bouncer_config.within_max_capacity_or_err(tx_weights) diff --git a/crates/blockifier/src/bouncer_test.rs b/crates/blockifier/src/bouncer_test.rs index 9385fc97742..3f2a704cda3 100644 --- a/crates/blockifier/src/bouncer_test.rs +++ b/crates/blockifier/src/bouncer_test.rs @@ -1,8 +1,6 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; use assert_matches::assert_matches; -use cairo_vm::types::builtin_name::BuiltinName; -use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use rstest::rstest; use starknet_api::execution_resources::GasAmount; use starknet_api::transaction::fields::Fee; @@ -10,12 +8,7 @@ use starknet_api::{class_hash, contract_address, storage_key}; use super::BouncerConfig; use crate::blockifier::transaction_executor::TransactionExecutorError; -use crate::bouncer::{ - verify_tx_weights_within_max_capacity, - Bouncer, - BouncerWeights, - BuiltinCount, -}; +use crate::bouncer::{verify_tx_weights_within_max_capacity, Bouncer, BouncerWeights}; use crate::context::BlockContext; use crate::execution::call_info::ExecutionSummary; use crate::fee::resources::{ComputationResources, TransactionResources}; @@ -26,42 +19,16 @@ use crate::transaction::errors::TransactionExecutionError; #[test] fn test_block_weights_has_room() { let max_bouncer_weights = BouncerWeights { - builtin_count: BuiltinCount { - add_mod: 10, - bitwise: 10, - ecdsa: 10, - ec_op: 10, - keccak: 10, - mul_mod: 10, - pedersen: 10, - poseidon: 10, - range_check: 10, - range_check96: 10, - }, l1_gas: 10, message_segment_length: 10, n_events: 10, - n_steps: 10, state_diff_size: 10, sierra_gas: GasAmount(10), }; let bouncer_weights = BouncerWeights { - builtin_count: BuiltinCount { - add_mod: 6, - bitwise: 6, - ecdsa: 7, - ec_op: 7, - keccak: 8, - mul_mod: 6, - pedersen: 7, - poseidon: 9, - range_check: 10, - range_check96: 10, - }, l1_gas: 7, message_segment_length: 10, - n_steps: 0, n_events: 2, state_diff_size: 7, sierra_gas: GasAmount(7), @@ -70,24 +37,11 @@ fn test_block_weights_has_room() { assert!(max_bouncer_weights.has_room(bouncer_weights)); let bouncer_weights_exceeds_max = BouncerWeights { - builtin_count: BuiltinCount { - add_mod: 5, - bitwise: 11, - ecdsa: 5, - ec_op: 5, - keccak: 5, - mul_mod: 5, - pedersen: 5, - poseidon: 5, - range_check: 5, - range_check96: 5, - }, l1_gas: 5, message_segment_length: 5, - n_steps: 5, n_events: 5, state_diff_size: 5, - sierra_gas: GasAmount(5), + sierra_gas: GasAmount(15), }; assert!(!max_bouncer_weights.has_room(bouncer_weights_exceeds_max)); @@ -106,21 +60,8 @@ fn test_block_weights_has_room() { ])), bouncer_config: BouncerConfig::empty(), accumulated_weights: BouncerWeights { - builtin_count: BuiltinCount { - add_mod: 10, - bitwise: 10, - ecdsa: 10, - ec_op: 10, - keccak: 10, - mul_mod: 10, - pedersen: 10, - poseidon: 10, - range_check: 10, - range_check96: 10, - }, l1_gas: 10, message_segment_length: 10, - n_steps: 10, n_events: 10, state_diff_size: 10, sierra_gas: GasAmount(10), @@ -137,21 +78,8 @@ fn test_bouncer_update(#[case] initial_bouncer: Bouncer) { }; let weights_to_update = BouncerWeights { - builtin_count: BuiltinCount { - add_mod: 0, - bitwise: 1, - ecdsa: 2, - ec_op: 3, - keccak: 4, - mul_mod: 0, - pedersen: 6, - poseidon: 7, - range_check: 8, - range_check96: 0, - }, l1_gas: 9, message_segment_length: 10, - n_steps: 0, n_events: 1, state_diff_size: 2, sierra_gas: GasAmount(9), @@ -181,31 +109,18 @@ fn test_bouncer_update(#[case] initial_bouncer: Bouncer) { } #[rstest] -#[case::positive_flow(1, "ok")] -#[case::block_full(11, "block_full")] -#[case::transaction_too_large(21, "too_large")] -fn test_bouncer_try_update(#[case] added_ecdsa: usize, #[case] scenario: &'static str) { - let state = - &mut test_state(&BlockContext::create_for_account_testing().chain_info, Fee(0), &[]); +#[case::positive_flow(GasAmount(1), "ok")] +#[case::block_full(GasAmount(11), "block_full")] +#[case::transaction_too_large(GasAmount(21), "too_large")] +fn test_bouncer_try_update(#[case] added_gas: GasAmount, #[case] scenario: &'static str) { + let block_context = BlockContext::create_for_account_testing(); + let state = &mut test_state(&block_context.chain_info, Fee(0), &[]); let mut transactional_state = TransactionalState::create_transactional(state); // Setup the bouncer. let block_max_capacity = BouncerWeights { - builtin_count: BuiltinCount { - add_mod: 20, - bitwise: 20, - ecdsa: 20, - ec_op: 20, - keccak: 20, - mul_mod: 20, - pedersen: 20, - poseidon: 20, - range_check: 20, - range_check96: 20, - }, l1_gas: 20, message_segment_length: 20, - n_steps: 20, n_events: 20, state_diff_size: 20, sierra_gas: GasAmount(20), @@ -213,21 +128,8 @@ fn test_bouncer_try_update(#[case] added_ecdsa: usize, #[case] scenario: &'stati let bouncer_config = BouncerConfig { block_max_capacity }; let accumulated_weights = BouncerWeights { - builtin_count: BuiltinCount { - add_mod: 10, - bitwise: 10, - ecdsa: 10, - ec_op: 10, - keccak: 10, - mul_mod: 10, - pedersen: 10, - poseidon: 10, - range_check: 10, - range_check96: 10, - }, l1_gas: 10, message_segment_length: 10, - n_steps: 10, n_events: 10, state_diff_size: 10, sierra_gas: GasAmount(10), @@ -237,23 +139,9 @@ fn test_bouncer_try_update(#[case] added_ecdsa: usize, #[case] scenario: &'stati // Prepare the resources to be added to the bouncer. let execution_summary = ExecutionSummary { ..Default::default() }; - let builtin_counter = HashMap::from([ - (BuiltinName::bitwise, 1), - (BuiltinName::ecdsa, added_ecdsa), - (BuiltinName::ec_op, 1), - (BuiltinName::keccak, 1), - (BuiltinName::pedersen, 1), - (BuiltinName::poseidon, 1), - (BuiltinName::range_check, 1), - ]); + let tx_resources = TransactionResources { - computation: ComputationResources { - vm_resources: ExecutionResources { - builtin_instance_counter: builtin_counter.clone(), - ..Default::default() - }, - ..Default::default() - }, + computation: ComputationResources { sierra_gas: added_gas, ..Default::default() }, ..Default::default() }; let tx_state_changes_keys = @@ -268,10 +156,10 @@ fn test_bouncer_try_update(#[case] added_ecdsa: usize, #[case] scenario: &'stati &tx_resources, &tx_state_changes_keys, &bouncer.bouncer_config, + &block_context.versioned_constants, ) .map_err(TransactionExecutorError::TransactionExecutionError); - let expected_weights = - BouncerWeights { builtin_count: builtin_counter.into(), ..BouncerWeights::empty() }; + let expected_weights = BouncerWeights { sierra_gas: added_gas, ..BouncerWeights::empty() }; if result.is_ok() { // Try to update the bouncer. @@ -280,6 +168,7 @@ fn test_bouncer_try_update(#[case] added_ecdsa: usize, #[case] scenario: &'stati &tx_state_changes_keys, &execution_summary, &tx_resources, + &block_context.versioned_constants, ); } diff --git a/crates/blockifier/src/concurrency/worker_logic.rs b/crates/blockifier/src/concurrency/worker_logic.rs index 2ab97e5c712..5fb733639ac 100644 --- a/crates/blockifier/src/concurrency/worker_logic.rs +++ b/crates/blockifier/src/concurrency/worker_logic.rs @@ -231,6 +231,7 @@ impl<'a, S: StateReader> WorkerExecutor<'a, S> { &tx_state_changes_keys, &tx_execution_info.summarize(&self.block_context.versioned_constants), &tx_execution_info.receipt.resources, + &self.block_context.versioned_constants, ); if let Err(error) = bouncer_result { match error { diff --git a/crates/blockifier/src/test_utils/struct_impls.rs b/crates/blockifier/src/test_utils/struct_impls.rs index 9c2e12c08cc..6275a6e4bbd 100644 --- a/crates/blockifier/src/test_utils/struct_impls.rs +++ b/crates/blockifier/src/test_utils/struct_impls.rs @@ -20,7 +20,7 @@ use starknet_api::execution_resources::GasAmount; use starknet_api::test_utils::{TEST_ERC20_CONTRACT_ADDRESS, TEST_ERC20_CONTRACT_ADDRESS2}; use crate::blockifier::config::{CairoNativeRunConfig, ContractClassManagerConfig}; -use crate::bouncer::{BouncerConfig, BouncerWeights, BuiltinCount}; +use crate::bouncer::{BouncerConfig, BouncerWeights}; use crate::context::{BlockContext, ChainInfo, FeeTokenAddresses, TransactionContext}; use crate::execution::call_info::{CallExecution, CallInfo, Retdata}; use crate::execution::common_hints::ExecutionMode; @@ -228,12 +228,6 @@ pub trait LoadContractFromFile: serde::de::DeserializeOwned { impl LoadContractFromFile for CasmContractClass {} impl LoadContractFromFile for DeprecatedContractClass {} -impl BouncerWeights { - pub fn create_for_testing(builtin_count: BuiltinCount) -> Self { - Self { builtin_count, ..Self::empty() } - } -} - #[cfg(feature = "cairo_native")] static COMPILED_NATIVE_CONTRACT_CACHE: LazyLock>> = LazyLock::new(|| RwLock::new(HashMap::new())); diff --git a/crates/blockifier/src/transaction/objects.rs b/crates/blockifier/src/transaction/objects.rs index 4cfef890e6e..573517cd1a3 100644 --- a/crates/blockifier/src/transaction/objects.rs +++ b/crates/blockifier/src/transaction/objects.rs @@ -239,6 +239,8 @@ impl ExecutionResourcesTraits for ExecutionResources { self.n_steps // Memory holes are slightly cheaper than actual steps, but we count them as such // for simplicity. + // TODO(AvivG): Compute memory_holes gas accurately while maintaining backward compatibility. + // Define memory_holes_gas version_constants as 100 gas (1 step) for previous versions. + self.n_memory_holes // The "segment arena" builtin is not part of the prover (not in any proof layout); // It is transformed into regular steps by the OS program - each instance requires diff --git a/crates/blockifier/src/transaction/transaction_execution.rs b/crates/blockifier/src/transaction/transaction_execution.rs index 8d7818aecb7..43f8f911eea 100644 --- a/crates/blockifier/src/transaction/transaction_execution.rs +++ b/crates/blockifier/src/transaction/transaction_execution.rs @@ -220,6 +220,7 @@ impl ExecutableTransaction for Transaction { &tx_execution_info.receipt.resources, &tx_state_changes_keys, &block_context.bouncer_config, + &block_context.versioned_constants, )?; Ok(tx_execution_info) diff --git a/crates/native_blockifier/src/errors.rs b/crates/native_blockifier/src/errors.rs index 77d4c032487..07794fc49fc 100644 --- a/crates/native_blockifier/src/errors.rs +++ b/crates/native_blockifier/src/errors.rs @@ -1,6 +1,6 @@ use blockifier::blockifier::stateful_validator::StatefulValidatorError; use blockifier::blockifier::transaction_executor::TransactionExecutorError; -use blockifier::bouncer::BuiltinCount; +use blockifier::bouncer::BuiltinCounterMap; use blockifier::state::errors::StateError; use blockifier::transaction::errors::{ ParseError, @@ -104,7 +104,7 @@ pub enum NativeBlockifierInputError { #[derive(Debug, Error)] pub enum InvalidNativeBlockifierInputError { #[error("Invalid builtin count: {0:?}.")] - InvalidBuiltinCounts(BuiltinCount), + InvalidBuiltinCounts(BuiltinCounterMap), #[error("Invalid Wei gas price: {0}.")] InvalidL1GasPriceWei(u128), #[error("Invalid Fri gas price: {0}.")] diff --git a/crates/native_blockifier/src/py_objects.rs b/crates/native_blockifier/src/py_objects.rs index e5ecc2035a8..44c85fa4380 100644 --- a/crates/native_blockifier/src/py_objects.rs +++ b/crates/native_blockifier/src/py_objects.rs @@ -9,10 +9,16 @@ use blockifier::blockifier::config::{ ConcurrencyConfig, ContractClassManagerConfig, }; -use blockifier::bouncer::{BouncerConfig, BouncerWeights, BuiltinCount, HashMapWrapper}; +use blockifier::bouncer::{ + builtins_to_sierra_gas, + BouncerConfig, + BouncerWeights, + BuiltinCounterMap, +}; use blockifier::state::contract_class_manager::DEFAULT_COMPILATION_REQUEST_CHANNEL_SIZE; use blockifier::state::global_cache::GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST; -use blockifier::versioned_constants::VersionedConstantsOverrides; +use blockifier::utils::u64_from_usize; +use blockifier::versioned_constants::{VersionedConstants, VersionedConstantsOverrides}; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use pyo3::prelude::*; @@ -105,21 +111,20 @@ impl TryFrom for BouncerConfig { fn hash_map_into_builtin_count( builtins: HashMap, -) -> Result { - let mut wrapper = HashMapWrapper::new(); +) -> Result { + let mut builtin_count_map = BuiltinCounterMap::new(); for (builtin_name, count) in builtins.iter() { + if *count == 0 { + return Err(NativeBlockifierInputError::InvalidNativeBlockifierInputError( + InvalidNativeBlockifierInputError::InvalidBuiltinCounts(builtin_count_map.clone()), + )); + } let builtin = BuiltinName::from_str_with_suffix(builtin_name) .ok_or(NativeBlockifierInputError::UnknownBuiltin(builtin_name.clone()))?; - wrapper.insert(builtin, *count); - } - let builtin_count: BuiltinCount = wrapper.into(); - if builtin_count.all_non_zero() { - Ok(builtin_count) - } else { - Err(NativeBlockifierInputError::InvalidNativeBlockifierInputError( - InvalidNativeBlockifierInputError::InvalidBuiltinCounts(builtin_count), - )) + builtin_count_map.insert(builtin, *count); } + + Ok(builtin_count_map) } fn hash_map_into_bouncer_weights( @@ -139,14 +144,30 @@ fn hash_map_into_bouncer_weights( .try_into() .unwrap_or_else(|err| panic!("Failed to convert 'sierra_gas' into GasAmount: {err}.")), ); + // TODO(AvivG): Implement logic to retrieve only the Sierra gas limit from Python without VM + // resources. + let builtins_count = hash_map_into_builtin_count(data)?; + let versioned_constants = VersionedConstants::latest_constants(); + let builtins_gas = builtins_to_sierra_gas(&builtins_count, versioned_constants); + let steps_gas = GasAmount(u64_from_usize(n_steps)); + + let sierra_gas_w_vm = sierra_gas + .checked_add(builtins_gas) + .and_then(|gas_with_builtins| gas_with_builtins.checked_add(steps_gas)) + .unwrap_or_else(|| { + panic!( + "Gas overflow: failed to add built-in gas and steps to Sierra gas.\nBuilt-ins: \ + {:?}\nSteps: {}\nInitial Sierra gas: {}", + builtins_count, n_steps, sierra_gas + ) + }); + Ok(BouncerWeights { l1_gas, - n_steps, message_segment_length, state_diff_size, n_events, - builtin_count: hash_map_into_builtin_count(data)?, - sierra_gas, + sierra_gas: sierra_gas_w_vm, }) }