diff --git a/crates/blockifier/src/concurrency/scheduler_test.rs b/crates/blockifier/src/concurrency/scheduler_test.rs index a9a0a7a711..617b486e62 100644 --- a/crates/blockifier/src/concurrency/scheduler_test.rs +++ b/crates/blockifier/src/concurrency/scheduler_test.rs @@ -164,10 +164,8 @@ fn test_set_executed_status(#[case] tx_status: TransactionStatus) { #[case::reduces_validation_index(0, 10)] #[case::does_not_reduce_validation_index(10, 0)] fn test_finish_execution(#[case] tx_index: TxIndex, #[case] validation_index: TxIndex) { - let scheduler = default_scheduler!( - chunk_size: DEFAULT_CHUNK_SIZE, - validation_index: validation_index, - ); + let scheduler = + default_scheduler!(chunk_size: DEFAULT_CHUNK_SIZE, validation_index: validation_index,); scheduler.set_tx_status(tx_index, TransactionStatus::Executing); scheduler.finish_execution(tx_index); assert_eq!(*scheduler.lock_tx_status(tx_index), TransactionStatus::Executed); @@ -223,10 +221,8 @@ fn test_finish_validation( #[case] execution_index: TxIndex, #[case] aborted: bool, ) { - let scheduler = default_scheduler!( - chunk_size: DEFAULT_CHUNK_SIZE, - execution_index: execution_index, - ); + let scheduler = + default_scheduler!(chunk_size: DEFAULT_CHUNK_SIZE, execution_index: execution_index,); let tx_status = if aborted { TransactionStatus::Aborting } else { TransactionStatus::Executed }; scheduler.set_tx_status(tx_index, tx_status); let mut result = Task::NoTask; diff --git a/crates/blockifier/src/versioned_constants.rs b/crates/blockifier/src/versioned_constants.rs index aa5d9a3abd..dfa58db2d2 100644 --- a/crates/blockifier/src/versioned_constants.rs +++ b/crates/blockifier/src/versioned_constants.rs @@ -202,6 +202,32 @@ impl VersionedConstants { ) -> Self { Self { validate_max_n_steps, max_recursion_depth, ..Self::latest_constants().clone() } } + + /// `versioned_constants_base_overrides` are used if they are provided, otherwise the latest + /// versioned constants are used. `validate_max_n_steps` & `max_recursion_depth` override both. + pub fn get_versioned_constants( + versioned_constants_overrides: VersionedConstantsOverrides, + ) -> Self { + let VersionedConstantsOverrides { + validate_max_n_steps, + max_recursion_depth, + versioned_constants_base_overrides, + } = versioned_constants_overrides; + let base_overrides = match versioned_constants_base_overrides { + Some(versioned_constants_base_overrides) => { + log::debug!( + "Using provided `versioned_constants_base_overrides` (with additional \ + overrides)." + ); + versioned_constants_base_overrides + } + None => { + log::debug!("Using latest versioned constants (with additional overrides)."); + Self::latest_constants().clone() + } + }; + Self { validate_max_n_steps, max_recursion_depth, ..base_overrides } + } } impl TryFrom<&Path> for VersionedConstants { @@ -690,3 +716,9 @@ pub struct ResourcesByVersion { pub resources: ResourcesParams, pub deprecated_resources: ResourcesParams, } + +pub struct VersionedConstantsOverrides { + pub validate_max_n_steps: u32, + pub max_recursion_depth: usize, + pub versioned_constants_base_overrides: Option, +} diff --git a/crates/blockifier/src/versioned_constants_test.rs b/crates/blockifier/src/versioned_constants_test.rs index 87bf080ae7..d449dff959 100644 --- a/crates/blockifier/src/versioned_constants_test.rs +++ b/crates/blockifier/src/versioned_constants_test.rs @@ -86,6 +86,26 @@ fn get_json_value_without_defaults() -> serde_json::Value { json_value_without_defaults } +/// Assert `versioned_constants_base_overrides` are used when provided. +#[test] +fn test_versioned_constants_base_overrides() { + // Create a versioned constants copy with a modified value for `invoke_tx_max_n_steps`. + let mut versioned_constants_base_overrides = DEFAULT_CONSTANTS.clone(); + versioned_constants_base_overrides.invoke_tx_max_n_steps += 1; + + let result = VersionedConstants::get_versioned_constants(VersionedConstantsOverrides { + validate_max_n_steps: versioned_constants_base_overrides.validate_max_n_steps, + max_recursion_depth: versioned_constants_base_overrides.max_recursion_depth, + versioned_constants_base_overrides: Some(versioned_constants_base_overrides.clone()), + }); + + // Assert the new value is used. + assert_eq!( + result.invoke_tx_max_n_steps, + versioned_constants_base_overrides.invoke_tx_max_n_steps + ); +} + #[test] fn test_default_values() { let json_value_without_defaults = get_json_value_without_defaults(); diff --git a/crates/native_blockifier/src/lib.rs b/crates/native_blockifier/src/lib.rs index 4dc4a0f476..1ae8dd5464 100644 --- a/crates/native_blockifier/src/lib.rs +++ b/crates/native_blockifier/src/lib.rs @@ -32,6 +32,7 @@ use py_validator::PyValidator; use pyo3::prelude::*; use storage::StorageConfig; +use crate::py_objects::PyVersionedConstantsOverrides; use crate::py_state_diff::PyStateDiff; use crate::py_testing_wrappers::{ estimate_casm_hash_computation_resources_for_testing_list, @@ -47,6 +48,7 @@ fn native_blockifier(py: Python<'_>, py_module: &PyModule) -> PyResult<()> { py_module.add_class::()?; py_module.add_class::()?; py_module.add_class::()?; + py_module.add_class::()?; py_module.add_class::()?; py_module.add_class::()?; py_module.add("UndeclaredClassHashError", py.get_type::())?; diff --git a/crates/native_blockifier/src/py_block_executor.rs b/crates/native_blockifier/src/py_block_executor.rs index 4d4a33f13c..f5d7f84060 100644 --- a/crates/native_blockifier/src/py_block_executor.rs +++ b/crates/native_blockifier/src/py_block_executor.rs @@ -10,7 +10,7 @@ use blockifier::state::cached_state::CachedState; use blockifier::state::global_cache::GlobalContractCache; use blockifier::transaction::objects::{GasVector, ResourcesMapping, TransactionExecutionInfo}; use blockifier::transaction::transaction_execution::Transaction; -use blockifier::versioned_constants::VersionedConstants; +use blockifier::versioned_constants::{VersionedConstants, VersionedConstantsOverrides}; use pyo3::prelude::*; use pyo3::types::{PyBytes, PyList}; use pyo3::{FromPyObject, PyAny, Python}; @@ -21,7 +21,7 @@ use starknet_api::hash::StarkFelt; use starknet_api::transaction::Fee; use crate::errors::{NativeBlockifierError, NativeBlockifierResult}; -use crate::py_objects::{PyBouncerConfig, PyConcurrencyConfig}; +use crate::py_objects::{PyBouncerConfig, PyConcurrencyConfig, PyVersionedConstantsOverrides}; use crate::py_state_diff::{PyBlockInfo, PyStateDiff}; use crate::py_transaction::{py_tx, PyClassInfo, PY_TX_PARSING_ERR}; use crate::py_utils::{int_to_chain_id, into_block_number_hash_pair, PyFelt}; @@ -91,23 +91,22 @@ pub struct PyBlockExecutor { #[pymethods] impl PyBlockExecutor { #[new] - #[pyo3(signature = (bouncer_config, concurrency_config, general_config, validate_max_n_steps, max_recursion_depth, global_contract_cache_size, target_storage_config))] + #[pyo3(signature = (bouncer_config, concurrency_config, general_config, global_contract_cache_size, target_storage_config, py_versioned_constants_overrides))] pub fn create( bouncer_config: PyBouncerConfig, concurrency_config: PyConcurrencyConfig, general_config: PyGeneralConfig, - validate_max_n_steps: u32, - max_recursion_depth: usize, global_contract_cache_size: usize, target_storage_config: StorageConfig, + py_versioned_constants_overrides: PyVersionedConstantsOverrides, ) -> Self { log::debug!("Initializing Block Executor..."); let storage = PapyrusStorage::new(target_storage_config).expect("Failed to initialize storage."); - let versioned_constants = VersionedConstants::latest_constants_with_overrides( - validate_max_n_steps, - max_recursion_depth, - ); + let versioned_constants_overrides = + VersionedConstantsOverrides::from(py_versioned_constants_overrides); + let versioned_constants = + VersionedConstants::get_versioned_constants(versioned_constants_overrides); log::debug!("Initialized Block Executor."); Self { diff --git a/crates/native_blockifier/src/py_objects.rs b/crates/native_blockifier/src/py_objects.rs index ac5c2da789..6f130c189c 100644 --- a/crates/native_blockifier/src/py_objects.rs +++ b/crates/native_blockifier/src/py_objects.rs @@ -3,7 +3,9 @@ use std::collections::HashMap; use blockifier::abi::constants; use blockifier::blockifier::config::ConcurrencyConfig; use blockifier::bouncer::{BouncerConfig, BouncerWeights, BuiltinCount}; +use blockifier::versioned_constants::{VersionedConstants, VersionedConstantsOverrides}; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; +use pyo3::exceptions::PyValueError; use pyo3::prelude::*; // From Rust to Python. @@ -31,6 +33,58 @@ impl From for PyExecutionResources { // From Python to Rust. +#[pyclass] +#[derive(Clone)] +pub struct PyVersionedConstantsOverrides { + pub validate_max_n_steps: u32, + pub max_recursion_depth: usize, + pub versioned_constants_base_overrides: Option, +} + +#[pymethods] +impl PyVersionedConstantsOverrides { + #[new] + #[pyo3(signature = (validate_max_n_steps, max_recursion_depth, versioned_constants_base_overrides))] + pub fn create( + validate_max_n_steps: u32, + max_recursion_depth: usize, + versioned_constants_base_overrides: Option, + ) -> Self { + Self { validate_max_n_steps, max_recursion_depth, versioned_constants_base_overrides } + } + + #[staticmethod] + pub fn assert_versioned_constants_load_successfully( + versioned_constants_str: &str, + ) -> PyResult<()> { + if serde_json::from_str::(versioned_constants_str).is_ok() { + Ok(()) + } else { + Err(PyValueError::new_err("Failed to parse `versioned_constants_str`.")) + } + } +} + +impl From for VersionedConstantsOverrides { + fn from(py_versioned_constants_overrides: PyVersionedConstantsOverrides) -> Self { + let PyVersionedConstantsOverrides { + validate_max_n_steps, + max_recursion_depth, + versioned_constants_base_overrides, + } = py_versioned_constants_overrides; + let base_overrides = + versioned_constants_base_overrides.map(|versioned_constants_base_overrides| { + serde_json::from_str(&versioned_constants_base_overrides) + .expect("Versioned constants JSON file is malformed.") + }); + Self { + validate_max_n_steps, + max_recursion_depth, + versioned_constants_base_overrides: base_overrides, + } + } +} + #[derive(Clone, Debug, FromPyObject)] pub struct PyBouncerConfig { pub full_total_weights_with_keccak: HashMap, diff --git a/crates/native_blockifier/src/py_validator.rs b/crates/native_blockifier/src/py_validator.rs index 5e986d1280..692f08ee67 100644 --- a/crates/native_blockifier/src/py_validator.rs +++ b/crates/native_blockifier/src/py_validator.rs @@ -2,13 +2,14 @@ use blockifier::blockifier::stateful_validator::StatefulValidator; use blockifier::bouncer::BouncerConfig; use blockifier::context::BlockContext; use blockifier::state::cached_state::CachedState; -use blockifier::versioned_constants::VersionedConstants; +use blockifier::versioned_constants::{VersionedConstants, VersionedConstantsOverrides}; use pyo3::{pyclass, pymethods, PyAny}; use starknet_api::core::Nonce; use starknet_api::transaction::TransactionHash; use crate::errors::NativeBlockifierResult; use crate::py_block_executor::PyGeneralConfig; +use crate::py_objects::PyVersionedConstantsOverrides; use crate::py_state_diff::PyBlockInfo; use crate::py_transaction::{py_account_tx, PyClassInfo, PY_TX_PARSING_ERR}; use crate::py_utils::PyFelt; @@ -22,24 +23,23 @@ pub struct PyValidator { #[pymethods] impl PyValidator { #[new] - #[pyo3(signature = (general_config, state_reader_proxy, next_block_info, validate_max_n_steps, max_recursion_depth, max_nonce_for_validation_skip))] + #[pyo3(signature = (general_config, state_reader_proxy, next_block_info, max_nonce_for_validation_skip, py_versioned_constants_overrides))] pub fn create( general_config: PyGeneralConfig, state_reader_proxy: &PyAny, next_block_info: PyBlockInfo, - validate_max_n_steps: u32, - max_recursion_depth: usize, max_nonce_for_validation_skip: PyFelt, + py_versioned_constants_overrides: PyVersionedConstantsOverrides, ) -> NativeBlockifierResult { // Create the state. let state_reader = PyStateReader::new(state_reader_proxy); let state = CachedState::new(state_reader); // Create the block context. - let versioned_constants = VersionedConstants::latest_constants_with_overrides( - validate_max_n_steps, - max_recursion_depth, - ); + let versioned_constants_overrides = + VersionedConstantsOverrides::from(py_versioned_constants_overrides); + let versioned_constants = + VersionedConstants::get_versioned_constants(versioned_constants_overrides); let block_context = BlockContext::new( next_block_info.try_into().expect("Failed to convert block info."), general_config.starknet_os_config.into_chain_info(),