From cc5c84b7bc6471dcda7a963766f499c473d137fa Mon Sep 17 00:00:00 2001 From: Yoni <78365039+Yoni-Starkware@users.noreply.github.com> Date: Wed, 27 Nov 2024 17:28:01 +0200 Subject: [PATCH 01/25] refactor(blockifier): rename ContractClass to CompiledClass (#2296) --- .../src/blockifier/transaction_executor.rs | 2 +- crates/blockifier/src/bouncer.rs | 2 +- .../src/concurrency/versioned_state.rs | 11 ++-- .../src/concurrency/versioned_state_test.rs | 20 +++---- .../src/execution/contract_class.rs | 53 ++++++++++--------- .../src/execution/contract_class_test.rs | 4 +- .../deprecated_entry_point_execution.rs | 18 +++---- .../src/execution/deprecated_syscalls/mod.rs | 2 +- .../blockifier/src/execution/entry_point.rs | 13 +++-- .../src/execution/entry_point_execution.rs | 20 +++---- .../src/execution/execution_utils.rs | 26 ++++----- .../src/execution/native/contract_class.rs | 34 ++++++------ .../execution/native/entry_point_execution.rs | 8 +-- .../src/execution/syscalls/syscall_base.rs | 4 +- crates/blockifier/src/state/cached_state.rs | 23 +++----- .../blockifier/src/state/cached_state_test.rs | 12 ++--- crates/blockifier/src/state/global_cache.rs | 8 +-- crates/blockifier/src/state/state_api.rs | 11 ++-- crates/blockifier/src/test_utils/contracts.rs | 16 +++--- .../src/test_utils/dict_state_reader.rs | 9 ++-- .../blockifier/src/test_utils/struct_impls.rs | 18 +++---- .../src/transaction/account_transaction.rs | 16 +++--- .../src/transaction/transactions.rs | 2 +- .../src/transaction/transactions_test.rs | 4 +- .../src/state_reader/test_state_reader.rs | 12 ++--- .../src/py_block_executor.rs | 4 +- .../src/py_block_executor_test.rs | 6 +-- crates/native_blockifier/src/py_test_utils.rs | 4 +- .../src/state_readers/py_state_reader.rs | 21 ++++---- .../papyrus_execution/src/execution_utils.rs | 16 +++--- crates/papyrus_execution/src/state_reader.rs | 19 +++---- .../src/state_reader_test.rs | 33 ++++++------ crates/papyrus_rpc/src/v0_8/api/api_impl.rs | 2 +- crates/papyrus_rpc/src/v0_8/api/mod.rs | 4 +- crates/papyrus_rpc/src/v0_8/api/test.rs | 2 +- .../papyrus_state_reader/src/papyrus_state.rs | 31 +++++------ crates/starknet_api/src/contract_class.rs | 2 +- .../src/executable_transaction.rs | 2 +- crates/starknet_batcher/src/block_builder.rs | 4 +- crates/starknet_gateway/src/rpc_objects.rs | 2 +- .../starknet_gateway/src/rpc_state_reader.rs | 23 ++++---- .../src/rpc_state_reader_test.rs | 22 ++++---- crates/starknet_gateway/src/state_reader.rs | 9 ++-- .../src/state_reader_test_utils.rs | 9 ++-- 44 files changed, 255 insertions(+), 308 deletions(-) diff --git a/crates/blockifier/src/blockifier/transaction_executor.rs b/crates/blockifier/src/blockifier/transaction_executor.rs index af9d216e1b..01be23df90 100644 --- a/crates/blockifier/src/blockifier/transaction_executor.rs +++ b/crates/blockifier/src/blockifier/transaction_executor.rs @@ -161,7 +161,7 @@ impl TransactionExecutor { .block_state .as_ref() .expect(BLOCK_STATE_ACCESS_ERR) - .get_compiled_contract_class(*class_hash)?; + .get_compiled_class(*class_hash)?; Ok((*class_hash, contract_class.get_visited_segments(class_visited_pcs)?)) }) .collect::>()?; diff --git a/crates/blockifier/src/bouncer.rs b/crates/blockifier/src/bouncer.rs index 414fff93a9..7788b06be0 100644 --- a/crates/blockifier/src/bouncer.rs +++ b/crates/blockifier/src/bouncer.rs @@ -551,7 +551,7 @@ pub fn get_casm_hash_calculation_resources( let mut casm_hash_computation_resources = ExecutionResources::default(); for class_hash in executed_class_hashes { - let class = state_reader.get_compiled_contract_class(*class_hash)?; + let class = state_reader.get_compiled_class(*class_hash)?; casm_hash_computation_resources += &class.estimate_casm_hash_computation_resources(); } diff --git a/crates/blockifier/src/concurrency/versioned_state.rs b/crates/blockifier/src/concurrency/versioned_state.rs index 33d97670b9..1d3c9a9270 100644 --- a/crates/blockifier/src/concurrency/versioned_state.rs +++ b/crates/blockifier/src/concurrency/versioned_state.rs @@ -7,7 +7,7 @@ use starknet_types_core::felt::Felt; use crate::concurrency::versioned_storage::VersionedStorage; use crate::concurrency::TxIndex; -use crate::execution::contract_class::RunnableContractClass; +use crate::execution::contract_class::RunnableCompiledClass; use crate::state::cached_state::{ContractClassMapping, StateMaps}; use crate::state::errors::StateError; use crate::state::state_api::{StateReader, StateResult, UpdatableState}; @@ -34,7 +34,7 @@ pub struct VersionedState { // the compiled contract classes mapping. Each key with value false, sohuld not apprear // in the compiled contract classes mapping. declared_contracts: VersionedStorage, - compiled_contract_classes: VersionedStorage, + compiled_contract_classes: VersionedStorage, } impl VersionedState { @@ -336,14 +336,11 @@ impl StateReader for VersionedStateProxy { } } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { let mut state = self.state(); match state.compiled_contract_classes.read(self.tx_index, class_hash) { Some(value) => Ok(value), - None => match state.initial_state.get_compiled_contract_class(class_hash) { + None => match state.initial_state.get_compiled_class(class_hash) { Ok(initial_value) => { state.declared_contracts.set_initial_value(class_hash, true); state diff --git a/crates/blockifier/src/concurrency/versioned_state_test.rs b/crates/blockifier/src/concurrency/versioned_state_test.rs index 991723acfb..c817263ddc 100644 --- a/crates/blockifier/src/concurrency/versioned_state_test.rs +++ b/crates/blockifier/src/concurrency/versioned_state_test.rs @@ -97,12 +97,9 @@ fn test_versioned_state_proxy() { versioned_state_proxys[5].get_compiled_class_hash(class_hash).unwrap(), compiled_class_hash ); - assert_eq!( - versioned_state_proxys[7].get_compiled_contract_class(class_hash).unwrap(), - contract_class - ); + assert_eq!(versioned_state_proxys[7].get_compiled_class(class_hash).unwrap(), contract_class); assert_matches!( - versioned_state_proxys[7].get_compiled_contract_class(another_class_hash).unwrap_err(), + versioned_state_proxys[7].get_compiled_class(another_class_hash).unwrap_err(), StateError::UndeclaredClassHash(class_hash) if another_class_hash == class_hash ); @@ -197,7 +194,7 @@ fn test_versioned_state_proxy() { compiled_class_hash_v18 ); assert_eq!( - versioned_state_proxys[15].get_compiled_contract_class(class_hash).unwrap(), + versioned_state_proxys[15].get_compiled_class(class_hash).unwrap(), contract_class_v11 ); } @@ -321,7 +318,7 @@ fn test_validate_reads( assert!(transactional_state.cache.borrow().initial_reads.declared_contracts.is_empty()); assert_matches!( - transactional_state.get_compiled_contract_class(class_hash), + transactional_state.get_compiled_class(class_hash), Err(StateError::UndeclaredClassHash(err_class_hash)) if err_class_hash == class_hash ); @@ -440,10 +437,7 @@ fn test_apply_writes( &HashMap::default(), ); assert!(transactional_states[1].get_class_hash_at(contract_address).unwrap() == class_hash_0); - assert!( - transactional_states[1].get_compiled_contract_class(class_hash).unwrap() - == contract_class_0 - ); + assert!(transactional_states[1].get_compiled_class(class_hash).unwrap() == contract_class_0); } #[rstest] @@ -659,7 +653,5 @@ fn test_versioned_proxy_state_flow( .commit_chunk_and_recover_block_state(4, HashMap::new()); assert!(modified_block_state.get_class_hash_at(contract_address).unwrap() == class_hash_3); - assert!( - modified_block_state.get_compiled_contract_class(class_hash).unwrap() == contract_class_2 - ); + assert!(modified_block_state.get_compiled_class(class_hash).unwrap() == contract_class_2); } diff --git a/crates/blockifier/src/execution/contract_class.rs b/crates/blockifier/src/execution/contract_class.rs index c1c6eec804..cf3d7289f9 100644 --- a/crates/blockifier/src/execution/contract_class.rs +++ b/crates/blockifier/src/execution/contract_class.rs @@ -37,7 +37,7 @@ use crate::execution::entry_point::CallEntryPoint; use crate::execution::errors::PreExecutionError; use crate::execution::execution_utils::{poseidon_hash_many_cost, sn_api_to_cairo_vm_program}; #[cfg(feature = "cairo_native")] -use crate::execution::native::contract_class::NativeContractClassV1; +use crate::execution::native::contract_class::NativeCompiledClassV1; use crate::transaction::errors::TransactionExecutionError; use crate::versioned_constants::CompilerVersion; @@ -58,16 +58,17 @@ pub enum TrackedResource { SierraGas, // AKA Sierra mode. } -/// Represents a runnable Starknet contract class (meaning, the program is runnable by the VM). +/// Represents a runnable Starknet compiled class. +/// Meaning, the program is runnable by the VM (or natively). #[derive(Clone, Debug, Eq, PartialEq, derive_more::From)] -pub enum RunnableContractClass { - V0(ContractClassV0), - V1(ContractClassV1), +pub enum RunnableCompiledClass { + V0(CompiledClassV0), + V1(CompiledClassV1), #[cfg(feature = "cairo_native")] - V1Native(NativeContractClassV1), + V1Native(NativeCompiledClassV1), } -impl TryFrom for RunnableContractClass { +impl TryFrom for RunnableCompiledClass { type Error = ProgramError; fn try_from(raw_contract_class: ContractClass) -> Result { @@ -80,7 +81,7 @@ impl TryFrom for RunnableContractClass { } } -impl RunnableContractClass { +impl RunnableCompiledClass { pub fn constructor_selector(&self) -> Option { match self { Self::V0(class) => class.constructor_selector(), @@ -156,16 +157,16 @@ impl RunnableContractClass { // Note: when deserializing from a SN API class JSON string, the ABI field is ignored // by serde, since it is not required for execution. #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)] -pub struct ContractClassV0(pub Arc); -impl Deref for ContractClassV0 { - type Target = ContractClassV0Inner; +pub struct CompiledClassV0(pub Arc); +impl Deref for CompiledClassV0 { + type Target = CompiledClassV0Inner; fn deref(&self) -> &Self::Target { &self.0 } } -impl ContractClassV0 { +impl CompiledClassV0 { fn constructor_selector(&self) -> Option { Some(self.entry_points_by_type[&EntryPointType::Constructor].first()?.selector) } @@ -201,24 +202,24 @@ impl ContractClassV0 { TrackedResource::CairoSteps } - pub fn try_from_json_string(raw_contract_class: &str) -> Result { - let contract_class: ContractClassV0Inner = serde_json::from_str(raw_contract_class)?; - Ok(ContractClassV0(Arc::new(contract_class))) + pub fn try_from_json_string(raw_contract_class: &str) -> Result { + let contract_class: CompiledClassV0Inner = serde_json::from_str(raw_contract_class)?; + Ok(CompiledClassV0(Arc::new(contract_class))) } } #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)] -pub struct ContractClassV0Inner { +pub struct CompiledClassV0Inner { #[serde(deserialize_with = "deserialize_program")] pub program: Program, pub entry_points_by_type: HashMap>, } -impl TryFrom for ContractClassV0 { +impl TryFrom for CompiledClassV0 { type Error = ProgramError; fn try_from(class: DeprecatedContractClass) -> Result { - Ok(Self(Arc::new(ContractClassV0Inner { + Ok(Self(Arc::new(CompiledClassV0Inner { program: sn_api_to_cairo_vm_program(class.program)?, entry_points_by_type: class.entry_points_by_type, }))) @@ -227,12 +228,12 @@ impl TryFrom for ContractClassV0 { // V1. -/// Represents a runnable Cario (Cairo 1) Starknet contract class (meaning, the program is runnable +/// Represents a runnable Cario (Cairo 1) Starknet compiled class (meaning, the program is runnable /// by the VM). We wrap the actual class in an Arc to avoid cloning the program when cloning the /// class. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct ContractClassV1(pub Arc); -impl Deref for ContractClassV1 { +pub struct CompiledClassV1(pub Arc); +impl Deref for CompiledClassV1 { type Target = ContractClassV1Inner; fn deref(&self) -> &Self::Target { @@ -240,7 +241,7 @@ impl Deref for ContractClassV1 { } } -impl ContractClassV1 { +impl CompiledClassV1 { pub fn constructor_selector(&self) -> Option { self.0.entry_points_by_type.constructor.first().map(|ep| ep.selector) } @@ -286,9 +287,9 @@ impl ContractClassV1 { get_visited_segments(&self.bytecode_segment_lengths, &mut reversed_visited_pcs, &mut 0) } - pub fn try_from_json_string(raw_contract_class: &str) -> Result { + pub fn try_from_json_string(raw_contract_class: &str) -> Result { let casm_contract_class: CasmContractClass = serde_json::from_str(raw_contract_class)?; - let contract_class = ContractClassV1::try_from(casm_contract_class)?; + let contract_class = CompiledClassV1::try_from(casm_contract_class)?; Ok(contract_class) } @@ -413,7 +414,7 @@ impl HasSelector for EntryPointV1 { } } -impl TryFrom for ContractClassV1 { +impl TryFrom for CompiledClassV1 { type Error = ProgramError; fn try_from(class: CasmContractClass) -> Result { @@ -466,7 +467,7 @@ impl TryFrom for ContractClassV1 { Version::parse(&class.compiler_version) .unwrap_or_else(|_| panic!("Invalid version: '{}'", class.compiler_version)), ); - Ok(ContractClassV1(Arc::new(ContractClassV1Inner { + Ok(CompiledClassV1(Arc::new(ContractClassV1Inner { program, entry_points_by_type, hints: string_to_hint, diff --git a/crates/blockifier/src/execution/contract_class_test.rs b/crates/blockifier/src/execution/contract_class_test.rs index 6dcfd7411e..bbf9bedc6c 100644 --- a/crates/blockifier/src/execution/contract_class_test.rs +++ b/crates/blockifier/src/execution/contract_class_test.rs @@ -5,12 +5,12 @@ use assert_matches::assert_matches; use cairo_lang_starknet_classes::NestedIntList; use rstest::rstest; -use crate::execution::contract_class::{ContractClassV1, ContractClassV1Inner}; +use crate::execution::contract_class::{CompiledClassV1, ContractClassV1Inner}; use crate::transaction::errors::TransactionExecutionError; #[rstest] fn test_get_visited_segments() { - let test_contract = ContractClassV1(Arc::new(ContractClassV1Inner { + let test_contract = CompiledClassV1(Arc::new(ContractClassV1Inner { program: Default::default(), entry_points_by_type: Default::default(), hints: Default::default(), diff --git a/crates/blockifier/src/execution/deprecated_entry_point_execution.rs b/crates/blockifier/src/execution/deprecated_entry_point_execution.rs index fd4084682d..bee02bedd5 100644 --- a/crates/blockifier/src/execution/deprecated_entry_point_execution.rs +++ b/crates/blockifier/src/execution/deprecated_entry_point_execution.rs @@ -14,7 +14,7 @@ use starknet_api::hash::StarkHash; use super::execution_utils::SEGMENT_ARENA_BUILTIN_SIZE; use crate::execution::call_info::{CallExecution, CallInfo, ChargedResources}; -use crate::execution::contract_class::{ContractClassV0, TrackedResource}; +use crate::execution::contract_class::{CompiledClassV0, TrackedResource}; use crate::execution::deprecated_syscalls::hint_processor::DeprecatedSyscallHintProcessor; use crate::execution::entry_point::{ CallEntryPoint, @@ -44,12 +44,12 @@ pub const CAIRO0_BUILTINS_NAMES: [BuiltinName; 6] = [ /// Executes a specific call to a contract entry point and returns its output. pub fn execute_entry_point_call( call: CallEntryPoint, - contract_class: ContractClassV0, + compiled_class: CompiledClassV0, state: &mut dyn State, context: &mut EntryPointExecutionContext, ) -> EntryPointExecutionResult { let VmExecutionContext { mut runner, mut syscall_handler, initial_syscall_ptr, entry_point_pc } = - initialize_execution_context(&call, contract_class, state, context)?; + initialize_execution_context(&call, compiled_class, state, context)?; let (implicit_args, args) = prepare_call_arguments( &call, @@ -67,13 +67,13 @@ pub fn execute_entry_point_call( pub fn initialize_execution_context<'a>( call: &CallEntryPoint, - contract_class: ContractClassV0, + compiled_class: CompiledClassV0, state: &'a mut dyn State, context: &'a mut EntryPointExecutionContext, ) -> Result, PreExecutionError> { // Verify use of cairo0 builtins only. let program_builtins: HashSet<&BuiltinName> = - HashSet::from_iter(contract_class.program.iter_builtins()); + HashSet::from_iter(compiled_class.program.iter_builtins()); let unsupported_builtins = &program_builtins - &HashSet::from_iter(CAIRO0_BUILTINS_NAMES.iter()); if !unsupported_builtins.is_empty() { @@ -83,14 +83,14 @@ pub fn initialize_execution_context<'a>( } // Resolve initial PC from EP indicator. - let entry_point_pc = resolve_entry_point_pc(call, &contract_class)?; + let entry_point_pc = resolve_entry_point_pc(call, &compiled_class)?; // Instantiate Cairo runner. let proof_mode = false; let trace_enabled = false; let allow_missing_builtins = false; let program_base = None; let mut runner = - CairoRunner::new(&contract_class.program, LayoutName::starknet, proof_mode, trace_enabled)?; + CairoRunner::new(&compiled_class.program, LayoutName::starknet, proof_mode, trace_enabled)?; runner.initialize_builtins(allow_missing_builtins)?; runner.initialize_segments(program_base); @@ -110,7 +110,7 @@ pub fn initialize_execution_context<'a>( pub fn resolve_entry_point_pc( call: &CallEntryPoint, - contract_class: &ContractClassV0, + compiled_class: &CompiledClassV0, ) -> Result { if call.entry_point_type == EntryPointType::Constructor && call.entry_point_selector != selector_from_name(CONSTRUCTOR_ENTRY_POINT_NAME) @@ -118,7 +118,7 @@ pub fn resolve_entry_point_pc( return Err(PreExecutionError::InvalidConstructorEntryPointName); } - let entry_points_of_same_type = &contract_class.entry_points_by_type[&call.entry_point_type]; + let entry_points_of_same_type = &compiled_class.entry_points_by_type[&call.entry_point_type]; let filtered_entry_points: Vec<_> = entry_points_of_same_type .iter() .filter(|ep| ep.selector == call.entry_point_selector) diff --git a/crates/blockifier/src/execution/deprecated_syscalls/mod.rs b/crates/blockifier/src/execution/deprecated_syscalls/mod.rs index ff0741948f..8a15ad9224 100644 --- a/crates/blockifier/src/execution/deprecated_syscalls/mod.rs +++ b/crates/blockifier/src/execution/deprecated_syscalls/mod.rs @@ -653,7 +653,7 @@ pub fn replace_class( syscall_handler: &mut DeprecatedSyscallHintProcessor<'_>, ) -> DeprecatedSyscallResult { // Ensure the class is declared (by reading it). - syscall_handler.state.get_compiled_contract_class(request.class_hash)?; + syscall_handler.state.get_compiled_class(request.class_hash)?; syscall_handler.state.set_class_hash_at(syscall_handler.storage_address, request.class_hash)?; Ok(ReplaceClassResponse {}) diff --git a/crates/blockifier/src/execution/entry_point.rs b/crates/blockifier/src/execution/entry_point.rs index 048023e0c1..39fd2fa42e 100644 --- a/crates/blockifier/src/execution/entry_point.rs +++ b/crates/blockifier/src/execution/entry_point.rs @@ -147,7 +147,7 @@ impl CallEntryPoint { } // Add class hash to the call, that will appear in the output (call info). self.class_hash = Some(class_hash); - let contract_class = state.get_compiled_contract_class(class_hash)?; + let compiled_class = state.get_compiled_class(class_hash)?; context.revert_infos.0.push(EntryPointRevertInfo::new( self.storage_address, @@ -157,7 +157,7 @@ impl CallEntryPoint { )); // This is the last operation of this function. - execute_entry_point_call_wrapper(self, contract_class, state, context, remaining_gas) + execute_entry_point_call_wrapper(self, compiled_class, state, context, remaining_gas) } /// Similar to `execute`, but returns an error if the outer call is reverted. @@ -406,11 +406,10 @@ pub fn execute_constructor_entry_point( remaining_gas: &mut u64, ) -> ConstructorEntryPointExecutionResult { // Ensure the class is declared (by reading it). - let contract_class = - state.get_compiled_contract_class(ctor_context.class_hash).map_err(|error| { - ConstructorEntryPointExecutionError::new(error.into(), &ctor_context, None) - })?; - let Some(constructor_selector) = contract_class.constructor_selector() else { + let compiled_class = state.get_compiled_class(ctor_context.class_hash).map_err(|error| { + ConstructorEntryPointExecutionError::new(error.into(), &ctor_context, None) + })?; + let Some(constructor_selector) = compiled_class.constructor_selector() else { // Contract has no constructor. return handle_empty_constructor(&ctor_context, calldata, *remaining_gas) .map_err(|error| ConstructorEntryPointExecutionError::new(error, &ctor_context, None)); diff --git a/crates/blockifier/src/execution/entry_point_execution.rs b/crates/blockifier/src/execution/entry_point_execution.rs index 070e55be8a..f1bf7ef01f 100644 --- a/crates/blockifier/src/execution/entry_point_execution.rs +++ b/crates/blockifier/src/execution/entry_point_execution.rs @@ -14,7 +14,7 @@ use starknet_api::execution_resources::GasAmount; use starknet_types_core::felt::Felt; use crate::execution::call_info::{CallExecution, CallInfo, ChargedResources, Retdata}; -use crate::execution::contract_class::{ContractClassV1, EntryPointV1, TrackedResource}; +use crate::execution::contract_class::{CompiledClassV1, EntryPointV1, TrackedResource}; use crate::execution::entry_point::{ CallEntryPoint, EntryPointExecutionContext, @@ -57,7 +57,7 @@ pub struct CallResult { /// Executes a specific call to a contract entry point and returns its output. pub fn execute_entry_point_call( call: CallEntryPoint, - contract_class: ContractClassV1, + compiled_class: CompiledClassV1, state: &mut dyn State, context: &mut EntryPointExecutionContext, ) -> EntryPointExecutionResult { @@ -74,7 +74,7 @@ pub fn execute_entry_point_call( initial_syscall_ptr, entry_point, program_extra_data_length, - } = initialize_execution_context(call, &contract_class, state, context)?; + } = initialize_execution_context(call, &compiled_class, state, context)?; let args = prepare_call_arguments( &syscall_handler.base.call, @@ -86,7 +86,7 @@ pub fn execute_entry_point_call( let n_total_args = args.len(); // Execute. - let bytecode_length = contract_class.bytecode_length(); + let bytecode_length = compiled_class.bytecode_length(); let program_segment_size = bytecode_length + program_extra_data_length; run_entry_point(&mut runner, &mut syscall_handler, entry_point, args, program_segment_size)?; @@ -142,17 +142,17 @@ fn register_visited_pcs( pub fn initialize_execution_context<'a>( call: CallEntryPoint, - contract_class: &'a ContractClassV1, + compiled_class: &'a CompiledClassV1, state: &'a mut dyn State, context: &'a mut EntryPointExecutionContext, ) -> Result, PreExecutionError> { - let entry_point = contract_class.get_entry_point(&call)?; + let entry_point = compiled_class.get_entry_point(&call)?; // Instantiate Cairo runner. let proof_mode = false; let trace_enabled = true; let mut runner = CairoRunner::new( - &contract_class.0.program, + &compiled_class.0.program, LayoutName::starknet, proof_mode, trace_enabled, @@ -162,7 +162,7 @@ pub fn initialize_execution_context<'a>( let mut read_only_segments = ReadOnlySegments::default(); let program_extra_data_length = prepare_program_extra_data( &mut runner, - contract_class, + compiled_class, &mut read_only_segments, &context.versioned_constants().os_constants.gas_costs, )?; @@ -174,7 +174,7 @@ pub fn initialize_execution_context<'a>( context, initial_syscall_ptr, call, - &contract_class.hints, + &compiled_class.hints, read_only_segments, ); @@ -189,7 +189,7 @@ pub fn initialize_execution_context<'a>( fn prepare_program_extra_data( runner: &mut CairoRunner, - contract_class: &ContractClassV1, + contract_class: &CompiledClassV1, read_only_segments: &mut ReadOnlySegments, gas_costs: &GasCosts, ) -> Result { diff --git a/crates/blockifier/src/execution/execution_utils.rs b/crates/blockifier/src/execution/execution_utils.rs index d2c0b9aeaf..03d3243b91 100644 --- a/crates/blockifier/src/execution/execution_utils.rs +++ b/crates/blockifier/src/execution/execution_utils.rs @@ -22,7 +22,7 @@ use starknet_api::transaction::fields::Calldata; use starknet_types_core::felt::Felt; use crate::execution::call_info::{CallExecution, CallInfo, Retdata}; -use crate::execution::contract_class::{RunnableContractClass, TrackedResource}; +use crate::execution::contract_class::{RunnableCompiledClass, TrackedResource}; use crate::execution::entry_point::{ execute_constructor_entry_point, CallEntryPoint, @@ -52,12 +52,12 @@ pub const SEGMENT_ARENA_BUILTIN_SIZE: usize = 3; /// A wrapper for execute_entry_point_call that performs pre and post-processing. pub fn execute_entry_point_call_wrapper( mut call: CallEntryPoint, - contract_class: RunnableContractClass, + compiled_class: RunnableCompiledClass, state: &mut dyn State, context: &mut EntryPointExecutionContext, remaining_gas: &mut u64, ) -> EntryPointExecutionResult { - let contract_tracked_resource = contract_class.tracked_resource( + let contract_tracked_resource = compiled_class.tracked_resource( &context.versioned_constants().min_compiler_version_for_sierra_gas, context.tx_context.tx_info.gas_mode(), ); @@ -81,7 +81,7 @@ pub fn execute_entry_point_call_wrapper( }; let orig_call = call.clone(); - let res = execute_entry_point_call(call, contract_class, state, context); + let res = execute_entry_point_call(call, compiled_class, state, context); let current_tracked_resource = context.tracked_resource_stack.pop().expect("Unexpected empty tracked resource."); @@ -120,37 +120,37 @@ pub fn execute_entry_point_call_wrapper( /// Executes a specific call to a contract entry point and returns its output. pub fn execute_entry_point_call( call: CallEntryPoint, - contract_class: RunnableContractClass, + compiled_class: RunnableCompiledClass, state: &mut dyn State, context: &mut EntryPointExecutionContext, ) -> EntryPointExecutionResult { - match contract_class { - RunnableContractClass::V0(contract_class) => { + match compiled_class { + RunnableCompiledClass::V0(compiled_class) => { deprecated_entry_point_execution::execute_entry_point_call( call, - contract_class, + compiled_class, state, context, ) } - RunnableContractClass::V1(contract_class) => { - entry_point_execution::execute_entry_point_call(call, contract_class, state, context) + RunnableCompiledClass::V1(compiled_class) => { + entry_point_execution::execute_entry_point_call(call, compiled_class, state, context) } #[cfg(feature = "cairo_native")] - RunnableContractClass::V1Native(contract_class) => { + RunnableCompiledClass::V1Native(compiled_class) => { if context.tracked_resource_stack.last() == Some(&TrackedResource::CairoSteps) { // We cannot run native with cairo steps as the tracked resources (it's a vm // resouorce). entry_point_execution::execute_entry_point_call( call, - contract_class.casm(), + compiled_class.casm(), state, context, ) } else { native_entry_point_execution::execute_entry_point_call( call, - contract_class, + compiled_class, state, context, ) diff --git a/crates/blockifier/src/execution/native/contract_class.rs b/crates/blockifier/src/execution/native/contract_class.rs index 2e85feb4f2..6139e02fca 100644 --- a/crates/blockifier/src/execution/native/contract_class.rs +++ b/crates/blockifier/src/execution/native/contract_class.rs @@ -4,30 +4,30 @@ use std::sync::Arc; use cairo_native::executor::AotContractExecutor; use starknet_api::core::EntryPointSelector; -use crate::execution::contract_class::{ContractClassV1, EntryPointV1}; +use crate::execution::contract_class::{CompiledClassV1, EntryPointV1}; use crate::execution::entry_point::CallEntryPoint; use crate::execution::errors::PreExecutionError; #[derive(Clone, Debug, PartialEq, Eq)] -pub struct NativeContractClassV1(pub Arc); -impl Deref for NativeContractClassV1 { - type Target = NativeContractClassV1Inner; +pub struct NativeCompiledClassV1(pub Arc); +impl Deref for NativeCompiledClassV1 { + type Target = NativeCompiledClassV1Inner; fn deref(&self) -> &Self::Target { &self.0 } } -impl NativeContractClassV1 { +impl NativeCompiledClassV1 { pub(crate) fn constructor_selector(&self) -> Option { self.casm.constructor_selector() } - /// Initialize a compiled contract class for native. + /// Initialize a compiled class for native. /// /// executor must be derived from sierra_program which in turn must be derived from /// sierra_contract_class. - pub fn new(executor: AotContractExecutor, casm: ContractClassV1) -> NativeContractClassV1 { - let contract = NativeContractClassV1Inner::new(executor, casm); + pub fn new(executor: AotContractExecutor, casm: CompiledClassV1) -> NativeCompiledClassV1 { + let contract = NativeCompiledClassV1Inner::new(executor, casm); Self(Arc::new(contract)) } @@ -39,29 +39,29 @@ impl NativeContractClassV1 { self.casm.get_entry_point(call) } - pub fn casm(&self) -> ContractClassV1 { + pub fn casm(&self) -> CompiledClassV1 { self.casm.clone() } } #[derive(Debug)] -pub struct NativeContractClassV1Inner { +pub struct NativeCompiledClassV1Inner { pub executor: AotContractExecutor, - casm: ContractClassV1, + casm: CompiledClassV1, } -impl NativeContractClassV1Inner { - fn new(executor: AotContractExecutor, casm: ContractClassV1) -> Self { - NativeContractClassV1Inner { executor, casm } +impl NativeCompiledClassV1Inner { + fn new(executor: AotContractExecutor, casm: CompiledClassV1) -> Self { + NativeCompiledClassV1Inner { executor, casm } } } -// The location where the compiled contract is loaded into memory will not +// The location where the compiled class is loaded into memory will not // be the same therefore we exclude it from the comparison. -impl PartialEq for NativeContractClassV1Inner { +impl PartialEq for NativeCompiledClassV1Inner { fn eq(&self, other: &Self) -> bool { self.casm == other.casm } } -impl Eq for NativeContractClassV1Inner {} +impl Eq for NativeCompiledClassV1Inner {} diff --git a/crates/blockifier/src/execution/native/entry_point_execution.rs b/crates/blockifier/src/execution/native/entry_point_execution.rs index 34b3460c67..719bbc775e 100644 --- a/crates/blockifier/src/execution/native/entry_point_execution.rs +++ b/crates/blockifier/src/execution/native/entry_point_execution.rs @@ -11,18 +11,18 @@ use crate::execution::entry_point::{ EntryPointExecutionResult, }; use crate::execution::errors::{EntryPointExecutionError, PostExecutionError}; -use crate::execution::native::contract_class::NativeContractClassV1; +use crate::execution::native::contract_class::NativeCompiledClassV1; use crate::execution::native::syscall_handler::NativeSyscallHandler; use crate::state::state_api::State; // todo(rodrigo): add an `entry point not found` test for Native pub fn execute_entry_point_call( call: CallEntryPoint, - contract_class: NativeContractClassV1, + compiled_class: NativeCompiledClassV1, state: &mut dyn State, context: &mut EntryPointExecutionContext, ) -> EntryPointExecutionResult { - let entry_point = contract_class.get_entry_point(&call)?; + let entry_point = compiled_class.get_entry_point(&call)?; let mut syscall_handler: NativeSyscallHandler<'_> = NativeSyscallHandler::new(call, state, context); @@ -39,7 +39,7 @@ pub fn execute_entry_point_call( mul_mod: gas_costs.mul_mod_gas_cost, }; - let execution_result = contract_class.executor.run( + let execution_result = compiled_class.executor.run( entry_point.selector.0, &syscall_handler.base.call.calldata.0.clone(), syscall_handler.base.call.initial_gas, diff --git a/crates/blockifier/src/execution/syscalls/syscall_base.rs b/crates/blockifier/src/execution/syscalls/syscall_base.rs index ade9cb398c..7a4b02fc38 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_base.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_base.rs @@ -156,9 +156,9 @@ impl<'state> SyscallHandlerBase<'state> { pub fn replace_class(&mut self, class_hash: ClassHash) -> SyscallResult<()> { // Ensure the class is declared (by reading it), and of type V1. - let class = self.state.get_compiled_contract_class(class_hash)?; + let compiled_class = self.state.get_compiled_class(class_hash)?; - if !is_cairo1(&class) { + if !is_cairo1(&compiled_class) { return Err(SyscallExecutionError::ForbiddenClassReplacement { class_hash }); } self.state.set_class_hash_at(self.call.storage_address, class_hash)?; diff --git a/crates/blockifier/src/state/cached_state.rs b/crates/blockifier/src/state/cached_state.rs index dbb84243e7..059387c51b 100644 --- a/crates/blockifier/src/state/cached_state.rs +++ b/crates/blockifier/src/state/cached_state.rs @@ -8,7 +8,7 @@ use starknet_api::state::StorageKey; use starknet_types_core::felt::Felt; use crate::context::TransactionContext; -use crate::execution::contract_class::RunnableContractClass; +use crate::execution::contract_class::RunnableCompiledClass; use crate::state::errors::StateError; use crate::state::state_api::{State, StateReader, StateResult, UpdatableState}; use crate::transaction::objects::TransactionExecutionInfo; @@ -18,7 +18,7 @@ use crate::utils::{strict_subtract_mappings, subtract_mappings}; #[path = "cached_state_test.rs"] mod test; -pub type ContractClassMapping = HashMap; +pub type ContractClassMapping = HashMap; /// Caches read and write requests. /// @@ -85,8 +85,7 @@ impl CachedState { /// * Nonce: read previous before incrementing. /// * Class hash: Deploy: verify the address is not occupied; Replace class: verify the /// contract is deployed before running any code. - /// * Compiled class hash: verify the class is not declared through - /// `get_compiled_contract_class`. + /// * Compiled class hash: verify the class is not declared through `get_compiled_class`. /// /// TODO(Noa, 30/07/23): Consider adding DB getters in bulk (via a DB read transaction). fn update_initial_values_of_write_only_access(&mut self) -> StateResult<()> { @@ -174,17 +173,14 @@ impl StateReader for CachedState { Ok(*class_hash) } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { let mut cache = self.cache.borrow_mut(); let class_hash_to_class = &mut *self.class_hash_to_class.borrow_mut(); if let std::collections::hash_map::Entry::Vacant(vacant_entry) = class_hash_to_class.entry(class_hash) { - match self.state.get_compiled_contract_class(class_hash) { + match self.state.get_compiled_class(class_hash) { Err(StateError::UndeclaredClassHash(class_hash)) => { cache.set_declared_contract_initial_value(class_hash, false); cache.set_compiled_class_hash_initial_value( @@ -260,7 +256,7 @@ impl State for CachedState { fn set_contract_class( &mut self, class_hash: ClassHash, - contract_class: RunnableContractClass, + contract_class: RunnableCompiledClass, ) -> StateResult<()> { self.class_hash_to_class.get_mut().insert(class_hash, contract_class); let mut cache = self.cache.borrow_mut(); @@ -528,11 +524,8 @@ impl<'a, S: StateReader + ?Sized> StateReader for MutRefState<'a, S> { self.0.get_class_hash_at(contract_address) } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { - self.0.get_compiled_contract_class(class_hash) + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { + self.0.get_compiled_class(class_hash) } fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult { diff --git a/crates/blockifier/src/state/cached_state_test.rs b/crates/blockifier/src/state/cached_state_test.rs index bcc91ab2f5..20f191a99c 100644 --- a/crates/blockifier/src/state/cached_state_test.rs +++ b/crates/blockifier/src/state/cached_state_test.rs @@ -115,7 +115,7 @@ fn declare_contract() { // Reading an undeclared contract class. assert_matches!( - state.get_compiled_contract_class(class_hash).unwrap_err(), + state.get_compiled_class(class_hash).unwrap_err(), StateError::UndeclaredClassHash(undeclared_class_hash) if undeclared_class_hash == class_hash ); @@ -166,14 +166,14 @@ fn get_contract_class() { let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); let state = test_state(&ChainInfo::create_for_testing(), Fee(0), &[(test_contract, 0)]); assert_eq!( - state.get_compiled_contract_class(test_contract.get_class_hash()).unwrap(), + state.get_compiled_class(test_contract.get_class_hash()).unwrap(), test_contract.get_runnable_class() ); // Negative flow. let missing_class_hash = class_hash!("0x101"); assert_matches!( - state.get_compiled_contract_class(missing_class_hash).unwrap_err(), + state.get_compiled_class(missing_class_hash).unwrap_err(), StateError::UndeclaredClassHash(undeclared) if undeclared == missing_class_hash ); } @@ -261,7 +261,7 @@ fn cached_state_state_diff_conversion() { let class_hash = FeatureContract::Empty(CairoVersion::Cairo0).get_class_hash(); let compiled_class_hash = compiled_class_hash!(1_u8); // Cache the initial read value, as in regular declare flow. - state.get_compiled_contract_class(class_hash).unwrap_err(); + state.get_compiled_class(class_hash).unwrap_err(); state.set_compiled_class_hash(class_hash, compiled_class_hash).unwrap(); // Write the initial value using key contract_address1. @@ -309,7 +309,7 @@ fn create_state_changes_for_test( state.increment_nonce(contract_address2).unwrap(); // Fill the initial read value, as in regular flow. - state.get_compiled_contract_class(class_hash).unwrap_err(); + state.get_compiled_class(class_hash).unwrap_err(); state.set_compiled_class_hash(class_hash, compiled_class_hash).unwrap(); // Assign the existing value to the storage (this shouldn't be considered a change). @@ -500,7 +500,7 @@ fn test_contract_cache_is_used() { assert!(state.class_hash_to_class.borrow().get(&class_hash).is_none()); // Check state uses the cache. - assert_eq!(state.get_compiled_contract_class(class_hash).unwrap(), contract_class); + assert_eq!(state.get_compiled_class(class_hash).unwrap(), contract_class); assert_eq!(state.class_hash_to_class.borrow().get(&class_hash).unwrap(), &contract_class); } diff --git a/crates/blockifier/src/state/global_cache.rs b/crates/blockifier/src/state/global_cache.rs index 040b116337..f26d4ab39d 100644 --- a/crates/blockifier/src/state/global_cache.rs +++ b/crates/blockifier/src/state/global_cache.rs @@ -8,7 +8,7 @@ use starknet_api::core::ClassHash; use starknet_api::state::SierraContractClass; #[cfg(feature = "cairo_native")] -use crate::execution::contract_class::RunnableContractClass; +use crate::execution::contract_class::RunnableCompiledClass; type ContractClassLRUCache = SizedCache; pub type LockedContractClassCache<'a, T> = MutexGuard<'a, ContractClassLRUCache>; @@ -53,18 +53,18 @@ impl GlobalContractCache { #[cfg(feature = "cairo_native")] pub struct GlobalContractCacheManager { - pub casm_cache: GlobalContractCache, + pub casm_cache: GlobalContractCache, pub native_cache: GlobalContractCache, pub sierra_cache: GlobalContractCache>, } #[cfg(feature = "cairo_native")] impl GlobalContractCacheManager { - pub fn get_casm(&self, class_hash: &ClassHash) -> Option { + pub fn get_casm(&self, class_hash: &ClassHash) -> Option { self.casm_cache.get(class_hash) } - pub fn set_casm(&self, class_hash: ClassHash, contract_class: RunnableContractClass) { + pub fn set_casm(&self, class_hash: ClassHash, contract_class: RunnableCompiledClass) { self.casm_cache.set(class_hash, contract_class); } diff --git a/crates/blockifier/src/state/state_api.rs b/crates/blockifier/src/state/state_api.rs index 2b4464d6ab..96e24c1e1a 100644 --- a/crates/blockifier/src/state/state_api.rs +++ b/crates/blockifier/src/state/state_api.rs @@ -6,7 +6,7 @@ use starknet_api::state::StorageKey; use starknet_types_core::felt::Felt; use super::cached_state::{ContractClassMapping, StateMaps}; -use crate::execution::contract_class::RunnableContractClass; +use crate::execution::contract_class::RunnableCompiledClass; use crate::state::errors::StateError; pub type StateResult = Result; @@ -39,11 +39,8 @@ pub trait StateReader { /// Default: 0 (uninitialized class hash) for an uninitialized contract address. fn get_class_hash_at(&self, contract_address: ContractAddress) -> StateResult; - /// Returns the contract class of the given class hash. - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult; + /// Returns the compiled class of the given class hash. + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult; /// Returns the compiled class hash of the given class hash. fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult; @@ -96,7 +93,7 @@ pub trait State: StateReader { fn set_contract_class( &mut self, class_hash: ClassHash, - contract_class: RunnableContractClass, + contract_class: RunnableCompiledClass, ) -> StateResult<()>; /// Sets the given compiled class hash under the given class hash. diff --git a/crates/blockifier/src/test_utils/contracts.rs b/crates/blockifier/src/test_utils/contracts.rs index 7a4bb8fa93..c3d4ea4ce2 100644 --- a/crates/blockifier/src/test_utils/contracts.rs +++ b/crates/blockifier/src/test_utils/contracts.rs @@ -12,10 +12,10 @@ use starknet_types_core::felt::Felt; use strum::IntoEnumIterator; use strum_macros::EnumIter; -use crate::execution::contract_class::RunnableContractClass; +use crate::execution::contract_class::RunnableCompiledClass; use crate::execution::entry_point::CallEntryPoint; #[cfg(feature = "cairo_native")] -use crate::execution::native::contract_class::NativeContractClassV1; +use crate::execution::native::contract_class::NativeCompiledClassV1; #[cfg(feature = "cairo_native")] use crate::test_utils::cairo_compile::starknet_compile; use crate::test_utils::cairo_compile::{cairo0_compile, cairo1_compile}; @@ -185,12 +185,12 @@ impl FeatureContract { } } - pub fn get_runnable_class(&self) -> RunnableContractClass { + pub fn get_runnable_class(&self) -> RunnableCompiledClass { #[cfg(feature = "cairo_native")] if CairoVersion::Native == self.cairo_version() { let native_contract_class = - NativeContractClassV1::compile_or_get_cached(&self.get_compiled_path()); - return RunnableContractClass::V1Native(native_contract_class); + NativeCompiledClassV1::compile_or_get_cached(&self.get_compiled_path()); + return RunnableCompiledClass::V1Native(native_contract_class); } self.get_class().try_into().unwrap() @@ -365,7 +365,7 @@ impl FeatureContract { entry_point_type: EntryPointType, ) -> EntryPointOffset { match self.get_runnable_class() { - RunnableContractClass::V0(class) => { + RunnableCompiledClass::V0(class) => { class .entry_points_by_type .get(&entry_point_type) @@ -375,7 +375,7 @@ impl FeatureContract { .unwrap() .offset } - RunnableContractClass::V1(class) => { + RunnableCompiledClass::V1(class) => { class .entry_points_by_type .get_entry_point(&CallEntryPoint { @@ -387,7 +387,7 @@ impl FeatureContract { .offset } #[cfg(feature = "cairo_native")] - RunnableContractClass::V1Native(_) => { + RunnableCompiledClass::V1Native(_) => { panic!("Not implemented for cairo native contracts") } } diff --git a/crates/blockifier/src/test_utils/dict_state_reader.rs b/crates/blockifier/src/test_utils/dict_state_reader.rs index 469e6cbdb7..16e3b3ed83 100644 --- a/crates/blockifier/src/test_utils/dict_state_reader.rs +++ b/crates/blockifier/src/test_utils/dict_state_reader.rs @@ -4,7 +4,7 @@ use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; use starknet_types_core::felt::Felt; -use crate::execution::contract_class::RunnableContractClass; +use crate::execution::contract_class::RunnableCompiledClass; use crate::state::cached_state::StorageEntry; use crate::state::errors::StateError; use crate::state::state_api::{StateReader, StateResult}; @@ -15,7 +15,7 @@ pub struct DictStateReader { pub storage_view: HashMap, pub address_to_nonce: HashMap, pub address_to_class_hash: HashMap, - pub class_hash_to_class: HashMap, + pub class_hash_to_class: HashMap, pub class_hash_to_compiled_class_hash: HashMap, } @@ -35,10 +35,7 @@ impl StateReader for DictStateReader { Ok(nonce) } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { let contract_class = self.class_hash_to_class.get(&class_hash).cloned(); match contract_class { Some(contract_class) => Ok(contract_class), diff --git a/crates/blockifier/src/test_utils/struct_impls.rs b/crates/blockifier/src/test_utils/struct_impls.rs index 581263a05c..dee7020eac 100644 --- a/crates/blockifier/src/test_utils/struct_impls.rs +++ b/crates/blockifier/src/test_utils/struct_impls.rs @@ -27,14 +27,14 @@ use crate::context::{BlockContext, ChainInfo, FeeTokenAddresses, TransactionCont use crate::execution::call_info::{CallExecution, CallInfo, Retdata}; use crate::execution::common_hints::ExecutionMode; #[cfg(feature = "cairo_native")] -use crate::execution::contract_class::ContractClassV1; +use crate::execution::contract_class::CompiledClassV1; use crate::execution::entry_point::{ CallEntryPoint, EntryPointExecutionContext, EntryPointExecutionResult, }; #[cfg(feature = "cairo_native")] -use crate::execution::native::contract_class::NativeContractClassV1; +use crate::execution::native::contract_class::NativeCompiledClassV1; use crate::state::state_api::State; use crate::test_utils::{ get_raw_contract_class, @@ -242,12 +242,12 @@ impl BouncerWeights { } #[cfg(feature = "cairo_native")] -static COMPILED_NATIVE_CONTRACT_CACHE: LazyLock>> = +static COMPILED_NATIVE_CONTRACT_CACHE: LazyLock>> = LazyLock::new(|| RwLock::new(HashMap::new())); #[cfg(feature = "cairo_native")] -impl NativeContractClassV1 { - /// Convenience function to construct a NativeContractClassV1 from a raw contract class. +impl NativeCompiledClassV1 { + /// Convenience function to construct a NativeCompiledClassV1 from a raw contract class. /// If control over the compilation is desired use [Self::new] instead. pub fn try_from_json_string(raw_sierra_contract_class: &str) -> Self { let sierra_contract_class: SierraContractClass = @@ -268,10 +268,10 @@ impl NativeContractClassV1 { let casm_contract_class = CasmContractClass::from_contract_class(sierra_contract_class, false, usize::MAX) .expect("Cannot compile sierra contract class into casm contract class"); - let casm = ContractClassV1::try_from(casm_contract_class) - .expect("Cannot get ContractClassV1 from CasmContractClass"); + let casm = CompiledClassV1::try_from(casm_contract_class) + .expect("Cannot get CompiledClassV1 from CasmContractClass"); - NativeContractClassV1::new(executor, casm) + NativeCompiledClassV1::new(executor, casm) } pub fn from_file(contract_path: &str) -> Self { @@ -287,7 +287,7 @@ impl NativeContractClassV1 { } std::mem::drop(cache); - let class = NativeContractClassV1::from_file(path); + let class = NativeCompiledClassV1::from_file(path); let mut cache = COMPILED_NATIVE_CONTRACT_CACHE.write().unwrap(); cache.insert(path.to_string(), class.clone()); class diff --git a/crates/blockifier/src/transaction/account_transaction.rs b/crates/blockifier/src/transaction/account_transaction.rs index a4b245dd0d..4c2c4a8731 100644 --- a/crates/blockifier/src/transaction/account_transaction.rs +++ b/crates/blockifier/src/transaction/account_transaction.rs @@ -28,7 +28,7 @@ use starknet_types_core::felt::Felt; use crate::context::{BlockContext, TransactionContext}; use crate::execution::call_info::CallInfo; -use crate::execution::contract_class::RunnableContractClass; +use crate::execution::contract_class::RunnableCompiledClass; use crate::execution::entry_point::{CallEntryPoint, CallType, EntryPointExecutionContext}; use crate::execution::stack_trace::{ extract_trailing_cairo1_revert_trace, @@ -885,8 +885,8 @@ impl ValidatableTransaction for AccountTransaction { })?; // Validate return data. - let contract_class = state.get_compiled_contract_class(class_hash)?; - if is_cairo1(&contract_class) { + let compiled_class = state.get_compiled_class(class_hash)?; + if is_cairo1(&compiled_class) { // The account contract class is a Cairo 1.0 contract; the `validate` entry point should // return `VALID`. let expected_retdata = retdata![*constants::VALIDATE_RETDATA]; @@ -910,11 +910,11 @@ impl ValidatableTransaction for AccountTransaction { } } -pub fn is_cairo1(contract_class: &RunnableContractClass) -> bool { - match contract_class { - RunnableContractClass::V0(_) => false, - RunnableContractClass::V1(_) => true, +pub fn is_cairo1(compiled_class: &RunnableCompiledClass) -> bool { + match compiled_class { + RunnableCompiledClass::V0(_) => false, + RunnableCompiledClass::V1(_) => true, #[cfg(feature = "cairo_native")] - RunnableContractClass::V1Native(_) => true, + RunnableCompiledClass::V1Native(_) => true, } } diff --git a/crates/blockifier/src/transaction/transactions.rs b/crates/blockifier/src/transaction/transactions.rs index d570ebe6c4..9005f73e4d 100644 --- a/crates/blockifier/src/transaction/transactions.rs +++ b/crates/blockifier/src/transaction/transactions.rs @@ -401,7 +401,7 @@ fn try_declare( class_hash: ClassHash, compiled_class_hash: Option, ) -> TransactionExecutionResult<()> { - match state.get_compiled_contract_class(class_hash) { + match state.get_compiled_class(class_hash) { Err(StateError::UndeclaredClassHash(_)) => { // Class is undeclared; declare it. state.set_contract_class(class_hash, tx.contract_class().try_into()?)?; diff --git a/crates/blockifier/src/transaction/transactions_test.rs b/crates/blockifier/src/transaction/transactions_test.rs index 2a6d85ad98..648725249f 100644 --- a/crates/blockifier/src/transaction/transactions_test.rs +++ b/crates/blockifier/src/transaction/transactions_test.rs @@ -1524,7 +1524,7 @@ fn test_declare_tx( // Check state before transaction application. assert_matches!( - state.get_compiled_contract_class(class_hash).unwrap_err(), + state.get_compiled_class(class_hash).unwrap_err(), StateError::UndeclaredClassHash(undeclared_class_hash) if undeclared_class_hash == class_hash ); @@ -1626,7 +1626,7 @@ fn test_declare_tx( ); // Verify class declaration. - let contract_class_from_state = state.get_compiled_contract_class(class_hash).unwrap(); + let contract_class_from_state = state.get_compiled_class(class_hash).unwrap(); assert_eq!(contract_class_from_state, class_info.contract_class().try_into().unwrap()); // Checks that redeclaring the same contract fails. diff --git a/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs b/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs index 5362a6ef63..7ebb38ac31 100644 --- a/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs +++ b/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs @@ -9,7 +9,7 @@ use blockifier::blockifier::config::TransactionExecutorConfig; use blockifier::blockifier::transaction_executor::TransactionExecutor; use blockifier::bouncer::BouncerConfig; use blockifier::context::BlockContext; -use blockifier::execution::contract_class::RunnableContractClass; +use blockifier::execution::contract_class::RunnableCompiledClass; use blockifier::state::cached_state::{CommitmentStateDiff, StateMaps}; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader, StateResult}; @@ -217,10 +217,7 @@ impl StateReader for TestStateReader { /// Returns the contract class of the given class hash. /// Compile the contract class if it is Sierra. - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { let contract_class = retry_request!(self.retry_config, || self.get_contract_class(&class_hash))?; @@ -591,10 +588,7 @@ impl StateReader for OfflineStateReader { )?) } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { match self.get_contract_class(&class_hash)? { StarknetContractClass::Sierra(sierra) => { Ok(sierra_to_contact_class_v1(sierra).unwrap().try_into().unwrap()) diff --git a/crates/native_blockifier/src/py_block_executor.rs b/crates/native_blockifier/src/py_block_executor.rs index 17f8604bb1..0cefe8026d 100644 --- a/crates/native_blockifier/src/py_block_executor.rs +++ b/crates/native_blockifier/src/py_block_executor.rs @@ -6,7 +6,7 @@ use blockifier::blockifier::transaction_executor::{TransactionExecutor, Transact use blockifier::bouncer::BouncerConfig; use blockifier::context::{BlockContext, ChainInfo, FeeTokenAddresses}; use blockifier::execution::call_info::CallInfo; -use blockifier::execution::contract_class::RunnableContractClass; +use blockifier::execution::contract_class::RunnableCompiledClass; use blockifier::fee::receipt::TransactionReceipt; use blockifier::state::global_cache::GlobalContractCache; use blockifier::transaction::objects::{ExecutionResourcesTraits, TransactionExecutionInfo}; @@ -130,7 +130,7 @@ pub struct PyBlockExecutor { pub tx_executor: Option>, /// `Send` trait is required for `pyclass` compatibility as Python objects must be threadsafe. pub storage: Box, - pub global_contract_cache: GlobalContractCache, + pub global_contract_cache: GlobalContractCache, } #[pymethods] diff --git a/crates/native_blockifier/src/py_block_executor_test.rs b/crates/native_blockifier/src/py_block_executor_test.rs index 47a39d3409..2a87bec4fc 100644 --- a/crates/native_blockifier/src/py_block_executor_test.rs +++ b/crates/native_blockifier/src/py_block_executor_test.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use blockifier::blockifier::transaction_executor::BLOCK_STATE_ACCESS_ERR; -use blockifier::execution::contract_class::{ContractClassV1, RunnableContractClass}; +use blockifier::execution::contract_class::{CompiledClassV1, RunnableCompiledClass}; use blockifier::state::state_api::StateReader; use cached::Cached; use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; @@ -33,7 +33,7 @@ fn global_contract_cache_update() { }; let sierra = SierraContractClass::default(); let contract_class = - RunnableContractClass::V1(ContractClassV1::try_from(casm.clone()).unwrap()); + RunnableCompiledClass::V1(CompiledClassV1::try_from(casm.clone()).unwrap()); let class_hash = class_hash!("0x1"); let temp_storage_path = tempfile::tempdir().unwrap().into_path(); @@ -75,7 +75,7 @@ fn global_contract_cache_update() { .block_state .as_ref() .expect(BLOCK_STATE_ACCESS_ERR) - .get_compiled_contract_class(class_hash) + .get_compiled_class(class_hash) .unwrap(); assert_eq!(queried_contract_class, contract_class); diff --git a/crates/native_blockifier/src/py_test_utils.rs b/crates/native_blockifier/src/py_test_utils.rs index 6cae66fa3f..2ba5ac4d48 100644 --- a/crates/native_blockifier/src/py_test_utils.rs +++ b/crates/native_blockifier/src/py_test_utils.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use blockifier::execution::contract_class::ContractClassV0; +use blockifier::execution::contract_class::CompiledClassV0; use blockifier::state::cached_state::CachedState; use blockifier::test_utils::dict_state_reader::DictStateReader; use blockifier::test_utils::struct_impls::LoadContractFromFile; @@ -14,7 +14,7 @@ pub const TOKEN_FOR_TESTING_CONTRACT_PATH: &str = starknet/core/test_contract/token_for_testing.json"; pub fn create_py_test_state() -> CachedState { - let contract_class: ContractClassV0 = + let contract_class: CompiledClassV0 = ContractClass::from_file(TOKEN_FOR_TESTING_CONTRACT_PATH).try_into().unwrap(); let class_hash_to_class = HashMap::from([(class_hash!(TOKEN_FOR_TESTING_CLASS_HASH), contract_class.into())]); diff --git a/crates/native_blockifier/src/state_readers/py_state_reader.rs b/crates/native_blockifier/src/state_readers/py_state_reader.rs index f379dcb05b..35cdde1d91 100644 --- a/crates/native_blockifier/src/state_readers/py_state_reader.rs +++ b/crates/native_blockifier/src/state_readers/py_state_reader.rs @@ -1,7 +1,7 @@ use blockifier::execution::contract_class::{ - ContractClassV0, - ContractClassV1, - RunnableContractClass, + CompiledClassV0, + CompiledClassV1, + RunnableCompiledClass, }; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader, StateResult}; @@ -68,11 +68,8 @@ impl StateReader for PyStateReader { .map_err(|err| StateError::StateReadError(err.to_string())) } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { - Python::with_gil(|py| -> Result { + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { + Python::with_gil(|py| -> Result { let args = (PyFelt::from(class_hash),); let py_raw_compiled_class: PyRawCompiledClass = self .state_reader_proxy @@ -80,7 +77,7 @@ impl StateReader for PyStateReader { .call_method1("get_raw_compiled_class", args)? .extract()?; - Ok(RunnableContractClass::try_from(py_raw_compiled_class)?) + Ok(RunnableCompiledClass::try_from(py_raw_compiled_class)?) }) .map_err(|err| { if Python::with_gil(|py| err.is_instance_of::(py)) { @@ -110,14 +107,14 @@ pub struct PyRawCompiledClass { pub version: usize, } -impl TryFrom for RunnableContractClass { +impl TryFrom for RunnableCompiledClass { type Error = NativeBlockifierError; fn try_from(raw_compiled_class: PyRawCompiledClass) -> NativeBlockifierResult { match raw_compiled_class.version { - 0 => Ok(ContractClassV0::try_from_json_string(&raw_compiled_class.raw_compiled_class)? + 0 => Ok(CompiledClassV0::try_from_json_string(&raw_compiled_class.raw_compiled_class)? .into()), - 1 => Ok(ContractClassV1::try_from_json_string(&raw_compiled_class.raw_compiled_class)? + 1 => Ok(CompiledClassV1::try_from_json_string(&raw_compiled_class.raw_compiled_class)? .into()), _ => Err(NativeBlockifierInputError::UnsupportedContractClassVersion { version: raw_compiled_class.version, diff --git a/crates/papyrus_execution/src/execution_utils.rs b/crates/papyrus_execution/src/execution_utils.rs index 45e45d16b8..9a6f34ffb7 100644 --- a/crates/papyrus_execution/src/execution_utils.rs +++ b/crates/papyrus_execution/src/execution_utils.rs @@ -3,9 +3,9 @@ use std::fs::File; use std::path::PathBuf; use blockifier::execution::contract_class::{ - ContractClassV0, - ContractClassV1, - RunnableContractClass, + CompiledClassV0, + CompiledClassV1, + RunnableCompiledClass, }; use blockifier::state::cached_state::{CachedState, CommitmentStateDiff, MutRefState}; use blockifier::state::state_api::StateReader; @@ -59,15 +59,15 @@ pub(crate) fn get_contract_class( txn: &StorageTxn<'_, RO>, class_hash: &ClassHash, state_number: StateNumber, -) -> Result, ExecutionUtilsError> { +) -> Result, ExecutionUtilsError> { match txn.get_state_reader()?.get_class_definition_block_number(class_hash)? { Some(block_number) if state_number.is_before(block_number) => return Ok(None), Some(_block_number) => { let Some(casm) = txn.get_casm(class_hash)? else { return Err(ExecutionUtilsError::CasmTableNotSynced); }; - return Ok(Some(RunnableContractClass::V1( - ContractClassV1::try_from(casm).map_err(ExecutionUtilsError::ProgramError)?, + return Ok(Some(RunnableCompiledClass::V1( + CompiledClassV1::try_from(casm).map_err(ExecutionUtilsError::ProgramError)?, ))); } None => {} @@ -78,8 +78,8 @@ pub(crate) fn get_contract_class( else { return Ok(None); }; - Ok(Some(RunnableContractClass::V0( - ContractClassV0::try_from(deprecated_class).map_err(ExecutionUtilsError::ProgramError)?, + Ok(Some(RunnableCompiledClass::V0( + CompiledClassV0::try_from(deprecated_class).map_err(ExecutionUtilsError::ProgramError)?, ))) } diff --git a/crates/papyrus_execution/src/state_reader.rs b/crates/papyrus_execution/src/state_reader.rs index a963241f61..b67aaa170e 100644 --- a/crates/papyrus_execution/src/state_reader.rs +++ b/crates/papyrus_execution/src/state_reader.rs @@ -5,9 +5,9 @@ mod state_reader_test; use std::cell::Cell; use blockifier::execution::contract_class::{ - ContractClassV0, - ContractClassV1, - RunnableContractClass, + CompiledClassV0, + CompiledClassV1, + RunnableCompiledClass, }; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader as BlockifierStateReader, StateResult}; @@ -75,17 +75,14 @@ impl BlockifierStateReader for ExecutionStateReader { .unwrap_or_default()) } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { if let Some(pending_casm) = self .maybe_pending_data .as_ref() .and_then(|pending_data| pending_data.classes.get_compiled_class(class_hash)) { - return Ok(RunnableContractClass::V1( - ContractClassV1::try_from(pending_casm).map_err(StateError::ProgramError)?, + return Ok(RunnableCompiledClass::V1( + CompiledClassV1::try_from(pending_casm).map_err(StateError::ProgramError)?, )); } if let Some(ApiContractClass::DeprecatedContractClass(pending_deprecated_class)) = self @@ -93,8 +90,8 @@ impl BlockifierStateReader for ExecutionStateReader { .as_ref() .and_then(|pending_data| pending_data.classes.get_class(class_hash)) { - return Ok(RunnableContractClass::V0( - ContractClassV0::try_from(pending_deprecated_class) + return Ok(RunnableCompiledClass::V0( + CompiledClassV0::try_from(pending_deprecated_class) .map_err(StateError::ProgramError)?, )); } diff --git a/crates/papyrus_execution/src/state_reader_test.rs b/crates/papyrus_execution/src/state_reader_test.rs index ac16c98afa..8e6a3c9558 100644 --- a/crates/papyrus_execution/src/state_reader_test.rs +++ b/crates/papyrus_execution/src/state_reader_test.rs @@ -2,9 +2,9 @@ use std::cell::Cell; use assert_matches::assert_matches; use blockifier::execution::contract_class::{ - ContractClassV0, - ContractClassV1, - RunnableContractClass, + CompiledClassV0, + CompiledClassV1, + RunnableCompiledClass, }; use blockifier::state::errors::StateError; use blockifier::state::state_api::StateReader; @@ -50,7 +50,7 @@ fn read_state() { let class0 = SierraContractClass::default(); let casm0 = get_test_casm(); let blockifier_casm0 = - RunnableContractClass::V1(ContractClassV1::try_from(casm0.clone()).unwrap()); + RunnableCompiledClass::V1(CompiledClassV1::try_from(casm0.clone()).unwrap()); let compiled_class_hash0 = CompiledClassHash(StarkHash::default()); let class_hash1 = ClassHash(1u128.into()); @@ -65,7 +65,7 @@ fn read_state() { let mut casm1 = get_test_casm(); casm1.bytecode[0] = BigUintAsHex { value: 12345u32.into() }; let blockifier_casm1 = - RunnableContractClass::V1(ContractClassV1::try_from(casm1.clone()).unwrap()); + RunnableCompiledClass::V1(CompiledClassV1::try_from(casm1.clone()).unwrap()); let nonce1 = Nonce(felt!(2_u128)); let class_hash3 = ClassHash(567_u128.into()); let class_hash4 = ClassHash(89_u128.into()); @@ -163,8 +163,7 @@ fn read_state() { assert_eq!(nonce_after_block_0, Nonce::default()); let class_hash_after_block_0 = state_reader0.get_class_hash_at(address0).unwrap(); assert_eq!(class_hash_after_block_0, ClassHash::default()); - let compiled_contract_class_after_block_0 = - state_reader0.get_compiled_contract_class(class_hash0); + let compiled_contract_class_after_block_0 = state_reader0.get_compiled_class(class_hash0); assert_matches!( compiled_contract_class_after_block_0, Err(StateError::UndeclaredClassHash(class_hash)) if class_hash == class_hash0 @@ -185,12 +184,12 @@ fn read_state() { let class_hash_after_block_1 = state_reader1.get_class_hash_at(address0).unwrap(); assert_eq!(class_hash_after_block_1, class_hash0); let compiled_contract_class_after_block_1 = - state_reader1.get_compiled_contract_class(class_hash0).unwrap(); + state_reader1.get_compiled_class(class_hash0).unwrap(); assert_eq!(compiled_contract_class_after_block_1, blockifier_casm0); - // Test that if we try to get a casm and it's missing, that an error is returned and the field - // `missing_compiled_class` is set to its hash - state_reader1.get_compiled_contract_class(class_hash5).unwrap_err(); + // Test that an error is returned if we try to get a missing casm, and the field + // `missing_compiled_class` is set to the missing casm's hash. + state_reader1.get_compiled_class(class_hash5).unwrap_err(); assert_eq!(state_reader1.missing_compiled_class.get().unwrap(), class_hash5); let state_number2 = StateNumber::unchecked_right_after_block(BlockNumber(2)); @@ -234,14 +233,14 @@ fn read_state() { assert_eq!(state_reader2.get_compiled_class_hash(class_hash2).unwrap(), compiled_class_hash2); assert_eq!(state_reader2.get_nonce_at(address0).unwrap(), nonce0); assert_eq!(state_reader2.get_nonce_at(address2).unwrap(), nonce1); - assert_eq!(state_reader2.get_compiled_contract_class(class_hash0).unwrap(), blockifier_casm0); - assert_eq!(state_reader2.get_compiled_contract_class(class_hash2).unwrap(), blockifier_casm1); - // Test that if we only got the class without the casm then an error is returned. - state_reader2.get_compiled_contract_class(class_hash3).unwrap_err(); + assert_eq!(state_reader2.get_compiled_class(class_hash0).unwrap(), blockifier_casm0); + assert_eq!(state_reader2.get_compiled_class(class_hash2).unwrap(), blockifier_casm1); + // Test that an error is returned if we only got the class without the casm. + state_reader2.get_compiled_class(class_hash3).unwrap_err(); // Test that if the class is deprecated it is returned. assert_eq!( - state_reader2.get_compiled_contract_class(class_hash4).unwrap(), - RunnableContractClass::V0(ContractClassV0::try_from(class1).unwrap()) + state_reader2.get_compiled_class(class_hash4).unwrap(), + RunnableCompiledClass::V0(CompiledClassV0::try_from(class1).unwrap()) ); // Test get_class_hash_at when the class is replaced. diff --git a/crates/papyrus_rpc/src/v0_8/api/api_impl.rs b/crates/papyrus_rpc/src/v0_8/api/api_impl.rs index b05437de3d..ad9094da1a 100644 --- a/crates/papyrus_rpc/src/v0_8/api/api_impl.rs +++ b/crates/papyrus_rpc/src/v0_8/api/api_impl.rs @@ -1445,7 +1445,7 @@ impl JsonRpcServer for JsonRpcServerImpl { } #[instrument(skip(self), level = "debug", err)] - fn get_compiled_contract_class( + fn get_compiled_class( &self, block_id: BlockId, class_hash: ClassHash, diff --git a/crates/papyrus_rpc/src/v0_8/api/mod.rs b/crates/papyrus_rpc/src/v0_8/api/mod.rs index 0c272fc379..1437933c93 100644 --- a/crates/papyrus_rpc/src/v0_8/api/mod.rs +++ b/crates/papyrus_rpc/src/v0_8/api/mod.rs @@ -257,9 +257,9 @@ pub trait JsonRpc { block_id: BlockId, ) -> RpcResult>; - /// Returns the compiled contract class associated with the given class hash. + /// Returns the compiled class associated with the given class hash. #[method(name = "getCompiledContractClass")] - fn get_compiled_contract_class( + fn get_compiled_class( &self, block_id: BlockId, class_hash: ClassHash, diff --git a/crates/papyrus_rpc/src/v0_8/api/test.rs b/crates/papyrus_rpc/src/v0_8/api/test.rs index 54819a917f..5bfb5c6c8e 100644 --- a/crates/papyrus_rpc/src/v0_8/api/test.rs +++ b/crates/papyrus_rpc/src/v0_8/api/test.rs @@ -3680,7 +3680,7 @@ async fn get_deprecated_class_state_mutability() { // TODO (Yael 16/06/2024): Add a test case for block_number which is not the latest. #[tokio::test] -async fn get_compiled_contract_class() { +async fn get_compiled_class() { let cairo1_class_hash = ClassHash(Felt::ONE); let cairo0_class_hash = ClassHash(Felt::TWO); let invalid_class_hash = ClassHash(Felt::THREE); diff --git a/crates/papyrus_state_reader/src/papyrus_state.rs b/crates/papyrus_state_reader/src/papyrus_state.rs index 3ff2cdc46e..2af2651d10 100644 --- a/crates/papyrus_state_reader/src/papyrus_state.rs +++ b/crates/papyrus_state_reader/src/papyrus_state.rs @@ -1,7 +1,7 @@ use blockifier::execution::contract_class::{ - ContractClassV0, - ContractClassV1, - RunnableContractClass, + CompiledClassV0, + CompiledClassV1, + RunnableCompiledClass, }; use blockifier::state::errors::StateError; use blockifier::state::global_cache::GlobalContractCache; @@ -23,14 +23,14 @@ type RawPapyrusReader<'env> = papyrus_storage::StorageTxn<'env, RO>; pub struct PapyrusReader { storage_reader: StorageReader, latest_block: BlockNumber, - global_class_hash_to_class: GlobalContractCache, + global_class_hash_to_class: GlobalContractCache, } impl PapyrusReader { pub fn new( storage_reader: StorageReader, latest_block: BlockNumber, - global_class_hash_to_class: GlobalContractCache, + global_class_hash_to_class: GlobalContractCache, ) -> Self { Self { storage_reader, latest_block, global_class_hash_to_class } } @@ -43,10 +43,10 @@ impl PapyrusReader { /// Returns a V1 contract if found, or a V0 contract if a V1 contract is not /// found, or an `Error` otherwise. - fn get_compiled_contract_class_inner( + fn get_compiled_class_inner( &self, class_hash: ClassHash, - ) -> StateResult { + ) -> StateResult { let state_number = StateNumber(self.latest_block); let class_declaration_block_number = self .reader()? @@ -57,7 +57,7 @@ impl PapyrusReader { Some(block_number) if block_number <= state_number.0); if class_is_declared { - let casm_contract_class = self + let casm_compiled_class = self .reader()? .get_casm(&class_hash) .map_err(|err| StateError::StateReadError(err.to_string()))? @@ -66,18 +66,18 @@ impl PapyrusReader { inconsistent.", ); - return Ok(RunnableContractClass::V1(ContractClassV1::try_from(casm_contract_class)?)); + return Ok(RunnableCompiledClass::V1(CompiledClassV1::try_from(casm_compiled_class)?)); } - let v0_contract_class = self + let v0_compiled_class = self .reader()? .get_state_reader() .and_then(|sr| sr.get_deprecated_class_definition_at(state_number, &class_hash)) .map_err(|err| StateError::StateReadError(err.to_string()))?; - match v0_contract_class { + match v0_compiled_class { Some(starknet_api_contract_class) => { - Ok(ContractClassV0::try_from(starknet_api_contract_class)?.into()) + Ok(CompiledClassV0::try_from(starknet_api_contract_class)?.into()) } None => Err(StateError::UndeclaredClassHash(class_hash)), } @@ -124,17 +124,14 @@ impl StateReader for PapyrusReader { } } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { // Assumption: the global cache is cleared upon reverted blocks. let contract_class = self.global_class_hash_to_class.get(&class_hash); match contract_class { Some(contract_class) => Ok(contract_class), None => { - let contract_class_from_db = self.get_compiled_contract_class_inner(class_hash)?; + let contract_class_from_db = self.get_compiled_class_inner(class_hash)?; // The class was declared in a previous (finalized) state; update the global cache. self.global_class_hash_to_class.set(class_hash, contract_class_from_db.clone()); Ok(contract_class_from_db) diff --git a/crates/starknet_api/src/contract_class.rs b/crates/starknet_api/src/contract_class.rs index f103a13eae..3a85573a06 100644 --- a/crates/starknet_api/src/contract_class.rs +++ b/crates/starknet_api/src/contract_class.rs @@ -42,7 +42,7 @@ impl ContractClass { } } } -/// All relevant information about a declared contract class, including the compiled contract class +/// All relevant information about a declared contract class, including the compiled class /// and other parameters derived from the original declare transaction required for billing. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] // TODO(Ayelet,10/02/2024): Change to bytes. diff --git a/crates/starknet_api/src/executable_transaction.rs b/crates/starknet_api/src/executable_transaction.rs index fe3e20f9f4..a3e0f96f33 100644 --- a/crates/starknet_api/src/executable_transaction.rs +++ b/crates/starknet_api/src/executable_transaction.rs @@ -168,7 +168,7 @@ impl DeclareTransaction { Ok(Self { tx: declare_tx, tx_hash, class_info }) } - /// Validates that the compiled class hash of the compiled contract class matches the supplied + /// Validates that the compiled class hash of the compiled class matches the supplied /// compiled class hash. /// Relevant only for version 3 transactions. pub fn validate_compiled_class_hash(&self) -> bool { diff --git a/crates/starknet_batcher/src/block_builder.rs b/crates/starknet_batcher/src/block_builder.rs index 4eab564c0f..ecb944c347 100644 --- a/crates/starknet_batcher/src/block_builder.rs +++ b/crates/starknet_batcher/src/block_builder.rs @@ -11,7 +11,7 @@ use blockifier::blockifier::transaction_executor::{ }; use blockifier::bouncer::{BouncerConfig, BouncerWeights}; use blockifier::context::{BlockContext, ChainInfo}; -use blockifier::execution::contract_class::RunnableContractClass; +use blockifier::execution::contract_class::RunnableCompiledClass; use blockifier::state::cached_state::CommitmentStateDiff; use blockifier::state::errors::StateError; use blockifier::state::global_cache::GlobalContractCache; @@ -296,7 +296,7 @@ impl SerializeConfig for BlockBuilderConfig { pub struct BlockBuilderFactory { pub block_builder_config: BlockBuilderConfig, pub storage_reader: StorageReader, - pub global_class_hash_to_class: GlobalContractCache, + pub global_class_hash_to_class: GlobalContractCache, } impl BlockBuilderFactory { diff --git a/crates/starknet_gateway/src/rpc_objects.rs b/crates/starknet_gateway/src/rpc_objects.rs index 9d015fb862..f9b7d17cc2 100644 --- a/crates/starknet_gateway/src/rpc_objects.rs +++ b/crates/starknet_gateway/src/rpc_objects.rs @@ -48,7 +48,7 @@ pub struct GetClassHashAtParams { } #[derive(Serialize, Deserialize)] -pub struct GetCompiledContractClassParams { +pub struct GetCompiledClassParams { pub class_hash: ClassHash, pub block_id: BlockId, } diff --git a/crates/starknet_gateway/src/rpc_state_reader.rs b/crates/starknet_gateway/src/rpc_state_reader.rs index 57eb41212c..fa4e5fc684 100644 --- a/crates/starknet_gateway/src/rpc_state_reader.rs +++ b/crates/starknet_gateway/src/rpc_state_reader.rs @@ -1,8 +1,8 @@ use blockifier::blockifier::block::BlockInfo; use blockifier::execution::contract_class::{ - ContractClassV0, - ContractClassV1, - RunnableContractClass, + CompiledClassV0, + CompiledClassV1, + RunnableCompiledClass, }; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader as BlockifierStateReader, StateResult}; @@ -22,7 +22,7 @@ use crate::rpc_objects::{ BlockId, GetBlockWithTxHashesParams, GetClassHashAtParams, - GetCompiledContractClassParams, + GetCompiledClassParams, GetNonceParams, GetStorageAtParams, RpcResponse, @@ -139,23 +139,20 @@ impl BlockifierStateReader for RpcStateReader { } } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { let get_compiled_class_params = - GetCompiledContractClassParams { class_hash, block_id: self.block_id }; + GetCompiledClassParams { class_hash, block_id: self.block_id }; let result = self.send_rpc_request("starknet_getCompiledContractClass", get_compiled_class_params)?; let contract_class: CompiledContractClass = serde_json::from_value(result).map_err(serde_err_to_state_err)?; match contract_class { - CompiledContractClass::V1(contract_class_v1) => Ok(RunnableContractClass::V1( - ContractClassV1::try_from(contract_class_v1).map_err(StateError::ProgramError)?, + CompiledContractClass::V1(contract_class_v1) => Ok(RunnableCompiledClass::V1( + CompiledClassV1::try_from(contract_class_v1).map_err(StateError::ProgramError)?, )), - CompiledContractClass::V0(contract_class_v0) => Ok(RunnableContractClass::V0( - ContractClassV0::try_from(contract_class_v0).map_err(StateError::ProgramError)?, + CompiledContractClass::V0(contract_class_v0) => Ok(RunnableCompiledClass::V0( + CompiledClassV0::try_from(contract_class_v0).map_err(StateError::ProgramError)?, )), } } diff --git a/crates/starknet_gateway/src/rpc_state_reader_test.rs b/crates/starknet_gateway/src/rpc_state_reader_test.rs index 034c9db09c..34756045fb 100644 --- a/crates/starknet_gateway/src/rpc_state_reader_test.rs +++ b/crates/starknet_gateway/src/rpc_state_reader_test.rs @@ -1,4 +1,4 @@ -use blockifier::execution::contract_class::RunnableContractClass; +use blockifier::execution::contract_class::RunnableCompiledClass; use blockifier::state::state_api::StateReader; use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; use papyrus_rpc::CompiledContractClass; @@ -13,7 +13,7 @@ use crate::rpc_objects::{ BlockId, GetBlockWithTxHashesParams, GetClassHashAtParams, - GetCompiledContractClassParams, + GetCompiledClassParams, GetNonceParams, GetStorageAtParams, ResourcePrice, @@ -153,7 +153,7 @@ async fn test_get_nonce_at() { } #[tokio::test] -async fn test_get_compiled_contract_class() { +async fn test_get_compiled_class() { let mut server = run_rpc_server().await; let config = RpcStateReaderConfig { url: server.url(), ..Default::default() }; @@ -171,10 +171,7 @@ async fn test_get_compiled_contract_class() { &mut server, &config.json_rpc_version, "starknet_getCompiledContractClass", - GetCompiledContractClassParams { - block_id: BlockId::Latest, - class_hash: class_hash!("0x1"), - }, + GetCompiledClassParams { block_id: BlockId::Latest, class_hash: class_hash!("0x1") }, &RpcResponse::Success(RpcSuccessResponse { result: serde_json::to_value(CompiledContractClass::V1(expected_result.clone())) .unwrap(), @@ -183,12 +180,11 @@ async fn test_get_compiled_contract_class() { ); let client = RpcStateReader::from_latest(&config); - let result = - tokio::task::spawn_blocking(move || client.get_compiled_contract_class(class_hash!("0x1"))) - .await - .unwrap() - .unwrap(); - assert_eq!(result, RunnableContractClass::V1(expected_result.try_into().unwrap())); + let result = tokio::task::spawn_blocking(move || client.get_compiled_class(class_hash!("0x1"))) + .await + .unwrap() + .unwrap(); + assert_eq!(result, RunnableCompiledClass::V1(expected_result.try_into().unwrap())); mock.assert_async().await; } diff --git a/crates/starknet_gateway/src/state_reader.rs b/crates/starknet_gateway/src/state_reader.rs index 993fe4b5d5..4109a426ee 100644 --- a/crates/starknet_gateway/src/state_reader.rs +++ b/crates/starknet_gateway/src/state_reader.rs @@ -1,5 +1,5 @@ use blockifier::blockifier::block::BlockInfo; -use blockifier::execution::contract_class::RunnableContractClass; +use blockifier::execution::contract_class::RunnableCompiledClass; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader as BlockifierStateReader, StateResult}; #[cfg(test)] @@ -45,11 +45,8 @@ impl BlockifierStateReader for Box { self.as_ref().get_class_hash_at(contract_address) } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { - self.as_ref().get_compiled_contract_class(class_hash) + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { + self.as_ref().get_compiled_class(class_hash) } fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult { diff --git a/crates/starknet_gateway/src/state_reader_test_utils.rs b/crates/starknet_gateway/src/state_reader_test_utils.rs index faf1121a53..45184de5d4 100644 --- a/crates/starknet_gateway/src/state_reader_test_utils.rs +++ b/crates/starknet_gateway/src/state_reader_test_utils.rs @@ -1,6 +1,6 @@ use blockifier::blockifier::block::BlockInfo; use blockifier::context::BlockContext; -use blockifier::execution::contract_class::RunnableContractClass; +use blockifier::execution::contract_class::RunnableCompiledClass; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader as BlockifierStateReader, StateResult}; use blockifier::test_utils::contracts::FeatureContract; @@ -44,11 +44,8 @@ impl BlockifierStateReader for TestStateReader { self.blockifier_state_reader.get_class_hash_at(contract_address) } - fn get_compiled_contract_class( - &self, - class_hash: ClassHash, - ) -> StateResult { - self.blockifier_state_reader.get_compiled_contract_class(class_hash) + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { + self.blockifier_state_reader.get_compiled_class(class_hash) } fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult { From 18e06a776fcf16c95d25aacea0f7e6a86cfd16ee Mon Sep 17 00:00:00 2001 From: avivg-starkware Date: Wed, 27 Nov 2024 18:26:24 +0200 Subject: [PATCH 02/25] chore(blockifier): create func keccak_base to delete code duplication (#2198) --- .../src/execution/native/syscall_handler.rs | 46 +++---------------- .../blockifier/src/execution/syscalls/mod.rs | 45 +++++------------- .../src/execution/syscalls/syscall_base.rs | 44 ++++++++++++++++++ 3 files changed, 61 insertions(+), 74 deletions(-) diff --git a/crates/blockifier/src/execution/native/syscall_handler.rs b/crates/blockifier/src/execution/native/syscall_handler.rs index 5412a62d79..28c4869bd0 100644 --- a/crates/blockifier/src/execution/native/syscall_handler.rs +++ b/crates/blockifier/src/execution/native/syscall_handler.rs @@ -446,47 +446,13 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { fn keccak(&mut self, input: &[u64], remaining_gas: &mut u64) -> SyscallResult { self.pre_execute_syscall(remaining_gas, self.gas_costs().keccak_gas_cost)?; - const KECCAK_FULL_RATE_IN_WORDS: usize = 17; - - let input_length = input.len(); - let (n_rounds, remainder) = num_integer::div_rem(input_length, KECCAK_FULL_RATE_IN_WORDS); - - if remainder != 0 { - return Err(self.handle_error( - remaining_gas, - SyscallExecutionError::SyscallError { - error_data: vec![Felt::from_hex(INVALID_INPUT_LENGTH_ERROR).unwrap()], - }, - )); - } - - // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion - // works. - let n_rounds = u64::try_from(n_rounds).expect("Failed to convert usize to u64."); - let gas_cost = n_rounds * self.gas_costs().keccak_round_cost_gas_cost; - - if gas_cost > *remaining_gas { - return Err(self.handle_error( - remaining_gas, - SyscallExecutionError::SyscallError { - error_data: vec![Felt::from_hex(OUT_OF_GAS_ERROR).unwrap()], - }, - )); - } - *remaining_gas -= gas_cost; - - let mut state = [0u64; 25]; - for chunk in input.chunks(KECCAK_FULL_RATE_IN_WORDS) { - for (i, val) in chunk.iter().enumerate() { - state[i] ^= val; - } - keccak::f1600(&mut state) + match self.base.keccak(input, remaining_gas) { + Ok((state, _n_rounds)) => Ok(U256 { + hi: u128::from(state[2]) | (u128::from(state[3]) << 64), + lo: u128::from(state[0]) | (u128::from(state[1]) << 64), + }), + Err(err) => Err(self.handle_error(remaining_gas, err)), } - - Ok(U256 { - hi: u128::from(state[2]) | (u128::from(state[3]) << 64), - lo: u128::from(state[0]) | (u128::from(state[1]) << 64), - }) } fn secp256k1_new( diff --git a/crates/blockifier/src/execution/syscalls/mod.rs b/crates/blockifier/src/execution/syscalls/mod.rs index 1ea040b7d1..9d6f412b72 100644 --- a/crates/blockifier/src/execution/syscalls/mod.rs +++ b/crates/blockifier/src/execution/syscalls/mod.rs @@ -30,7 +30,6 @@ use crate::execution::execution_utils::{ write_maybe_relocatable, ReadOnlySegment, }; -use crate::execution::syscalls::hint_processor::{INVALID_INPUT_LENGTH_ERROR, OUT_OF_GAS_ERROR}; use crate::execution::syscalls::syscall_base::SyscallResult; use crate::versioned_constants::{EventLimits, VersionedConstants}; @@ -606,45 +605,23 @@ pub fn keccak( ) -> SyscallResult { let input_length = (request.input_end - request.input_start)?; - const KECCAK_FULL_RATE_IN_WORDS: usize = 17; - let (n_rounds, remainder) = num_integer::div_rem(input_length, KECCAK_FULL_RATE_IN_WORDS); - - if remainder != 0 { - return Err(SyscallExecutionError::SyscallError { - error_data: vec![ - Felt::from_hex(INVALID_INPUT_LENGTH_ERROR).map_err(SyscallExecutionError::from)?, - ], - }); - } - - // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion works. - let n_rounds_as_u64 = u64::try_from(n_rounds).expect("Failed to convert usize to u64."); - let gas_cost = n_rounds_as_u64 * syscall_handler.gas_costs().keccak_round_cost_gas_cost; - if gas_cost > *remaining_gas { - let out_of_gas_error = - Felt::from_hex(OUT_OF_GAS_ERROR).map_err(SyscallExecutionError::from)?; + let data = vm.get_integer_range(request.input_start, input_length)?; + let data_u64: &[u64] = &data + .iter() + .map(|felt| { + felt.to_u64().ok_or_else(|| SyscallExecutionError::InvalidSyscallInput { + input: **felt, + info: "Invalid input for the keccak syscall.".to_string(), + }) + }) + .collect::, _>>()?; - return Err(SyscallExecutionError::SyscallError { error_data: vec![out_of_gas_error] }); - } - *remaining_gas -= gas_cost; + let (state, n_rounds) = syscall_handler.base.keccak(data_u64, remaining_gas)?; // For the keccak system call we want to count the number of rounds rather than the number of // syscall invocations. syscall_handler.increment_syscall_count_by(&SyscallSelector::Keccak, n_rounds); - let data = vm.get_integer_range(request.input_start, input_length)?; - - let mut state = [0u64; 25]; - for chunk in data.chunks(KECCAK_FULL_RATE_IN_WORDS) { - for (i, val) in chunk.iter().enumerate() { - state[i] ^= val.to_u64().ok_or_else(|| SyscallExecutionError::InvalidSyscallInput { - input: **val, - info: String::from("Invalid input for the keccak syscall."), - })?; - } - keccak::f1600(&mut state) - } - Ok(KeccakResponse { result_low: (Felt::from(state[1]) * Felt::TWO.pow(64_u128)) + Felt::from(state[0]), result_high: (Felt::from(state[3]) * Felt::TWO.pow(64_u128)) + Felt::from(state[2]), diff --git a/crates/blockifier/src/execution/syscalls/syscall_base.rs b/crates/blockifier/src/execution/syscalls/syscall_base.rs index 7a4b02fc38..b93c2141a7 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_base.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_base.rs @@ -21,11 +21,14 @@ use crate::execution::syscalls::hint_processor::{ SyscallExecutionError, BLOCK_NUMBER_OUT_OF_RANGE_ERROR, ENTRYPOINT_FAILED_ERROR, + INVALID_INPUT_LENGTH_ERROR, + OUT_OF_GAS_ERROR, }; use crate::state::state_api::State; use crate::transaction::account_transaction::is_cairo1; pub type SyscallResult = Result; +pub const KECCAK_FULL_RATE_IN_WORDS: usize = 17; /// This file is for sharing common logic between Native and VM syscall implementations. @@ -250,6 +253,47 @@ impl<'state> SyscallHandlerBase<'state> { Ok(raw_retdata) } + pub fn keccak( + &mut self, + input: &[u64], + remaining_gas: &mut u64, + ) -> SyscallResult<([u64; 4], usize)> { + let input_length = input.len(); + + let (n_rounds, remainder) = num_integer::div_rem(input_length, KECCAK_FULL_RATE_IN_WORDS); + + if remainder != 0 { + return Err(SyscallExecutionError::SyscallError { + error_data: vec![ + Felt::from_hex(INVALID_INPUT_LENGTH_ERROR) + .expect("Failed to parse INVALID_INPUT_LENGTH_ERROR hex string"), + ], + }); + } + // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion + // works. + let n_rounds_as_u64 = u64::try_from(n_rounds).expect("Failed to convert usize to u64."); + let gas_cost = n_rounds_as_u64 * self.context.gas_costs().keccak_round_cost_gas_cost; + + if gas_cost > *remaining_gas { + let out_of_gas_error = Felt::from_hex(OUT_OF_GAS_ERROR) + .expect("Failed to parse OUT_OF_GAS_ERROR hex string"); + + return Err(SyscallExecutionError::SyscallError { error_data: vec![out_of_gas_error] }); + } + *remaining_gas -= gas_cost; + + let mut state = [0u64; 25]; + for chunk in input.chunks(KECCAK_FULL_RATE_IN_WORDS) { + for (i, val) in chunk.iter().enumerate() { + state[i] ^= val; + } + keccak::f1600(&mut state) + } + + Ok((state[..4].try_into().expect("Slice with incorrect length"), n_rounds)) + } + pub fn finalize(&mut self) { self.context .revert_infos From bbd1aef2735d45964dcee2e273d4205741d97e26 Mon Sep 17 00:00:00 2001 From: avivg-starkware Date: Wed, 27 Nov 2024 20:52:11 +0200 Subject: [PATCH 03/25] chore(blockifier): add ContractClassManagerConfig (#2092) --- crates/blockifier/src/blockifier/config.rs | 44 +++++++++++++++++++ crates/blockifier/src/state/global_cache.rs | 2 +- .../src/py_block_executor.rs | 42 ++++++++++++++---- .../src/py_block_executor_test.rs | 4 +- crates/native_blockifier/src/py_objects.rs | 30 ++++++++++++- 5 files changed, 110 insertions(+), 12 deletions(-) diff --git a/crates/blockifier/src/blockifier/config.rs b/crates/blockifier/src/blockifier/config.rs index 3252394a45..bc8b5628ce 100644 --- a/crates/blockifier/src/blockifier/config.rs +++ b/crates/blockifier/src/blockifier/config.rs @@ -4,6 +4,8 @@ use papyrus_config::dumping::{append_sub_config_name, ser_param, SerializeConfig use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::{Deserialize, Serialize}; +use crate::state::global_cache::GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST; + #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] pub struct TransactionExecutorConfig { pub concurrency_config: ConcurrencyConfig, @@ -61,3 +63,45 @@ impl SerializeConfig for ConcurrencyConfig { ]) } } + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +pub struct ContractClassManagerConfig { + pub run_cairo_native: bool, + pub wait_on_native_compilation: bool, + pub contract_cache_size: usize, +} + +impl Default for ContractClassManagerConfig { + fn default() -> Self { + Self { + run_cairo_native: false, + wait_on_native_compilation: false, + contract_cache_size: GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST, + } + } +} + +impl SerializeConfig for ContractClassManagerConfig { + fn dump(&self) -> BTreeMap { + BTreeMap::from_iter([ + ser_param( + "run_cairo_native", + &self.run_cairo_native, + "Enables Cairo native execution.", + ParamPrivacyInput::Public, + ), + ser_param( + "wait_on_native_compilation", + &self.wait_on_native_compilation, + "Block Sequencer main program while compiling sierra, for testing.", + ParamPrivacyInput::Public, + ), + ser_param( + "contract_cache_size", + &self.contract_cache_size, + "The size of the global contract cache.", + ParamPrivacyInput::Public, + ), + ]) + } +} diff --git a/crates/blockifier/src/state/global_cache.rs b/crates/blockifier/src/state/global_cache.rs index f26d4ab39d..46534a1839 100644 --- a/crates/blockifier/src/state/global_cache.rs +++ b/crates/blockifier/src/state/global_cache.rs @@ -25,7 +25,7 @@ pub enum CachedCairoNative { CompilationFailed, } -pub const GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST: usize = 100; +pub const GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST: usize = 400; impl GlobalContractCache { /// Locks the cache for atomic access. Although conceptually shared, writing to this cache is diff --git a/crates/native_blockifier/src/py_block_executor.rs b/crates/native_blockifier/src/py_block_executor.rs index 0cefe8026d..d2668edb0b 100644 --- a/crates/native_blockifier/src/py_block_executor.rs +++ b/crates/native_blockifier/src/py_block_executor.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use blockifier::abi::constants as abi_constants; -use blockifier::blockifier::config::TransactionExecutorConfig; +use blockifier::blockifier::config::{ContractClassManagerConfig, TransactionExecutorConfig}; use blockifier::blockifier::transaction_executor::{TransactionExecutor, TransactionExecutorError}; use blockifier::bouncer::BouncerConfig; use blockifier::context::{BlockContext, ChainInfo, FeeTokenAddresses}; @@ -25,7 +25,12 @@ use starknet_api::transaction::fields::Fee; use starknet_types_core::felt::Felt; use crate::errors::{NativeBlockifierError, NativeBlockifierResult}; -use crate::py_objects::{PyBouncerConfig, PyConcurrencyConfig, PyVersionedConstantsOverrides}; +use crate::py_objects::{ + PyBouncerConfig, + PyConcurrencyConfig, + PyContractClassManagerConfig, + 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}; @@ -130,18 +135,19 @@ pub struct PyBlockExecutor { pub tx_executor: Option>, /// `Send` trait is required for `pyclass` compatibility as Python objects must be threadsafe. pub storage: Box, + pub contract_class_manager_config: ContractClassManagerConfig, pub global_contract_cache: GlobalContractCache, } #[pymethods] impl PyBlockExecutor { #[new] - #[pyo3(signature = (bouncer_config, concurrency_config, os_config, global_contract_cache_size, target_storage_config, py_versioned_constants_overrides))] + #[pyo3(signature = (bouncer_config, concurrency_config, contract_class_manager_config, os_config, target_storage_config, py_versioned_constants_overrides))] pub fn create( bouncer_config: PyBouncerConfig, concurrency_config: PyConcurrencyConfig, + contract_class_manager_config: PyContractClassManagerConfig, os_config: PyOsConfig, - global_contract_cache_size: usize, target_storage_config: StorageConfig, py_versioned_constants_overrides: PyVersionedConstantsOverrides, ) -> Self { @@ -161,7 +167,10 @@ impl PyBlockExecutor { versioned_constants, tx_executor: None, storage: Box::new(storage), - global_contract_cache: GlobalContractCache::new(global_contract_cache_size), + contract_class_manager_config: contract_class_manager_config.into(), + global_contract_cache: GlobalContractCache::new( + contract_class_manager_config.contract_cache_size, + ), } } @@ -369,16 +378,16 @@ impl PyBlockExecutor { } #[cfg(any(feature = "testing", test))] - #[pyo3(signature = (concurrency_config, os_config, path, max_state_diff_size))] + #[pyo3(signature = (concurrency_config, contract_class_manager_config, os_config, path, max_state_diff_size))] #[staticmethod] fn create_for_testing( concurrency_config: PyConcurrencyConfig, + contract_class_manager_config: PyContractClassManagerConfig, os_config: PyOsConfig, path: std::path::PathBuf, max_state_diff_size: usize, ) -> Self { use blockifier::bouncer::BouncerWeights; - use blockifier::state::global_cache::GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST; // TODO(Meshi, 01/01/2025): Remove this once we fix all python tests that re-declare cairo0 // contracts. let mut versioned_constants = VersionedConstants::latest_constants().clone(); @@ -397,7 +406,10 @@ impl PyBlockExecutor { chain_info: os_config.into_chain_info(), versioned_constants, tx_executor: None, - global_contract_cache: GlobalContractCache::new(GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST), + contract_class_manager_config: contract_class_manager_config.into(), + global_contract_cache: GlobalContractCache::new( + contract_class_manager_config.contract_cache_size, + ), } } } @@ -427,6 +439,11 @@ impl PyBlockExecutor { chain_info: ChainInfo::default(), versioned_constants: VersionedConstants::latest_constants().clone(), tx_executor: None, + contract_class_manager_config: ContractClassManagerConfig { + run_cairo_native: false, + wait_on_native_compilation: false, + contract_cache_size: GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST, + }, global_contract_cache: GlobalContractCache::new(GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST), } } @@ -434,11 +451,18 @@ impl PyBlockExecutor { #[cfg(test)] pub(crate) fn native_create_for_testing( concurrency_config: PyConcurrencyConfig, + contract_class_manager_config: PyContractClassManagerConfig, os_config: PyOsConfig, path: std::path::PathBuf, max_state_diff_size: usize, ) -> Self { - Self::create_for_testing(concurrency_config, os_config, path, max_state_diff_size) + Self::create_for_testing( + concurrency_config, + contract_class_manager_config, + os_config, + path, + max_state_diff_size, + ) } } diff --git a/crates/native_blockifier/src/py_block_executor_test.rs b/crates/native_blockifier/src/py_block_executor_test.rs index 2a87bec4fc..d223df4657 100644 --- a/crates/native_blockifier/src/py_block_executor_test.rs +++ b/crates/native_blockifier/src/py_block_executor_test.rs @@ -12,7 +12,7 @@ use starknet_api::state::SierraContractClass; use starknet_types_core::felt::Felt; use crate::py_block_executor::{PyBlockExecutor, PyOsConfig}; -use crate::py_objects::PyConcurrencyConfig; +use crate::py_objects::{PyConcurrencyConfig, PyContractClassManagerConfig}; use crate::py_state_diff::{PyBlockInfo, PyStateDiff}; use crate::py_utils::PyFelt; use crate::test_utils::MockStorage; @@ -39,6 +39,7 @@ fn global_contract_cache_update() { let temp_storage_path = tempfile::tempdir().unwrap().into_path(); let mut block_executor = PyBlockExecutor::create_for_testing( PyConcurrencyConfig::default(), + PyContractClassManagerConfig::default(), PyOsConfig::default(), temp_storage_path, 4000, @@ -119,6 +120,7 @@ fn global_contract_cache_update_large_contract() { let temp_storage_path = tempfile::tempdir().unwrap().into_path(); let mut block_executor = PyBlockExecutor::native_create_for_testing( Default::default(), + PyContractClassManagerConfig::default(), Default::default(), temp_storage_path, 4000, diff --git a/crates/native_blockifier/src/py_objects.rs b/crates/native_blockifier/src/py_objects.rs index 8212a3fd3a..8e54cff2f4 100644 --- a/crates/native_blockifier/src/py_objects.rs +++ b/crates/native_blockifier/src/py_objects.rs @@ -1,8 +1,9 @@ use std::collections::HashMap; use blockifier::abi::constants; -use blockifier::blockifier::config::ConcurrencyConfig; +use blockifier::blockifier::config::{ConcurrencyConfig, ContractClassManagerConfig}; use blockifier::bouncer::{BouncerConfig, BouncerWeights, BuiltinCount, HashMapWrapper}; +use blockifier::state::global_cache::GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST; use blockifier::versioned_constants::VersionedConstantsOverrides; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; @@ -148,3 +149,30 @@ impl From for ConcurrencyConfig { } } } + +#[derive(Debug, Clone, Copy, FromPyObject)] +pub struct PyContractClassManagerConfig { + pub run_cairo_native: bool, + pub wait_on_native_compilation: bool, + pub contract_cache_size: usize, +} + +impl Default for PyContractClassManagerConfig { + fn default() -> Self { + Self { + run_cairo_native: false, + wait_on_native_compilation: false, + contract_cache_size: GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST, + } + } +} + +impl From for ContractClassManagerConfig { + fn from(py_contract_class_manager_config: PyContractClassManagerConfig) -> Self { + ContractClassManagerConfig { + run_cairo_native: py_contract_class_manager_config.run_cairo_native, + wait_on_native_compilation: py_contract_class_manager_config.wait_on_native_compilation, + contract_cache_size: py_contract_class_manager_config.contract_cache_size, + } + } +} From 50473014cf679f0f226309bf13dd158731584ca9 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 28 Nov 2024 09:53:44 +0200 Subject: [PATCH 04/25] refactor(starknet_api): remove duplicate definition of contract class (#2298) --- .../src/starknet_api_test_utils.rs | 5 +- .../src/converters/rpc_transaction.rs | 66 +------------------ crates/papyrus_test_utils/src/lib.rs | 9 +-- crates/starknet_api/src/rpc_transaction.rs | 14 +--- .../starknet_api/src/rpc_transaction_test.rs | 4 +- crates/starknet_api/src/state.rs | 2 +- crates/starknet_api/src/test_utils/declare.rs | 10 +-- .../src/stateless_transaction_validator.rs | 4 +- .../stateless_transaction_validator_test.rs | 16 ++--- crates/starknet_gateway/src/test_utils.rs | 5 +- crates/starknet_sierra_compile/src/utils.rs | 10 +-- 11 files changed, 31 insertions(+), 114 deletions(-) diff --git a/crates/mempool_test_utils/src/starknet_api_test_utils.rs b/crates/mempool_test_utils/src/starknet_api_test_utils.rs index c9e685fbd7..74a1a7b5a4 100644 --- a/crates/mempool_test_utils/src/starknet_api_test_utils.rs +++ b/crates/mempool_test_utils/src/starknet_api_test_utils.rs @@ -15,7 +15,8 @@ use starknet_api::block::GasPrice; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::executable_transaction::AccountTransaction; use starknet_api::execution_resources::GasAmount; -use starknet_api::rpc_transaction::{ContractClass, RpcTransaction}; +use starknet_api::rpc_transaction::RpcTransaction; +use starknet_api::state::SierraContractClass; use starknet_api::test_utils::declare::rpc_declare_tx; use starknet_api::test_utils::deploy_account::rpc_deploy_account_tx; use starknet_api::test_utils::invoke::{rpc_invoke_tx, InvokeTxArgs}; @@ -65,7 +66,7 @@ pub fn test_valid_resource_bounds() -> ValidResourceBounds { } /// Get the contract class used for testing. -pub fn contract_class() -> ContractClass { +pub fn contract_class() -> SierraContractClass { env::set_current_dir(resolve_project_relative_path(TEST_FILES_FOLDER).unwrap()) .expect("Couldn't set working dir."); let json_file_path = Path::new(CONTRACT_CLASS_FILE); diff --git a/crates/papyrus_protobuf/src/converters/rpc_transaction.rs b/crates/papyrus_protobuf/src/converters/rpc_transaction.rs index 234a31e3ff..55998e14e8 100644 --- a/crates/papyrus_protobuf/src/converters/rpc_transaction.rs +++ b/crates/papyrus_protobuf/src/converters/rpc_transaction.rs @@ -4,8 +4,6 @@ mod rpc_transaction_test; use prost::Message; use starknet_api::rpc_transaction::{ - ContractClass, - EntryPointByType, RpcDeclareTransaction, RpcDeclareTransactionV3, RpcDeployAccountTransaction, @@ -14,19 +12,17 @@ use starknet_api::rpc_transaction::{ RpcInvokeTransactionV3, RpcTransaction, }; -use starknet_api::state::EntryPoint; use starknet_api::transaction::fields::{AllResourceBounds, ValidResourceBounds}; use starknet_api::transaction::{ DeclareTransactionV3, DeployAccountTransactionV3, InvokeTransactionV3, }; -use starknet_types_core::felt::Felt; use super::ProtobufConversionError; use crate::auto_impl_into_and_try_from_vec_u8; use crate::mempool::RpcTransactionWrapper; -use crate::protobuf::{self, Felt252}; +use crate::protobuf::{self}; auto_impl_into_and_try_from_vec_u8!(RpcTransactionWrapper, protobuf::RpcTransaction); @@ -330,63 +326,3 @@ impl From for protobuf::ResourceBounds { ValidResourceBounds::AllResources(value).into() } } - -impl TryFrom for ContractClass { - type Error = ProtobufConversionError; - fn try_from(value: protobuf::Cairo1Class) -> Result { - let sierra_program = - value.program.into_iter().map(Felt::try_from).collect::, _>>()?; - let contract_class_version = value.contract_class_version; - let entry_points = value.entry_points.ok_or(ProtobufConversionError::MissingField { - field_description: "Cairo1Class::entry_points_by_type", - })?; - let entry_points_by_type = EntryPointByType { - constructor: entry_points - .constructors - .into_iter() - .map(EntryPoint::try_from) - .collect::, _>>()?, - external: entry_points - .externals - .into_iter() - .map(EntryPoint::try_from) - .collect::, _>>()?, - l1handler: entry_points - .l1_handlers - .into_iter() - .map(EntryPoint::try_from) - .collect::, _>>()?, - }; - let abi = value.abi; - Ok(Self { sierra_program, contract_class_version, entry_points_by_type, abi }) - } -} - -impl From for protobuf::Cairo1Class { - fn from(value: ContractClass) -> Self { - let program = value.sierra_program.into_iter().map(Felt252::from).collect(); - let contract_class_version = value.contract_class_version; - let entry_points = protobuf::Cairo1EntryPoints { - constructors: value - .entry_points_by_type - .constructor - .into_iter() - .map(protobuf::SierraEntryPoint::from) - .collect(), - externals: value - .entry_points_by_type - .external - .into_iter() - .map(protobuf::SierraEntryPoint::from) - .collect(), - l1_handlers: value - .entry_points_by_type - .l1handler - .into_iter() - .map(protobuf::SierraEntryPoint::from) - .collect(), - }; - let abi = value.abi; - Self { program, contract_class_version, entry_points: Some(entry_points), abi } - } -} diff --git a/crates/papyrus_test_utils/src/lib.rs b/crates/papyrus_test_utils/src/lib.rs index e930cf6e60..2dbf884e80 100644 --- a/crates/papyrus_test_utils/src/lib.rs +++ b/crates/papyrus_test_utils/src/lib.rs @@ -88,7 +88,6 @@ use starknet_api::deprecated_contract_class::{ use starknet_api::execution_resources::{Builtin, ExecutionResources, GasAmount, GasVector}; use starknet_api::hash::{PoseidonHash, StarkHash}; use starknet_api::rpc_transaction::{ - ContractClass as RpcContractClass, EntryPointByType as RpcEntryPointByType, EntryPointByType, RpcDeclareTransaction, @@ -750,12 +749,6 @@ auto_impl_get_test_instance! { pub max_amount: GasAmount, pub max_price_per_unit: GasPrice, } - pub struct RpcContractClass { - pub sierra_program: Vec, - pub contract_class_version: String, - pub entry_points_by_type: RpcEntryPointByType, - pub abi: String, - } pub enum RpcTransaction { Declare(RpcDeclareTransaction) = 0, DeployAccount(RpcDeployAccountTransaction) = 1, @@ -769,7 +762,7 @@ auto_impl_get_test_instance! { pub tip: Tip, pub signature: TransactionSignature, pub nonce: Nonce, - pub contract_class: RpcContractClass, + pub contract_class: SierraContractClass, pub compiled_class_hash: CompiledClassHash, pub sender_address: ContractAddress, pub nonce_data_availability_mode: DataAvailabilityMode, diff --git a/crates/starknet_api/src/rpc_transaction.rs b/crates/starknet_api/src/rpc_transaction.rs index 4607fdd45d..49295a230d 100644 --- a/crates/starknet_api/src/rpc_transaction.rs +++ b/crates/starknet_api/src/rpc_transaction.rs @@ -5,7 +5,6 @@ mod rpc_transaction_test; use std::collections::HashMap; use serde::{Deserialize, Serialize}; -use starknet_types_core::felt::Felt; use crate::contract_class::EntryPointType; use crate::core::{ @@ -16,7 +15,7 @@ use crate::core::{ Nonce, }; use crate::data_availability::DataAvailabilityMode; -use crate::state::EntryPoint; +use crate::state::{EntryPoint, SierraContractClass}; use crate::transaction::fields::{ AccountDeploymentData, AllResourceBounds, @@ -180,7 +179,7 @@ pub struct RpcDeclareTransactionV3 { pub compiled_class_hash: CompiledClassHash, pub signature: TransactionSignature, pub nonce: Nonce, - pub contract_class: ContractClass, + pub contract_class: SierraContractClass, pub resource_bounds: AllResourceBounds, pub tip: Tip, pub paymaster_data: PaymasterData, @@ -272,15 +271,6 @@ impl From for InvokeTransactionV3 { } } -// The contract class in SN_API state doesn't have `contract_class_version`, not following the spec. -#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize, Hash)] -pub struct ContractClass { - pub sierra_program: Vec, - pub contract_class_version: String, - pub entry_points_by_type: EntryPointByType, - pub abi: String, -} - // TODO(Aviv): remove duplication with sequencer/crates/papyrus_rpc/src/v0_8/state.rs #[derive(Debug, Clone, Default, Eq, PartialEq, Deserialize, Serialize, Hash)] pub struct EntryPointByType { diff --git a/crates/starknet_api/src/rpc_transaction_test.rs b/crates/starknet_api/src/rpc_transaction_test.rs index f12acce012..7854a5d929 100644 --- a/crates/starknet_api/src/rpc_transaction_test.rs +++ b/crates/starknet_api/src/rpc_transaction_test.rs @@ -7,7 +7,6 @@ use crate::block::GasPrice; use crate::core::CompiledClassHash; use crate::execution_resources::GasAmount; use crate::rpc_transaction::{ - ContractClass, DataAvailabilityMode, RpcDeclareTransaction, RpcDeclareTransactionV3, @@ -15,6 +14,7 @@ use crate::rpc_transaction::{ RpcDeployAccountTransactionV3, RpcTransaction, }; +use crate::state::SierraContractClass; use crate::test_utils::invoke::{rpc_invoke_tx, InvokeTxArgs}; use crate::transaction::fields::{ AccountDeploymentData, @@ -40,7 +40,7 @@ fn create_resource_bounds_for_testing() -> AllResourceBounds { fn create_declare_v3() -> RpcDeclareTransaction { RpcDeclareTransaction::V3(RpcDeclareTransactionV3 { - contract_class: ContractClass::default(), + contract_class: SierraContractClass::default(), resource_bounds: create_resource_bounds_for_testing(), tip: Tip(1), signature: TransactionSignature(vec![Felt::ONE, Felt::TWO]), diff --git a/crates/starknet_api/src/state.rs b/crates/starknet_api/src/state.rs index 8bfb841bef..5de7b48865 100644 --- a/crates/starknet_api/src/state.rs +++ b/crates/starknet_api/src/state.rs @@ -209,7 +209,7 @@ impl StorageKey { impl_from_through_intermediate!(u128, StorageKey, u8, u16, u32, u64); /// A contract class. -#[derive(Debug, Clone, Default, Eq, PartialEq, Deserialize, Serialize)] +#[derive(Debug, Clone, Default, Eq, PartialEq, Deserialize, Serialize, Hash)] pub struct SierraContractClass { pub sierra_program: Vec, pub contract_class_version: String, diff --git a/crates/starknet_api/src/test_utils/declare.rs b/crates/starknet_api/src/test_utils/declare.rs index 141cf964b9..8f905add89 100644 --- a/crates/starknet_api/src/test_utils/declare.rs +++ b/crates/starknet_api/src/test_utils/declare.rs @@ -3,12 +3,8 @@ use crate::contract_class::ClassInfo; use crate::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use crate::data_availability::DataAvailabilityMode; use crate::executable_transaction::DeclareTransaction as ExecutableDeclareTransaction; -use crate::rpc_transaction::{ - ContractClass, - RpcDeclareTransaction, - RpcDeclareTransactionV3, - RpcTransaction, -}; +use crate::rpc_transaction::{RpcDeclareTransaction, RpcDeclareTransactionV3, RpcTransaction}; +use crate::state::SierraContractClass; use crate::transaction::fields::{ AccountDeploymentData, Fee, @@ -142,7 +138,7 @@ pub fn executable_declare_tx( pub fn rpc_declare_tx( declare_tx_args: DeclareTxArgs, - contract_class: ContractClass, + contract_class: SierraContractClass, ) -> RpcTransaction { if declare_tx_args.version != TransactionVersion::THREE { panic!("Unsupported transaction version: {:?}.", declare_tx_args.version); diff --git a/crates/starknet_gateway/src/stateless_transaction_validator.rs b/crates/starknet_gateway/src/stateless_transaction_validator.rs index 8dbd815540..871e2a3d3c 100644 --- a/crates/starknet_gateway/src/stateless_transaction_validator.rs +++ b/crates/starknet_gateway/src/stateless_transaction_validator.rs @@ -237,7 +237,7 @@ impl StatelessTransactionValidator { fn validate_class_length( &self, - contract_class: &starknet_api::rpc_transaction::ContractClass, + contract_class: &starknet_api::state::SierraContractClass, ) -> StatelessTransactionValidatorResult<()> { let contract_class_object_size = serde_json::to_string(&contract_class) .expect("Unexpected error serializing contract class.") @@ -254,7 +254,7 @@ impl StatelessTransactionValidator { fn validate_entry_points_sorted_and_unique( &self, - contract_class: &starknet_api::rpc_transaction::ContractClass, + contract_class: &starknet_api::state::SierraContractClass, ) -> StatelessTransactionValidatorResult<()> { let is_sorted_unique = |entry_points: &[EntryPoint]| { entry_points.windows(2).all(|pair| pair[0].selector < pair[1].selector) diff --git a/crates/starknet_gateway/src/stateless_transaction_validator_test.rs b/crates/starknet_gateway/src/stateless_transaction_validator_test.rs index dd79ded4df..57319f1d3a 100644 --- a/crates/starknet_gateway/src/stateless_transaction_validator_test.rs +++ b/crates/starknet_gateway/src/stateless_transaction_validator_test.rs @@ -5,8 +5,8 @@ use assert_matches::assert_matches; use rstest::rstest; use starknet_api::core::{EntryPointSelector, L2_ADDRESS_UPPER_BOUND}; use starknet_api::data_availability::DataAvailabilityMode; -use starknet_api::rpc_transaction::{ContractClass, EntryPointByType}; -use starknet_api::state::EntryPoint; +use starknet_api::rpc_transaction::EntryPointByType; +use starknet_api::state::{EntryPoint, SierraContractClass}; use starknet_api::test_utils::declare::rpc_declare_tx; use starknet_api::transaction::fields::{ AccountDeploymentData, @@ -359,7 +359,7 @@ fn test_declare_sierra_version_failure( let tx_validator = StatelessTransactionValidator { config: DEFAULT_VALIDATOR_CONFIG_FOR_TESTING.clone() }; - let contract_class = ContractClass { sierra_program, ..Default::default() }; + let contract_class = SierraContractClass { sierra_program, ..Default::default() }; let tx = rpc_declare_tx(declare_tx_args!(), contract_class); assert_eq!(tx_validator.validate(&tx).unwrap_err(), expected_error); @@ -379,7 +379,7 @@ fn test_declare_sierra_version_sucsses(#[case] sierra_program: Vec) { let tx_validator = StatelessTransactionValidator { config: DEFAULT_VALIDATOR_CONFIG_FOR_TESTING.clone() }; - let contract_class = ContractClass { sierra_program, ..Default::default() }; + let contract_class = SierraContractClass { sierra_program, ..Default::default() }; let tx = rpc_declare_tx(declare_tx_args!(), contract_class); assert_matches!(tx_validator.validate(&tx), Ok(())); @@ -394,7 +394,7 @@ fn test_declare_contract_class_size_too_long() { ..*DEFAULT_VALIDATOR_CONFIG_FOR_TESTING }, }; - let contract_class = ContractClass { + let contract_class = SierraContractClass { sierra_program: create_sierra_program(&MIN_SIERRA_VERSION), ..Default::default() }; @@ -458,7 +458,7 @@ fn test_declare_entry_points_not_sorted_by_selector( let tx_validator = StatelessTransactionValidator { config: DEFAULT_VALIDATOR_CONFIG_FOR_TESTING.clone() }; - let contract_class = ContractClass { + let contract_class = SierraContractClass { sierra_program: create_sierra_program(&MIN_SIERRA_VERSION), entry_points_by_type: EntryPointByType { constructor: entry_points.clone(), @@ -471,7 +471,7 @@ fn test_declare_entry_points_not_sorted_by_selector( assert_eq!(tx_validator.validate(&tx), expected); - let contract_class = ContractClass { + let contract_class = SierraContractClass { sierra_program: create_sierra_program(&MIN_SIERRA_VERSION), entry_points_by_type: EntryPointByType { constructor: vec![], @@ -484,7 +484,7 @@ fn test_declare_entry_points_not_sorted_by_selector( assert_eq!(tx_validator.validate(&tx), expected); - let contract_class = ContractClass { + let contract_class = SierraContractClass { sierra_program: create_sierra_program(&MIN_SIERRA_VERSION), entry_points_by_type: EntryPointByType { constructor: vec![], diff --git a/crates/starknet_gateway/src/test_utils.rs b/crates/starknet_gateway/src/test_utils.rs index d8866fdffe..f92bb5bce8 100644 --- a/crates/starknet_gateway/src/test_utils.rs +++ b/crates/starknet_gateway/src/test_utils.rs @@ -2,7 +2,8 @@ use starknet_api::block::GasPrice; use starknet_api::core::ContractAddress; use starknet_api::data_availability::DataAvailabilityMode; use starknet_api::execution_resources::GasAmount; -use starknet_api::rpc_transaction::{ContractClass, RpcTransaction}; +use starknet_api::rpc_transaction::RpcTransaction; +use starknet_api::state::SierraContractClass; use starknet_api::test_utils::declare::{rpc_declare_tx, TEST_SENDER_ADDRESS}; use starknet_api::test_utils::deploy_account::rpc_deploy_account_tx; use starknet_api::test_utils::invoke::rpc_invoke_tx; @@ -89,7 +90,7 @@ pub fn rpc_tx_for_testing( match tx_type { TransactionType::Declare => { // Minimal contract class. - let contract_class = ContractClass { + let contract_class = SierraContractClass { sierra_program: vec![ // Sierra Version ID. felt!(1_u32), diff --git a/crates/starknet_sierra_compile/src/utils.rs b/crates/starknet_sierra_compile/src/utils.rs index e96d0ada5f..bc73f000bd 100644 --- a/crates/starknet_sierra_compile/src/utils.rs +++ b/crates/starknet_sierra_compile/src/utils.rs @@ -6,17 +6,17 @@ use cairo_lang_starknet_classes::contract_class::{ ContractEntryPoints as CairoLangContractEntryPoints, }; use cairo_lang_utils::bigint::BigUintAsHex; -use starknet_api::rpc_transaction::{ - ContractClass as RpcContractClass, - EntryPointByType as StarknetApiEntryPointByType, +use starknet_api::rpc_transaction::EntryPointByType as StarknetApiEntryPointByType; +use starknet_api::state::{ + EntryPoint as StarknetApiEntryPoint, + SierraContractClass as StarknetApiContractClass, }; -use starknet_api::state::EntryPoint as StarknetApiEntryPoint; use starknet_types_core::felt::Felt; /// Retruns a [`CairoLangContractClass`] struct ready for Sierra to Casm compilation. Note the `abi` /// field is None as it is not relevant for the compilation. pub fn into_contract_class_for_compilation( - rpc_contract_class: &RpcContractClass, + rpc_contract_class: &StarknetApiContractClass, ) -> CairoLangContractClass { let sierra_program = sierra_program_as_felts_to_big_uint_as_hex(&rpc_contract_class.sierra_program); From 8edd6d76af36f68328d4c5f841e97dcf28c7624f Mon Sep 17 00:00:00 2001 From: Yonatan-Starkware Date: Thu, 28 Nov 2024 10:53:47 +0200 Subject: [PATCH 05/25] feat(blockifier): add get_syscall_gas_cost to versioned constants impl (#2188) --- crates/blockifier/src/versioned_constants.rs | 30 +++++++++++++++++++ .../src/versioned_constants_test.rs | 22 ++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/crates/blockifier/src/versioned_constants.rs b/crates/blockifier/src/versioned_constants.rs index 6d18bca5e8..0ce942652a 100644 --- a/crates/blockifier/src/versioned_constants.rs +++ b/crates/blockifier/src/versioned_constants.rs @@ -26,6 +26,7 @@ use crate::execution::execution_utils::poseidon_hash_many_cost; use crate::execution::syscalls::SyscallSelector; use crate::fee::resources::StarknetResources; use crate::transaction::transaction_types::TransactionType; +use crate::utils::u64_from_usize; #[cfg(test)] #[path = "versioned_constants_test.rs"] @@ -347,6 +348,35 @@ impl VersionedConstants { GasVectorComputationMode::NoL2Gas => &self.deprecated_l2_resource_gas_costs, } } + + /// Calculates the syscall gas cost from the OS resources. + pub fn get_syscall_gas_cost(&self, syscall_selector: &SyscallSelector) -> u64 { + let gas_costs = &self.os_constants.gas_costs; + let execution_resources = &self + .os_resources + .execute_syscalls + .get(syscall_selector) + .expect("Fetching the execution resources of a syscall should not fail."); + let n_steps = u64_from_usize(execution_resources.n_steps); + let n_memory_holes = u64_from_usize(execution_resources.n_memory_holes); + let total_builtin_gas_cost: u64 = execution_resources + .builtin_instance_counter + .iter() + .map(|(builtin, amount)| { + let builtin_cost = gas_costs + .get_builtin_gas_cost(builtin) + .unwrap_or_else(|err| panic!("Failed to get gas cost: {}", err)); + builtin_cost * u64_from_usize(*amount) + }) + .sum(); + // The minimum total cost is `syscall_base_gas_cost`, which is pre-charged by the compiler. + std::cmp::max( + n_steps * gas_costs.step_gas_cost + + n_memory_holes * gas_costs.memory_hole_gas_cost + + total_builtin_gas_cost, + gas_costs.syscall_base_gas_cost, + ) + } } #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)] diff --git a/crates/blockifier/src/versioned_constants_test.rs b/crates/blockifier/src/versioned_constants_test.rs index 7947afc52a..4f281f71af 100644 --- a/crates/blockifier/src/versioned_constants_test.rs +++ b/crates/blockifier/src/versioned_constants_test.rs @@ -167,3 +167,25 @@ fn test_all_jsons_in_enum() { fn test_latest_no_panic() { VersionedConstants::latest_constants(); } + +#[test] +fn test_syscall_gas_cost_calculation() { + const EXPECTED_CALL_CONTRACT_GAS_COST: u64 = 87650; + const EXPECTED_SECP256K1MUL_GAS_COST: u64 = 8143650; + const EXPECTED_SHA256PROCESSBLOCK_GAS_COST: u64 = 841095; + + let versioned_constants = VersionedConstants::latest_constants().clone(); + + assert_eq!( + versioned_constants.get_syscall_gas_cost(&SyscallSelector::CallContract), + EXPECTED_CALL_CONTRACT_GAS_COST + ); + assert_eq!( + versioned_constants.get_syscall_gas_cost(&SyscallSelector::Secp256k1Mul), + EXPECTED_SECP256K1MUL_GAS_COST + ); + assert_eq!( + versioned_constants.get_syscall_gas_cost(&SyscallSelector::Sha256ProcessBlock), + EXPECTED_SHA256PROCESSBLOCK_GAS_COST + ); +} From 46ca92494ae4c5757ff71d1b1501f848ca1ac817 Mon Sep 17 00:00:00 2001 From: aner-starkware <147302140+aner-starkware@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:06:07 +0200 Subject: [PATCH 06/25] refactor(blockifier_reexecution): move reexecution test to separate file (#2304) --- .../workflows/blockifier_reexecution_ci.yml | 2 +- .../src/state_reader.rs | 3 ++- .../src/state_reader/raw_rpc_json_test.rs | 21 +----------------- .../src/state_reader/reexecution_test.rs | 22 +++++++++++++++++++ 4 files changed, 26 insertions(+), 22 deletions(-) create mode 100644 crates/blockifier_reexecution/src/state_reader/reexecution_test.rs diff --git a/.github/workflows/blockifier_reexecution_ci.yml b/.github/workflows/blockifier_reexecution_ci.yml index 36b3c65875..6dde67dd70 100644 --- a/.github/workflows/blockifier_reexecution_ci.yml +++ b/.github/workflows/blockifier_reexecution_ci.yml @@ -41,4 +41,4 @@ jobs: # Run blockifier re-execution tests. - run: cargo test --release -p blockifier_reexecution -- --include-ignored # Compile the rpc-tests, without running them. - - run: cargo test -p blockifier_reexecution --features blockifier_regression_https_testing --no-run + - run: cargo test --release -p blockifier_reexecution --features blockifier_regression_https_testing --no-run diff --git a/crates/blockifier_reexecution/src/state_reader.rs b/crates/blockifier_reexecution/src/state_reader.rs index eadb24337f..8b5cb9b259 100644 --- a/crates/blockifier_reexecution/src/state_reader.rs +++ b/crates/blockifier_reexecution/src/state_reader.rs @@ -4,7 +4,8 @@ mod errors; pub mod raw_rpc_json_test; pub mod reexecution_state_reader; #[cfg(test)] -#[cfg(feature = "blockifier_regression_https_testing")] +pub mod reexecution_test; +#[cfg(all(test, feature = "blockifier_regression_https_testing"))] pub mod rpc_https_test; pub mod serde_utils; pub mod test_state_reader; diff --git a/crates/blockifier_reexecution/src/state_reader/raw_rpc_json_test.rs b/crates/blockifier_reexecution/src/state_reader/raw_rpc_json_test.rs index a1d10da6cb..0fdd100f81 100644 --- a/crates/blockifier_reexecution/src/state_reader/raw_rpc_json_test.rs +++ b/crates/blockifier_reexecution/src/state_reader/raw_rpc_json_test.rs @@ -19,7 +19,7 @@ use starknet_gateway::rpc_objects::BlockHeader; use crate::state_reader::compile::legacy_to_contract_class_v0; use crate::state_reader::serde_utils::deserialize_transaction_json_to_starknet_api_tx; -use crate::state_reader::utils::{reexecute_block_for_testing, ReexecutionStateMaps}; +use crate::state_reader::utils::ReexecutionStateMaps; #[fixture] fn block_header() -> BlockHeader { @@ -162,22 +162,3 @@ fn serialize_state_maps() { assert_eq!(serializable_state_maps, deserialized_state_maps); assert_eq!(original_state_maps, deserialized_state_maps.try_into().unwrap()); } - -#[rstest] -#[case::v_0_13_0(600001)] -#[case::v_0_13_1(620978)] -#[case::v_0_13_1_1(649367)] -#[case::v_0_13_2(685878)] -#[case::v_0_13_2_1(700000)] -#[case::invoke_with_replace_class_syscall(780008)] -#[case::invoke_with_deploy_syscall(870136)] -#[case::example_deploy_account_v1(837408)] -#[case::example_deploy_account_v3(837792)] -#[case::example_declare_v1(837461)] -#[case::example_declare_v2(822636)] -#[case::example_declare_v3(825013)] -#[case::example_l1_handler(868429)] -#[ignore = "Requires downloading JSON files prior to running; Long test, run with --release flag."] -fn test_block_reexecution(#[case] block_number: u64) { - reexecute_block_for_testing(block_number); -} diff --git a/crates/blockifier_reexecution/src/state_reader/reexecution_test.rs b/crates/blockifier_reexecution/src/state_reader/reexecution_test.rs new file mode 100644 index 0000000000..ac9e97a786 --- /dev/null +++ b/crates/blockifier_reexecution/src/state_reader/reexecution_test.rs @@ -0,0 +1,22 @@ +use rstest::rstest; + +use crate::state_reader::utils::reexecute_block_for_testing; + +#[rstest] +#[case::v_0_13_0(600001)] +#[case::v_0_13_1(620978)] +#[case::v_0_13_1_1(649367)] +#[case::v_0_13_2(685878)] +#[case::v_0_13_2_1(700000)] +#[case::invoke_with_replace_class_syscall(780008)] +#[case::invoke_with_deploy_syscall(870136)] +#[case::example_deploy_account_v1(837408)] +#[case::example_deploy_account_v3(837792)] +#[case::example_declare_v1(837461)] +#[case::example_declare_v2(822636)] +#[case::example_declare_v3(825013)] +#[case::example_l1_handler(868429)] +#[ignore = "Requires downloading JSON files prior to running; Long test, run with --release flag."] +fn test_block_reexecution(#[case] block_number: u64) { + reexecute_block_for_testing(block_number); +} From 23231e473f6a0af25e233959360ab3f988b3ed15 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 28 Nov 2024 11:15:32 +0200 Subject: [PATCH 07/25] chore(blockifier): separate create and validate logic on gas prices (#2243) --- crates/blockifier/src/blockifier/block.rs | 44 +++++++++++-------- crates/blockifier/src/fee/fee_test.rs | 6 +-- .../blockifier/src/test_utils/struct_impls.rs | 2 +- crates/native_blockifier/src/py_state_diff.rs | 2 +- crates/papyrus_execution/src/lib.rs | 2 +- crates/starknet_batcher/src/block_builder.rs | 2 +- crates/starknet_gateway/src/rpc_objects.rs | 2 +- 7 files changed, 34 insertions(+), 26 deletions(-) diff --git a/crates/blockifier/src/blockifier/block.rs b/crates/blockifier/src/blockifier/block.rs index 83aca48b1c..760afc8861 100644 --- a/crates/blockifier/src/blockifier/block.rs +++ b/crates/blockifier/src/blockifier/block.rs @@ -35,40 +35,45 @@ pub struct BlockInfo { #[cfg_attr(feature = "transaction_serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Clone, Debug)] pub struct GasPrices { - eth_gas_prices: GasPriceVector, // In wei. - strk_gas_prices: GasPriceVector, // In fri. + pub eth_gas_prices: GasPriceVector, // In wei. + pub strk_gas_prices: GasPriceVector, // In fri. } impl GasPrices { - pub fn new( - eth_l1_gas_price: NonzeroGasPrice, - strk_l1_gas_price: NonzeroGasPrice, - eth_l1_data_gas_price: NonzeroGasPrice, - strk_l1_data_gas_price: NonzeroGasPrice, - eth_l2_gas_price: NonzeroGasPrice, - strk_l2_gas_price: NonzeroGasPrice, - ) -> Self { + /// Warns if the submitted gas prices do not match the expected gas prices. + fn validate_l2_gas_price(&self) { // TODO(Aner): fix backwards compatibility. + let eth_l2_gas_price = self.eth_gas_prices.l2_gas_price; let expected_eth_l2_gas_price = VersionedConstants::latest_constants() - .convert_l1_to_l2_gas_price_round_up(eth_l1_gas_price.into()); + .convert_l1_to_l2_gas_price_round_up(self.eth_gas_prices.l1_gas_price.into()); if GasPrice::from(eth_l2_gas_price) != expected_eth_l2_gas_price { // TODO!(Aner): change to panic! Requires fixing several tests. warn!( - "eth_l2_gas_price {eth_l2_gas_price} does not match expected eth_l2_gas_price \ - {expected_eth_l2_gas_price}." + "eth_l2_gas_price {} does not match expected eth_l2_gas_price {}.", + eth_l2_gas_price, expected_eth_l2_gas_price ) } + let strk_l2_gas_price = self.strk_gas_prices.l2_gas_price; let expected_strk_l2_gas_price = VersionedConstants::latest_constants() - .convert_l1_to_l2_gas_price_round_up(strk_l1_gas_price.into()); + .convert_l1_to_l2_gas_price_round_up(self.strk_gas_prices.l1_gas_price.into()); if GasPrice::from(strk_l2_gas_price) != expected_strk_l2_gas_price { // TODO!(Aner): change to panic! Requires fixing test_discounted_gas_overdraft warn!( - "strk_l2_gas_price {strk_l2_gas_price} does not match expected strk_l2_gas_price \ - {expected_strk_l2_gas_price}." + "strk_l2_gas_price {} does not match expected strk_l2_gas_price {}.", + strk_l2_gas_price, expected_strk_l2_gas_price ) } + } - Self { + pub fn validated_new( + eth_l1_gas_price: NonzeroGasPrice, + strk_l1_gas_price: NonzeroGasPrice, + eth_l1_data_gas_price: NonzeroGasPrice, + strk_l1_data_gas_price: NonzeroGasPrice, + eth_l2_gas_price: NonzeroGasPrice, + strk_l2_gas_price: NonzeroGasPrice, + ) -> Self { + let gas_prices = Self { eth_gas_prices: GasPriceVector { l1_gas_price: eth_l1_gas_price, l1_data_gas_price: eth_l1_data_gas_price, @@ -79,7 +84,10 @@ impl GasPrices { l1_data_gas_price: strk_l1_data_gas_price, l2_gas_price: strk_l2_gas_price, }, - } + }; + gas_prices.validate_l2_gas_price(); + + gas_prices } pub fn get_l1_gas_price_by_fee_type(&self, fee_type: &FeeType) -> NonzeroGasPrice { diff --git a/crates/blockifier/src/fee/fee_test.rs b/crates/blockifier/src/fee/fee_test.rs index e96f443431..2d090a7871 100644 --- a/crates/blockifier/src/fee/fee_test.rs +++ b/crates/blockifier/src/fee/fee_test.rs @@ -178,7 +178,7 @@ fn test_discounted_gas_overdraft( NonzeroGasPrice::try_from(data_gas_price).unwrap(), ); let mut block_context = BlockContext::create_for_account_testing(); - block_context.block_info.gas_prices = GasPrices::new( + block_context.block_info.gas_prices = GasPrices::validated_new( DEFAULT_ETH_L1_GAS_PRICE, gas_price, DEFAULT_ETH_L1_DATA_GAS_PRICE, @@ -313,7 +313,7 @@ fn test_get_fee_by_gas_vector_regression( #[case] expected_fee_strk: u128, ) { let mut block_info = BlockContext::create_for_account_testing().block_info; - block_info.gas_prices = GasPrices::new( + block_info.gas_prices = GasPrices::validated_new( 1_u8.try_into().unwrap(), 2_u8.try_into().unwrap(), 3_u8.try_into().unwrap(), @@ -347,7 +347,7 @@ fn test_get_fee_by_gas_vector_overflow( ) { let huge_gas_price = NonzeroGasPrice::try_from(2_u128 * u128::from(u64::MAX)).unwrap(); let mut block_info = BlockContext::create_for_account_testing().block_info; - block_info.gas_prices = GasPrices::new( + block_info.gas_prices = GasPrices::validated_new( huge_gas_price, huge_gas_price, huge_gas_price, diff --git a/crates/blockifier/src/test_utils/struct_impls.rs b/crates/blockifier/src/test_utils/struct_impls.rs index dee7020eac..af42fb4eb8 100644 --- a/crates/blockifier/src/test_utils/struct_impls.rs +++ b/crates/blockifier/src/test_utils/struct_impls.rs @@ -152,7 +152,7 @@ impl BlockInfo { block_number: BlockNumber(CURRENT_BLOCK_NUMBER), block_timestamp: BlockTimestamp(CURRENT_BLOCK_TIMESTAMP), sequencer_address: contract_address!(TEST_SEQUENCER_ADDRESS), - gas_prices: GasPrices::new( + gas_prices: GasPrices::validated_new( DEFAULT_ETH_L1_GAS_PRICE, DEFAULT_STRK_L1_GAS_PRICE, DEFAULT_ETH_L1_DATA_GAS_PRICE, diff --git a/crates/native_blockifier/src/py_state_diff.rs b/crates/native_blockifier/src/py_state_diff.rs index 70f15e98e3..6a78360363 100644 --- a/crates/native_blockifier/src/py_state_diff.rs +++ b/crates/native_blockifier/src/py_state_diff.rs @@ -182,7 +182,7 @@ impl TryFrom for BlockInfo { block_number: BlockNumber(block_info.block_number), block_timestamp: BlockTimestamp(block_info.block_timestamp), sequencer_address: ContractAddress::try_from(block_info.sequencer_address.0)?, - gas_prices: GasPrices::new( + gas_prices: GasPrices::validated_new( NonzeroGasPrice::try_from(block_info.l1_gas_price.price_in_wei).map_err(|_| { NativeBlockifierInputError::InvalidNativeBlockifierInputError( InvalidNativeBlockifierInputError::InvalidL1GasPriceWei( diff --git a/crates/papyrus_execution/src/lib.rs b/crates/papyrus_execution/src/lib.rs index 4e7fada6bd..d997f58f04 100644 --- a/crates/papyrus_execution/src/lib.rs +++ b/crates/papyrus_execution/src/lib.rs @@ -369,7 +369,7 @@ fn create_block_context( use_kzg_da, block_number, // TODO(yair): What to do about blocks pre 0.13.1 where the data gas price were 0? - gas_prices: GasPrices::new( + gas_prices: GasPrices::validated_new( NonzeroGasPrice::new(l1_gas_price.price_in_wei).unwrap_or(NonzeroGasPrice::MIN), NonzeroGasPrice::new(l1_gas_price.price_in_fri).unwrap_or(NonzeroGasPrice::MIN), NonzeroGasPrice::new(l1_data_gas_price.price_in_wei).unwrap_or(NonzeroGasPrice::MIN), diff --git a/crates/starknet_batcher/src/block_builder.rs b/crates/starknet_batcher/src/block_builder.rs index ecb944c347..94a8fbb69a 100644 --- a/crates/starknet_batcher/src/block_builder.rs +++ b/crates/starknet_batcher/src/block_builder.rs @@ -312,7 +312,7 @@ impl BlockBuilderFactory { // TODO (yael 7/10/2024): add logic to compute gas prices gas_prices: { let tmp_val = NonzeroGasPrice::MIN; - GasPrices::new(tmp_val, tmp_val, tmp_val, tmp_val, tmp_val, tmp_val) + GasPrices::validated_new(tmp_val, tmp_val, tmp_val, tmp_val, tmp_val, tmp_val) }, use_kzg_da: block_builder_config.use_kzg_da, }; diff --git a/crates/starknet_gateway/src/rpc_objects.rs b/crates/starknet_gateway/src/rpc_objects.rs index f9b7d17cc2..1209a4f459 100644 --- a/crates/starknet_gateway/src/rpc_objects.rs +++ b/crates/starknet_gateway/src/rpc_objects.rs @@ -86,7 +86,7 @@ impl TryInto for BlockHeader { block_number: self.block_number, sequencer_address: self.sequencer_address, block_timestamp: self.timestamp, - gas_prices: GasPrices::new( + gas_prices: GasPrices::validated_new( parse_gas_price(self.l1_gas_price.price_in_wei)?, parse_gas_price(self.l1_gas_price.price_in_fri)?, parse_gas_price(self.l1_data_gas_price.price_in_wei)?, From 48037a7e3e8e9a240e33db85064885aac24bf65e Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 28 Nov 2024 11:39:47 +0200 Subject: [PATCH 08/25] chore(blockifier): rename the getters for the gas prices struct (#2269) --- crates/blockifier/src/blockifier/block.rs | 14 +++++++------- crates/blockifier/src/context.rs | 5 +---- crates/blockifier/src/execution/entry_point.rs | 6 +++--- crates/blockifier/src/fee/fee_utils.rs | 2 +- .../src/transaction/account_transaction.rs | 4 ++-- .../transaction/account_transactions_test.rs | 17 +++++++---------- .../src/transaction/execution_flavors_test.rs | 8 ++++---- .../src/transaction/post_execution_test.rs | 2 +- .../src/transaction/transactions_test.rs | 11 +++++------ crates/papyrus_execution/src/objects.rs | 6 +++--- 10 files changed, 34 insertions(+), 41 deletions(-) diff --git a/crates/blockifier/src/blockifier/block.rs b/crates/blockifier/src/blockifier/block.rs index 760afc8861..05ee20a2f4 100644 --- a/crates/blockifier/src/blockifier/block.rs +++ b/crates/blockifier/src/blockifier/block.rs @@ -90,19 +90,19 @@ impl GasPrices { gas_prices } - pub fn get_l1_gas_price_by_fee_type(&self, fee_type: &FeeType) -> NonzeroGasPrice { - self.get_gas_prices_by_fee_type(fee_type).l1_gas_price + pub fn l1_gas_price(&self, fee_type: &FeeType) -> NonzeroGasPrice { + self.gas_price_vector(fee_type).l1_gas_price } - pub fn get_l1_data_gas_price_by_fee_type(&self, fee_type: &FeeType) -> NonzeroGasPrice { - self.get_gas_prices_by_fee_type(fee_type).l1_data_gas_price + pub fn l1_data_gas_price(&self, fee_type: &FeeType) -> NonzeroGasPrice { + self.gas_price_vector(fee_type).l1_data_gas_price } - pub fn get_l2_gas_price_by_fee_type(&self, fee_type: &FeeType) -> NonzeroGasPrice { - self.get_gas_prices_by_fee_type(fee_type).l2_gas_price + pub fn l2_gas_price(&self, fee_type: &FeeType) -> NonzeroGasPrice { + self.gas_price_vector(fee_type).l2_gas_price } - pub fn get_gas_prices_by_fee_type(&self, fee_type: &FeeType) -> &GasPriceVector { + pub fn gas_price_vector(&self, fee_type: &FeeType) -> &GasPriceVector { match fee_type { FeeType::Strk => &self.strk_gas_prices, FeeType::Eth => &self.eth_gas_prices, diff --git a/crates/blockifier/src/context.rs b/crates/blockifier/src/context.rs index e77c5e0382..5c6700b9d0 100644 --- a/crates/blockifier/src/context.rs +++ b/crates/blockifier/src/context.rs @@ -39,10 +39,7 @@ impl TransactionContext { self.tx_info.gas_mode() } pub fn get_gas_prices(&self) -> &GasPriceVector { - self.block_context - .block_info - .gas_prices - .get_gas_prices_by_fee_type(&self.tx_info.fee_type()) + self.block_context.block_info.gas_prices.gas_price_vector(&self.tx_info.fee_type()) } /// Returns the initial Sierra gas of the transaction. diff --git a/crates/blockifier/src/execution/entry_point.rs b/crates/blockifier/src/execution/entry_point.rs index 39fd2fa42e..b977f57239 100644 --- a/crates/blockifier/src/execution/entry_point.rs +++ b/crates/blockifier/src/execution/entry_point.rs @@ -293,9 +293,9 @@ impl EntryPointExecutionContext { if l1_gas_per_step.is_zero() { u64::MAX } else { - let induced_l1_gas_limit = context.max_fee.saturating_div( - block_info.gas_prices.get_l1_gas_price_by_fee_type(&tx_info.fee_type()), - ); + let induced_l1_gas_limit = context + .max_fee + .saturating_div(block_info.gas_prices.l1_gas_price(&tx_info.fee_type())); (l1_gas_per_step.inv() * induced_l1_gas_limit.0).to_integer() } } diff --git a/crates/blockifier/src/fee/fee_utils.rs b/crates/blockifier/src/fee/fee_utils.rs index 89a3685f3e..e217d3d6b2 100644 --- a/crates/blockifier/src/fee/fee_utils.rs +++ b/crates/blockifier/src/fee/fee_utils.rs @@ -79,7 +79,7 @@ pub fn get_fee_by_gas_vector( gas_vector: GasVector, fee_type: &FeeType, ) -> Fee { - gas_vector.cost(block_info.gas_prices.get_gas_prices_by_fee_type(fee_type)) + gas_vector.cost(block_info.gas_prices.gas_price_vector(fee_type)) } /// Returns the current fee balance and a boolean indicating whether the balance covers the fee. diff --git a/crates/blockifier/src/transaction/account_transaction.rs b/crates/blockifier/src/transaction/account_transaction.rs index 4c2c4a8731..ca61f75576 100644 --- a/crates/blockifier/src/transaction/account_transaction.rs +++ b/crates/blockifier/src/transaction/account_transaction.rs @@ -288,7 +288,7 @@ impl AccountTransaction { L1Gas, l1_gas_resource_bounds, minimal_gas_amount_vector.to_discounted_l1_gas(tx_context.get_gas_prices()), - block_info.gas_prices.get_l1_gas_price_by_fee_type(fee_type), + block_info.gas_prices.l1_gas_price(fee_type), )], ValidResourceBounds::AllResources(AllResourceBounds { l1_gas: l1_gas_resource_bounds, @@ -296,7 +296,7 @@ impl AccountTransaction { l1_data_gas: l1_data_gas_resource_bounds, }) => { let GasPriceVector { l1_gas_price, l1_data_gas_price, l2_gas_price } = - block_info.gas_prices.get_gas_prices_by_fee_type(fee_type); + block_info.gas_prices.gas_price_vector(fee_type); vec![ ( L1Gas, diff --git a/crates/blockifier/src/transaction/account_transactions_test.rs b/crates/blockifier/src/transaction/account_transactions_test.rs index 5870922b47..8f901664bf 100644 --- a/crates/blockifier/src/transaction/account_transactions_test.rs +++ b/crates/blockifier/src/transaction/account_transactions_test.rs @@ -548,13 +548,13 @@ fn test_max_fee_limit_validate( GasVectorComputationMode::All => create_all_resource_bounds( estimated_min_gas_usage_vector.l1_gas, block_info.gas_prices - .get_l1_gas_price_by_fee_type(&account_tx.fee_type()).into(), + .l1_gas_price(&account_tx.fee_type()).into(), estimated_min_gas_usage_vector.l2_gas, block_info.gas_prices - .get_l2_gas_price_by_fee_type(&account_tx.fee_type()).into(), + .l2_gas_price(&account_tx.fee_type()).into(), estimated_min_gas_usage_vector.l1_data_gas, block_info.gas_prices - .get_l1_data_gas_price_by_fee_type(&account_tx.fee_type()).into(), + .l1_data_gas_price(&account_tx.fee_type()).into(), ), }, ..tx_args @@ -1052,9 +1052,7 @@ fn test_max_fee_computation_from_tx_bounds(block_context: BlockContext) { account_tx_max_fee, (steps_per_l1_gas * max_fee - .checked_div( - block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&FeeType::Eth), - ) + .checked_div(block_context.block_info.gas_prices.eth_gas_prices.l1_gas_price,) .unwrap() .0) .to_integer(), @@ -1108,8 +1106,7 @@ fn test_max_fee_to_max_steps_conversion( ) .into(); let actual_fee = u128::from(actual_gas_used.0) * 100000000000; - let actual_strk_gas_price = - block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&FeeType::Strk); + let actual_strk_gas_price = block_context.block_info.gas_prices.strk_gas_prices.l1_gas_price; let execute_calldata = create_calldata( contract_address, "with_arg", @@ -1205,11 +1202,11 @@ fn test_insufficient_max_fee_reverts( let resource_used_depth1 = match gas_mode { GasVectorComputationMode::NoL2Gas => l1_resource_bounds( tx_execution_info1.receipt.gas.l1_gas, - block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&FeeType::Strk).into(), + block_context.block_info.gas_prices.strk_gas_prices.l1_gas_price.into(), ), GasVectorComputationMode::All => ValidResourceBounds::all_bounds_from_vectors( &tx_execution_info1.receipt.gas, - block_context.block_info.gas_prices.get_gas_prices_by_fee_type(&FeeType::Strk), + &block_context.block_info.gas_prices.strk_gas_prices, ), }; let tx_execution_info2 = run_invoke_tx( diff --git a/crates/blockifier/src/transaction/execution_flavors_test.rs b/crates/blockifier/src/transaction/execution_flavors_test.rs index 3f6a43b4d1..edf7058021 100644 --- a/crates/blockifier/src/transaction/execution_flavors_test.rs +++ b/crates/blockifier/src/transaction/execution_flavors_test.rs @@ -291,7 +291,7 @@ fn test_simulate_validate_pre_validate_with_charge_fee( } // Second scenario: resource bounds greater than balance. - let gas_price = block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&fee_type); + let gas_price = block_context.block_info.gas_prices.l1_gas_price(&fee_type); let balance_over_gas_price = BALANCE.checked_div(gas_price).unwrap(); let result = account_invoke_tx(invoke_tx_args! { max_fee: Fee(BALANCE.0 + 1), @@ -409,7 +409,7 @@ fn test_simulate_validate_pre_validate_not_charge_fee( execute_and_check_gas_and_fee!(Fee(10), l1_resource_bounds(10_u8.into(), 10_u8.into())); // Second scenario: resource bounds greater than balance. - let gas_price = block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&fee_type); + let gas_price = block_context.block_info.gas_prices.l1_gas_price(&fee_type); let balance_over_gas_price = BALANCE.checked_div(gas_price).unwrap(); execute_and_check_gas_and_fee!( Fee(BALANCE.0 + 1), @@ -548,7 +548,7 @@ fn test_simulate_validate_charge_fee_mid_execution( ) { let block_context = BlockContext::create_for_account_testing(); let chain_info = &block_context.chain_info; - let gas_price = block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&fee_type); + let gas_price = block_context.block_info.gas_prices.l1_gas_price(&fee_type); let FlavorTestInitialState { mut state, account_address, @@ -714,7 +714,7 @@ fn test_simulate_validate_charge_fee_post_execution( #[case] is_deprecated: bool, ) { let block_context = BlockContext::create_for_account_testing(); - let gas_price = block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&fee_type); + let gas_price = block_context.block_info.gas_prices.l1_gas_price(&fee_type); let chain_info = &block_context.chain_info; let fee_token_address = chain_info.fee_token_address(&fee_type); diff --git a/crates/blockifier/src/transaction/post_execution_test.rs b/crates/blockifier/src/transaction/post_execution_test.rs index 3ac147f0a3..2b93fc5bc0 100644 --- a/crates/blockifier/src/transaction/post_execution_test.rs +++ b/crates/blockifier/src/transaction/post_execution_test.rs @@ -269,7 +269,7 @@ fn test_revert_on_resource_overuse( block_context.block_info.use_kzg_da = true; let gas_mode = resource_bounds.get_gas_vector_computation_mode(); let fee_type = if version == TransactionVersion::THREE { FeeType::Strk } else { FeeType::Eth }; - let gas_prices = block_context.block_info.gas_prices.get_gas_prices_by_fee_type(&fee_type); + let gas_prices = block_context.block_info.gas_prices.gas_price_vector(&fee_type); let TestInitData { mut state, account_address, contract_address, mut nonce_manager } = init_data_by_version(&block_context.chain_info, cairo_version); diff --git a/crates/blockifier/src/transaction/transactions_test.rs b/crates/blockifier/src/transaction/transactions_test.rs index 648725249f..1d69557692 100644 --- a/crates/blockifier/src/transaction/transactions_test.rs +++ b/crates/blockifier/src/transaction/transactions_test.rs @@ -1083,7 +1083,7 @@ fn test_insufficient_new_resource_bounds_pre_validation( l1_gas_price: actual_strk_l1_gas_price, l1_data_gas_price: actual_strk_l1_data_gas_price, l2_gas_price: actual_strk_l2_gas_price, - } = block_context.block_info.gas_prices.get_gas_prices_by_fee_type(&FeeType::Strk); + } = block_context.block_info.gas_prices.strk_gas_prices; let minimal_gas_vector = estimate_minimal_gas_vector(block_context, tx, &GasVectorComputationMode::All); @@ -1217,9 +1217,8 @@ fn test_insufficient_deprecated_resource_bounds_pre_validation( let gas_prices = &block_context.block_info.gas_prices; // TODO(Aner, 21/01/24) change to linear combination. - let minimal_fee = minimal_l1_gas - .checked_mul(gas_prices.get_l1_gas_price_by_fee_type(&FeeType::Eth).into()) - .unwrap(); + let minimal_fee = + minimal_l1_gas.checked_mul(gas_prices.eth_gas_prices.l1_gas_price.get()).unwrap(); // Max fee too low (lower than minimal estimated fee). let invalid_max_fee = Fee(minimal_fee.0 - 1); let invalid_v1_tx = account_invoke_tx( @@ -1237,7 +1236,7 @@ fn test_insufficient_deprecated_resource_bounds_pre_validation( ); // Test V3 transaction. - let actual_strk_l1_gas_price = gas_prices.get_l1_gas_price_by_fee_type(&FeeType::Strk); + let actual_strk_l1_gas_price = gas_prices.strk_gas_prices.l1_gas_price; // Max L1 gas amount too low, old resource bounds. // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion works. @@ -1291,7 +1290,7 @@ fn test_actual_fee_gt_resource_bounds( block_context.block_info.use_kzg_da = true; let mut nonce_manager = NonceManager::default(); let gas_mode = resource_bounds.get_gas_vector_computation_mode(); - let gas_prices = block_context.block_info.gas_prices.get_gas_prices_by_fee_type(&FeeType::Strk); + let gas_prices = &block_context.block_info.gas_prices.strk_gas_prices; let account_contract = FeatureContract::AccountWithoutValidations(account_cairo_version); let test_contract = FeatureContract::TestContract(CairoVersion::Cairo0); let state = &mut test_state( diff --git a/crates/papyrus_execution/src/objects.rs b/crates/papyrus_execution/src/objects.rs index f80ab9e6c2..d44c769310 100644 --- a/crates/papyrus_execution/src/objects.rs +++ b/crates/papyrus_execution/src/objects.rs @@ -164,9 +164,9 @@ pub(crate) fn tx_execution_output_to_fee_estimation( ) -> ExecutionResult { let gas_prices = &block_context.block_info().gas_prices; let (l1_gas_price, l1_data_gas_price, l2_gas_price) = ( - gas_prices.get_l1_gas_price_by_fee_type(&tx_execution_output.price_unit.into()).get(), - gas_prices.get_l1_data_gas_price_by_fee_type(&tx_execution_output.price_unit.into()).get(), - gas_prices.get_l2_gas_price_by_fee_type(&tx_execution_output.price_unit.into()).get(), + gas_prices.l1_gas_price(&tx_execution_output.price_unit.into()).get(), + gas_prices.l1_data_gas_price(&tx_execution_output.price_unit.into()).get(), + gas_prices.l2_gas_price(&tx_execution_output.price_unit.into()).get(), ); let gas_vector = tx_execution_output.execution_info.receipt.gas; From 680df8d396d9dac32acc06a46ba798dd723c0055 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 28 Nov 2024 11:56:32 +0200 Subject: [PATCH 09/25] feat(blockifier): derive serialize for block info (#2244) --- crates/blockifier/src/blockifier/block.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/blockifier/src/blockifier/block.rs b/crates/blockifier/src/blockifier/block.rs index 05ee20a2f4..4d3304666e 100644 --- a/crates/blockifier/src/blockifier/block.rs +++ b/crates/blockifier/src/blockifier/block.rs @@ -1,4 +1,5 @@ use log::warn; +use serde::{Deserialize, Serialize}; use starknet_api::block::{ BlockHashAndNumber, BlockNumber, @@ -20,8 +21,7 @@ use crate::versioned_constants::VersionedConstants; #[path = "block_test.rs"] pub mod block_test; -#[cfg_attr(feature = "transaction_serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct BlockInfo { pub block_number: BlockNumber, pub block_timestamp: BlockTimestamp, @@ -32,8 +32,7 @@ pub struct BlockInfo { pub use_kzg_da: bool, } -#[cfg_attr(feature = "transaction_serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct GasPrices { pub eth_gas_prices: GasPriceVector, // In wei. pub strk_gas_prices: GasPriceVector, // In fri. From d7198bde269359b61df5c09a38b6abd0a9729331 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 28 Nov 2024 12:18:03 +0200 Subject: [PATCH 10/25] chore(blockifier): move GasPrices to snapi (#2245) --- crates/blockifier/src/blockifier/block.rs | 117 +++++++----------- .../src/concurrency/fee_utils_test.rs | 2 +- crates/blockifier/src/context.rs | 3 +- crates/blockifier/src/fee/fee_checks.rs | 3 +- crates/blockifier/src/fee/fee_test.rs | 11 +- crates/blockifier/src/fee/fee_utils.rs | 3 +- crates/blockifier/src/fee/gas_usage_test.rs | 3 +- .../src/test_utils/initial_test_state.rs | 2 +- crates/blockifier/src/test_utils/prices.rs | 2 +- .../blockifier/src/test_utils/struct_impls.rs | 4 +- .../transaction/account_transactions_test.rs | 4 +- .../src/transaction/execution_flavors_test.rs | 3 +- crates/blockifier/src/transaction/objects.rs | 8 +- .../src/transaction/post_execution_test.rs | 3 +- .../blockifier/src/transaction/test_utils.rs | 4 +- .../src/transaction/transactions_test.rs | 3 +- crates/native_blockifier/src/py_state_diff.rs | 4 +- crates/papyrus_execution/src/lib.rs | 4 +- crates/papyrus_execution/src/objects.rs | 4 +- crates/starknet_api/src/block.rs | 34 +++++ crates/starknet_batcher/src/block_builder.rs | 4 +- crates/starknet_gateway/src/rpc_objects.rs | 4 +- .../src/state_reader.rs | 2 +- 23 files changed, 116 insertions(+), 115 deletions(-) diff --git a/crates/blockifier/src/blockifier/block.rs b/crates/blockifier/src/blockifier/block.rs index 4d3304666e..59a8a1ec0f 100644 --- a/crates/blockifier/src/blockifier/block.rs +++ b/crates/blockifier/src/blockifier/block.rs @@ -6,6 +6,7 @@ use starknet_api::block::{ BlockTimestamp, GasPrice, GasPriceVector, + GasPrices, NonzeroGasPrice, }; use starknet_api::core::ContractAddress; @@ -14,7 +15,6 @@ use starknet_api::state::StorageKey; use crate::abi::constants; use crate::state::errors::StateError; use crate::state::state_api::{State, StateResult}; -use crate::transaction::objects::FeeType; use crate::versioned_constants::VersionedConstants; #[cfg(test)] @@ -32,81 +32,54 @@ pub struct BlockInfo { pub use_kzg_da: bool, } -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct GasPrices { - pub eth_gas_prices: GasPriceVector, // In wei. - pub strk_gas_prices: GasPriceVector, // In fri. -} - -impl GasPrices { - /// Warns if the submitted gas prices do not match the expected gas prices. - fn validate_l2_gas_price(&self) { - // TODO(Aner): fix backwards compatibility. - let eth_l2_gas_price = self.eth_gas_prices.l2_gas_price; - let expected_eth_l2_gas_price = VersionedConstants::latest_constants() - .convert_l1_to_l2_gas_price_round_up(self.eth_gas_prices.l1_gas_price.into()); - if GasPrice::from(eth_l2_gas_price) != expected_eth_l2_gas_price { - // TODO!(Aner): change to panic! Requires fixing several tests. - warn!( - "eth_l2_gas_price {} does not match expected eth_l2_gas_price {}.", - eth_l2_gas_price, expected_eth_l2_gas_price - ) - } - let strk_l2_gas_price = self.strk_gas_prices.l2_gas_price; - let expected_strk_l2_gas_price = VersionedConstants::latest_constants() - .convert_l1_to_l2_gas_price_round_up(self.strk_gas_prices.l1_gas_price.into()); - if GasPrice::from(strk_l2_gas_price) != expected_strk_l2_gas_price { - // TODO!(Aner): change to panic! Requires fixing test_discounted_gas_overdraft - warn!( - "strk_l2_gas_price {} does not match expected strk_l2_gas_price {}.", - strk_l2_gas_price, expected_strk_l2_gas_price - ) - } - } - - pub fn validated_new( - eth_l1_gas_price: NonzeroGasPrice, - strk_l1_gas_price: NonzeroGasPrice, - eth_l1_data_gas_price: NonzeroGasPrice, - strk_l1_data_gas_price: NonzeroGasPrice, - eth_l2_gas_price: NonzeroGasPrice, - strk_l2_gas_price: NonzeroGasPrice, - ) -> Self { - let gas_prices = Self { - eth_gas_prices: GasPriceVector { - l1_gas_price: eth_l1_gas_price, - l1_data_gas_price: eth_l1_data_gas_price, - l2_gas_price: eth_l2_gas_price, - }, - strk_gas_prices: GasPriceVector { - l1_gas_price: strk_l1_gas_price, - l1_data_gas_price: strk_l1_data_gas_price, - l2_gas_price: strk_l2_gas_price, - }, - }; - gas_prices.validate_l2_gas_price(); - - gas_prices +/// Warns if the submitted gas prices do not match the expected gas prices. +fn validate_l2_gas_price(gas_prices: &GasPrices) { + // TODO(Aner): fix backwards compatibility. + let eth_l2_gas_price = gas_prices.eth_gas_prices.l2_gas_price; + let expected_eth_l2_gas_price = VersionedConstants::latest_constants() + .convert_l1_to_l2_gas_price_round_up(gas_prices.eth_gas_prices.l1_gas_price.into()); + if GasPrice::from(eth_l2_gas_price) != expected_eth_l2_gas_price { + // TODO!(Aner): change to panic! Requires fixing several tests. + warn!( + "eth_l2_gas_price {} does not match expected eth_l2_gas_price {}.", + eth_l2_gas_price, expected_eth_l2_gas_price + ) } - - pub fn l1_gas_price(&self, fee_type: &FeeType) -> NonzeroGasPrice { - self.gas_price_vector(fee_type).l1_gas_price - } - - pub fn l1_data_gas_price(&self, fee_type: &FeeType) -> NonzeroGasPrice { - self.gas_price_vector(fee_type).l1_data_gas_price + let strk_l2_gas_price = gas_prices.strk_gas_prices.l2_gas_price; + let expected_strk_l2_gas_price = VersionedConstants::latest_constants() + .convert_l1_to_l2_gas_price_round_up(gas_prices.strk_gas_prices.l1_gas_price.into()); + if GasPrice::from(strk_l2_gas_price) != expected_strk_l2_gas_price { + // TODO!(Aner): change to panic! Requires fixing test_discounted_gas_overdraft + warn!( + "strk_l2_gas_price {} does not match expected strk_l2_gas_price {}.", + strk_l2_gas_price, expected_strk_l2_gas_price + ) } +} - pub fn l2_gas_price(&self, fee_type: &FeeType) -> NonzeroGasPrice { - self.gas_price_vector(fee_type).l2_gas_price - } +pub fn validated_gas_prices( + eth_l1_gas_price: NonzeroGasPrice, + strk_l1_gas_price: NonzeroGasPrice, + eth_l1_data_gas_price: NonzeroGasPrice, + strk_l1_data_gas_price: NonzeroGasPrice, + eth_l2_gas_price: NonzeroGasPrice, + strk_l2_gas_price: NonzeroGasPrice, +) -> GasPrices { + let gas_prices = GasPrices { + eth_gas_prices: GasPriceVector { + l1_gas_price: eth_l1_gas_price, + l1_data_gas_price: eth_l1_data_gas_price, + l2_gas_price: eth_l2_gas_price, + }, + strk_gas_prices: GasPriceVector { + l1_gas_price: strk_l1_gas_price, + l1_data_gas_price: strk_l1_data_gas_price, + l2_gas_price: strk_l2_gas_price, + }, + }; + validate_l2_gas_price(&gas_prices); - pub fn gas_price_vector(&self, fee_type: &FeeType) -> &GasPriceVector { - match fee_type { - FeeType::Strk => &self.strk_gas_prices, - FeeType::Eth => &self.eth_gas_prices, - } - } + gas_prices } // Block pre-processing. diff --git a/crates/blockifier/src/concurrency/fee_utils_test.rs b/crates/blockifier/src/concurrency/fee_utils_test.rs index d5884c4530..f136a8f491 100644 --- a/crates/blockifier/src/concurrency/fee_utils_test.rs +++ b/crates/blockifier/src/concurrency/fee_utils_test.rs @@ -1,5 +1,6 @@ use num_bigint::BigUint; use rstest::rstest; +use starknet_api::block::FeeType; use starknet_api::transaction::fields::{Fee, ValidResourceBounds}; use starknet_api::{felt, invoke_tx_args}; use starknet_types_core::felt::Felt; @@ -12,7 +13,6 @@ use crate::state::state_api::StateReader; use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::{fund_account, test_state, test_state_inner}; use crate::test_utils::{create_trivial_calldata, CairoVersion, BALANCE}; -use crate::transaction::objects::FeeType; use crate::transaction::test_utils::{ account_invoke_tx, block_context, diff --git a/crates/blockifier/src/context.rs b/crates/blockifier/src/context.rs index 5c6700b9d0..069fcb53e6 100644 --- a/crates/blockifier/src/context.rs +++ b/crates/blockifier/src/context.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use papyrus_config::dumping::{append_sub_config_name, ser_param, SerializeConfig}; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::{Deserialize, Serialize}; -use starknet_api::block::GasPriceVector; +use starknet_api::block::{FeeType, GasPriceVector}; use starknet_api::core::{ChainId, ContractAddress}; use starknet_api::transaction::fields::{ AllResourceBounds, @@ -15,7 +15,6 @@ use crate::blockifier::block::BlockInfo; use crate::bouncer::BouncerConfig; use crate::transaction::objects::{ CurrentTransactionInfo, - FeeType, HasRelatedFeeType, TransactionInfo, TransactionInfoCreator, diff --git a/crates/blockifier/src/fee/fee_checks.rs b/crates/blockifier/src/fee/fee_checks.rs index f5bc38a2bd..2657fffed8 100644 --- a/crates/blockifier/src/fee/fee_checks.rs +++ b/crates/blockifier/src/fee/fee_checks.rs @@ -1,3 +1,4 @@ +use starknet_api::block::FeeType; use starknet_api::execution_resources::{GasAmount, GasVector}; use starknet_api::transaction::fields::Resource::{self, L1DataGas, L1Gas, L2Gas}; use starknet_api::transaction::fields::{ @@ -14,7 +15,7 @@ use crate::fee::fee_utils::{get_balance_and_if_covers_fee, get_fee_by_gas_vector use crate::fee::receipt::TransactionReceipt; use crate::state::state_api::StateReader; use crate::transaction::errors::TransactionExecutionError; -use crate::transaction::objects::{FeeType, TransactionExecutionResult, TransactionInfo}; +use crate::transaction::objects::{TransactionExecutionResult, TransactionInfo}; #[cfg_attr(feature = "transaction_serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Clone, Copy, Debug, Error, PartialEq)] diff --git a/crates/blockifier/src/fee/fee_test.rs b/crates/blockifier/src/fee/fee_test.rs index 2d090a7871..98ad761ef4 100644 --- a/crates/blockifier/src/fee/fee_test.rs +++ b/crates/blockifier/src/fee/fee_test.rs @@ -1,7 +1,7 @@ use assert_matches::assert_matches; use cairo_vm::types::builtin_name::BuiltinName; use rstest::rstest; -use starknet_api::block::{GasPrice, NonzeroGasPrice}; +use starknet_api::block::{FeeType, GasPrice, NonzeroGasPrice}; use starknet_api::execution_resources::{GasAmount, GasVector}; use starknet_api::invoke_tx_args; use starknet_api::transaction::fields::{ @@ -13,7 +13,7 @@ use starknet_api::transaction::fields::{ ValidResourceBounds, }; -use crate::blockifier::block::GasPrices; +use crate::blockifier::block::validated_gas_prices; use crate::context::BlockContext; use crate::fee::fee_checks::{FeeCheckError, FeeCheckReportFields, PostExecutionReport}; use crate::fee::fee_utils::{get_fee_by_gas_vector, get_vm_resources_cost}; @@ -32,7 +32,6 @@ use crate::test_utils::{ DEFAULT_L2_GAS_MAX_AMOUNT, DEFAULT_STRK_L1_GAS_PRICE, }; -use crate::transaction::objects::FeeType; use crate::transaction::test_utils::{ account_invoke_tx, all_resource_bounds, @@ -178,7 +177,7 @@ fn test_discounted_gas_overdraft( NonzeroGasPrice::try_from(data_gas_price).unwrap(), ); let mut block_context = BlockContext::create_for_account_testing(); - block_context.block_info.gas_prices = GasPrices::validated_new( + block_context.block_info.gas_prices = validated_gas_prices( DEFAULT_ETH_L1_GAS_PRICE, gas_price, DEFAULT_ETH_L1_DATA_GAS_PRICE, @@ -313,7 +312,7 @@ fn test_get_fee_by_gas_vector_regression( #[case] expected_fee_strk: u128, ) { let mut block_info = BlockContext::create_for_account_testing().block_info; - block_info.gas_prices = GasPrices::validated_new( + block_info.gas_prices = validated_gas_prices( 1_u8.try_into().unwrap(), 2_u8.try_into().unwrap(), 3_u8.try_into().unwrap(), @@ -347,7 +346,7 @@ fn test_get_fee_by_gas_vector_overflow( ) { let huge_gas_price = NonzeroGasPrice::try_from(2_u128 * u128::from(u64::MAX)).unwrap(); let mut block_info = BlockContext::create_for_account_testing().block_info; - block_info.gas_prices = GasPrices::validated_new( + block_info.gas_prices = validated_gas_prices( huge_gas_price, huge_gas_price, huge_gas_price, diff --git a/crates/blockifier/src/fee/fee_utils.rs b/crates/blockifier/src/fee/fee_utils.rs index e217d3d6b2..32c12710b0 100644 --- a/crates/blockifier/src/fee/fee_utils.rs +++ b/crates/blockifier/src/fee/fee_utils.rs @@ -4,6 +4,7 @@ use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use num_bigint::BigUint; use starknet_api::abi::abi_utils::get_fee_token_var_address; +use starknet_api::block::FeeType; use starknet_api::core::ContractAddress; use starknet_api::execution_resources::GasVector; use starknet_api::state::StorageKey; @@ -16,7 +17,7 @@ use crate::context::{BlockContext, TransactionContext}; use crate::fee::resources::TransactionFeeResult; use crate::state::state_api::StateReader; use crate::transaction::errors::TransactionFeeError; -use crate::transaction::objects::{ExecutionResourcesTraits, FeeType, TransactionInfo}; +use crate::transaction::objects::{ExecutionResourcesTraits, TransactionInfo}; use crate::utils::u64_from_usize; use crate::versioned_constants::VersionedConstants; diff --git a/crates/blockifier/src/fee/gas_usage_test.rs b/crates/blockifier/src/fee/gas_usage_test.rs index 9d1bcb0f34..25dfb09958 100644 --- a/crates/blockifier/src/fee/gas_usage_test.rs +++ b/crates/blockifier/src/fee/gas_usage_test.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use num_rational::Ratio; use pretty_assertions::assert_eq; use rstest::{fixture, rstest}; -use starknet_api::block::StarknetVersion; +use starknet_api::block::{FeeType, StarknetVersion}; use starknet_api::execution_resources::{GasAmount, GasVector}; use starknet_api::invoke_tx_args; use starknet_api::transaction::fields::GasVectorComputationMode; @@ -28,7 +28,6 @@ use crate::test_utils::{ DEFAULT_ETH_L1_DATA_GAS_PRICE, DEFAULT_ETH_L1_GAS_PRICE, }; -use crate::transaction::objects::FeeType; use crate::transaction::test_utils::account_invoke_tx; use crate::utils::u64_from_usize; use crate::versioned_constants::{ResourceCost, VersionedConstants, VmResourceCosts}; diff --git a/crates/blockifier/src/test_utils/initial_test_state.rs b/crates/blockifier/src/test_utils/initial_test_state.rs index 094fdca6ad..0beeb1a36d 100644 --- a/crates/blockifier/src/test_utils/initial_test_state.rs +++ b/crates/blockifier/src/test_utils/initial_test_state.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use starknet_api::abi::abi_utils::get_fee_token_var_address; +use starknet_api::block::FeeType; use starknet_api::core::ContractAddress; use starknet_api::felt; use starknet_api::transaction::fields::Fee; @@ -11,7 +12,6 @@ use crate::state::cached_state::CachedState; use crate::test_utils::contracts::FeatureContract; use crate::test_utils::dict_state_reader::DictStateReader; use crate::test_utils::CairoVersion; -use crate::transaction::objects::FeeType; /// Utility to fund an account. pub fn fund_account( diff --git a/crates/blockifier/src/test_utils/prices.rs b/crates/blockifier/src/test_utils/prices.rs index 47fba5e7eb..5b8fee6616 100644 --- a/crates/blockifier/src/test_utils/prices.rs +++ b/crates/blockifier/src/test_utils/prices.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use cached::proc_macro::cached; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use starknet_api::abi::abi_utils::{get_fee_token_var_address, selector_from_name}; +use starknet_api::block::FeeType; use starknet_api::core::ContractAddress; use starknet_api::test_utils::invoke::InvokeTxArgs; use starknet_api::transaction::constants; @@ -14,7 +15,6 @@ use crate::execution::entry_point::{CallEntryPoint, EntryPointExecutionContext}; use crate::state::state_api::State; use crate::test_utils::initial_test_state::test_state; use crate::test_utils::BALANCE; -use crate::transaction::objects::FeeType; use crate::transaction::test_utils::account_invoke_tx; /// Enum for all resource costs. diff --git a/crates/blockifier/src/test_utils/struct_impls.rs b/crates/blockifier/src/test_utils/struct_impls.rs index af42fb4eb8..71d64061f9 100644 --- a/crates/blockifier/src/test_utils/struct_impls.rs +++ b/crates/blockifier/src/test_utils/struct_impls.rs @@ -21,7 +21,7 @@ use super::{ TEST_ERC20_CONTRACT_ADDRESS2, TEST_SEQUENCER_ADDRESS, }; -use crate::blockifier::block::{BlockInfo, GasPrices}; +use crate::blockifier::block::{validated_gas_prices, BlockInfo}; use crate::bouncer::{BouncerConfig, BouncerWeights, BuiltinCount}; use crate::context::{BlockContext, ChainInfo, FeeTokenAddresses, TransactionContext}; use crate::execution::call_info::{CallExecution, CallInfo, Retdata}; @@ -152,7 +152,7 @@ impl BlockInfo { block_number: BlockNumber(CURRENT_BLOCK_NUMBER), block_timestamp: BlockTimestamp(CURRENT_BLOCK_TIMESTAMP), sequencer_address: contract_address!(TEST_SEQUENCER_ADDRESS), - gas_prices: GasPrices::validated_new( + gas_prices: validated_gas_prices( DEFAULT_ETH_L1_GAS_PRICE, DEFAULT_STRK_L1_GAS_PRICE, DEFAULT_ETH_L1_DATA_GAS_PRICE, diff --git a/crates/blockifier/src/transaction/account_transactions_test.rs b/crates/blockifier/src/transaction/account_transactions_test.rs index 8f901664bf..f677ada05f 100644 --- a/crates/blockifier/src/transaction/account_transactions_test.rs +++ b/crates/blockifier/src/transaction/account_transactions_test.rs @@ -11,7 +11,7 @@ use starknet_api::abi::abi_utils::{ get_storage_var_address, selector_from_name, }; -use starknet_api::block::GasPrice; +use starknet_api::block::{FeeType, GasPrice}; use starknet_api::core::{calculate_contract_address, ClassHash, ContractAddress}; use starknet_api::executable_transaction::{ AccountTransaction as ApiExecutableTransaction, @@ -84,7 +84,7 @@ use crate::test_utils::{ MAX_FEE, }; use crate::transaction::account_transaction::AccountTransaction; -use crate::transaction::objects::{FeeType, HasRelatedFeeType, TransactionInfoCreator}; +use crate::transaction::objects::{HasRelatedFeeType, TransactionInfoCreator}; use crate::transaction::test_utils::{ account_invoke_tx, all_resource_bounds, diff --git a/crates/blockifier/src/transaction/execution_flavors_test.rs b/crates/blockifier/src/transaction/execution_flavors_test.rs index edf7058021..fbae899ebf 100644 --- a/crates/blockifier/src/transaction/execution_flavors_test.rs +++ b/crates/blockifier/src/transaction/execution_flavors_test.rs @@ -1,6 +1,7 @@ use assert_matches::assert_matches; use pretty_assertions::assert_eq; use rstest::rstest; +use starknet_api::block::FeeType; use starknet_api::core::ContractAddress; use starknet_api::execution_resources::{GasAmount, GasVector}; use starknet_api::test_utils::invoke::InvokeTxArgs; @@ -41,7 +42,7 @@ use crate::transaction::errors::{ TransactionFeeError, TransactionPreValidationError, }; -use crate::transaction::objects::{FeeType, TransactionExecutionInfo, TransactionExecutionResult}; +use crate::transaction::objects::{TransactionExecutionInfo, TransactionExecutionResult}; use crate::transaction::test_utils::{ account_invoke_tx, default_l1_resource_bounds, diff --git a/crates/blockifier/src/transaction/objects.rs b/crates/blockifier/src/transaction/objects.rs index 06e0e89835..0ce713a6a0 100644 --- a/crates/blockifier/src/transaction/objects.rs +++ b/crates/blockifier/src/transaction/objects.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; +use starknet_api::block::FeeType; use starknet_api::core::{ContractAddress, Nonce}; use starknet_api::data_availability::DataAvailabilityMode; use starknet_api::execution_resources::GasVector; @@ -22,7 +23,6 @@ use starknet_api::transaction::{ TransactionOptions, TransactionVersion, }; -use strum_macros::EnumIter; use crate::abi::constants as abi_constants; use crate::blockifier::block::BlockInfo; @@ -279,12 +279,6 @@ pub trait HasRelatedFeeType { } } -#[derive(Clone, Copy, Hash, EnumIter, Eq, PartialEq)] -pub enum FeeType { - Strk, - Eth, -} - pub trait TransactionInfoCreator { fn create_tx_info(&self) -> TransactionInfo; } diff --git a/crates/blockifier/src/transaction/post_execution_test.rs b/crates/blockifier/src/transaction/post_execution_test.rs index 2b93fc5bc0..5ec93ed343 100644 --- a/crates/blockifier/src/transaction/post_execution_test.rs +++ b/crates/blockifier/src/transaction/post_execution_test.rs @@ -1,5 +1,6 @@ use assert_matches::assert_matches; use rstest::rstest; +use starknet_api::block::FeeType; use starknet_api::core::ContractAddress; use starknet_api::execution_resources::GasAmount; use starknet_api::state::StorageKey; @@ -31,7 +32,7 @@ use crate::test_utils::{ }; use crate::transaction::account_transaction::AccountTransaction; use crate::transaction::errors::TransactionExecutionError; -use crate::transaction::objects::{FeeType, HasRelatedFeeType, TransactionInfoCreator}; +use crate::transaction::objects::{HasRelatedFeeType, TransactionInfoCreator}; use crate::transaction::test_utils::{ account_invoke_tx, block_context, diff --git a/crates/blockifier/src/transaction/test_utils.rs b/crates/blockifier/src/transaction/test_utils.rs index fdefb138e6..36757124a4 100644 --- a/crates/blockifier/src/transaction/test_utils.rs +++ b/crates/blockifier/src/transaction/test_utils.rs @@ -1,6 +1,6 @@ use rstest::fixture; use starknet_api::abi::abi_utils::get_fee_token_var_address; -use starknet_api::block::GasPrice; +use starknet_api::block::{FeeType, GasPrice}; use starknet_api::contract_class::{ClassInfo, ContractClass}; use starknet_api::core::{ClassHash, ContractAddress, Nonce}; use starknet_api::execution_resources::GasAmount; @@ -43,7 +43,7 @@ use crate::test_utils::{ MAX_FEE, }; use crate::transaction::account_transaction::AccountTransaction; -use crate::transaction::objects::{FeeType, TransactionExecutionInfo, TransactionExecutionResult}; +use crate::transaction::objects::{TransactionExecutionInfo, TransactionExecutionResult}; use crate::transaction::transaction_types::TransactionType; use crate::transaction::transactions::ExecutableTransaction; diff --git a/crates/blockifier/src/transaction/transactions_test.rs b/crates/blockifier/src/transaction/transactions_test.rs index 1d69557692..5933e4b076 100644 --- a/crates/blockifier/src/transaction/transactions_test.rs +++ b/crates/blockifier/src/transaction/transactions_test.rs @@ -13,7 +13,7 @@ use starknet_api::abi::abi_utils::{ selector_from_name, }; use starknet_api::abi::constants::CONSTRUCTOR_ENTRY_POINT_NAME; -use starknet_api::block::GasPriceVector; +use starknet_api::block::{FeeType, GasPriceVector}; use starknet_api::contract_class::EntryPointType; use starknet_api::core::{ChainId, ClassHash, ContractAddress, EthAddress, Nonce}; use starknet_api::executable_transaction::AccountTransaction as ApiExecutableTransaction; @@ -123,7 +123,6 @@ use crate::transaction::errors::{ TransactionPreValidationError, }; use crate::transaction::objects::{ - FeeType, HasRelatedFeeType, TransactionExecutionInfo, TransactionInfo, diff --git a/crates/native_blockifier/src/py_state_diff.rs b/crates/native_blockifier/src/py_state_diff.rs index 6a78360363..70ea8fb9d1 100644 --- a/crates/native_blockifier/src/py_state_diff.rs +++ b/crates/native_blockifier/src/py_state_diff.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::convert::TryFrom; -use blockifier::blockifier::block::{BlockInfo, GasPrices}; +use blockifier::blockifier::block::{validated_gas_prices, BlockInfo}; use blockifier::state::cached_state::CommitmentStateDiff; use blockifier::test_utils::{ DEFAULT_ETH_L1_DATA_GAS_PRICE, @@ -182,7 +182,7 @@ impl TryFrom for BlockInfo { block_number: BlockNumber(block_info.block_number), block_timestamp: BlockTimestamp(block_info.block_timestamp), sequencer_address: ContractAddress::try_from(block_info.sequencer_address.0)?, - gas_prices: GasPrices::validated_new( + gas_prices: validated_gas_prices( NonzeroGasPrice::try_from(block_info.l1_gas_price.price_in_wei).map_err(|_| { NativeBlockifierInputError::InvalidNativeBlockifierInputError( InvalidNativeBlockifierInputError::InvalidL1GasPriceWei( diff --git a/crates/papyrus_execution/src/lib.rs b/crates/papyrus_execution/src/lib.rs index d997f58f04..6ed407c2dd 100644 --- a/crates/papyrus_execution/src/lib.rs +++ b/crates/papyrus_execution/src/lib.rs @@ -23,7 +23,7 @@ use std::cell::Cell; use std::collections::BTreeMap; use std::sync::{Arc, LazyLock}; -use blockifier::blockifier::block::{pre_process_block, BlockInfo, GasPrices}; +use blockifier::blockifier::block::{pre_process_block, validated_gas_prices, BlockInfo}; use blockifier::bouncer::BouncerConfig; use blockifier::context::{BlockContext, ChainInfo, FeeTokenAddresses, TransactionContext}; use blockifier::execution::call_info::CallExecution; @@ -369,7 +369,7 @@ fn create_block_context( use_kzg_da, block_number, // TODO(yair): What to do about blocks pre 0.13.1 where the data gas price were 0? - gas_prices: GasPrices::validated_new( + gas_prices: validated_gas_prices( NonzeroGasPrice::new(l1_gas_price.price_in_wei).unwrap_or(NonzeroGasPrice::MIN), NonzeroGasPrice::new(l1_gas_price.price_in_fri).unwrap_or(NonzeroGasPrice::MIN), NonzeroGasPrice::new(l1_data_gas_price.price_in_wei).unwrap_or(NonzeroGasPrice::MIN), diff --git a/crates/papyrus_execution/src/objects.rs b/crates/papyrus_execution/src/objects.rs index d44c769310..8be701059e 100644 --- a/crates/papyrus_execution/src/objects.rs +++ b/crates/papyrus_execution/src/objects.rs @@ -9,7 +9,7 @@ use blockifier::execution::call_info::{ Retdata as BlockifierRetdata, }; use blockifier::execution::entry_point::CallType as BlockifierCallType; -use blockifier::transaction::objects::{FeeType, TransactionExecutionInfo}; +use blockifier::transaction::objects::TransactionExecutionInfo; use blockifier::utils::u64_from_usize; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources as VmExecutionResources; @@ -23,7 +23,7 @@ use papyrus_common::state::{ StorageEntry, }; use serde::{Deserialize, Serialize}; -use starknet_api::block::{BlockTimestamp, GasPrice, GasPricePerToken}; +use starknet_api::block::{BlockTimestamp, FeeType, GasPrice, GasPricePerToken}; use starknet_api::contract_class::EntryPointType; use starknet_api::core::{ ClassHash, diff --git a/crates/starknet_api/src/block.rs b/crates/starknet_api/src/block.rs index 32dde80eac..2e89212e8e 100644 --- a/crates/starknet_api/src/block.rs +++ b/crates/starknet_api/src/block.rs @@ -6,6 +6,7 @@ use itertools::Itertools; use serde::{Deserialize, Serialize}; use starknet_types_core::felt::Felt; use starknet_types_core::hash::{Poseidon, StarkHash as CoreStarkHash}; +use strum_macros::EnumIter; use crate::core::{ EventCommitment, @@ -444,6 +445,39 @@ pub struct GasPriceVector { pub l2_gas_price: NonzeroGasPrice, } +#[derive(Clone, Copy, Hash, EnumIter, Eq, PartialEq)] +pub enum FeeType { + Strk, + Eth, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct GasPrices { + pub eth_gas_prices: GasPriceVector, // In wei. + pub strk_gas_prices: GasPriceVector, // In fri. +} + +impl GasPrices { + pub fn l1_gas_price(&self, fee_type: &FeeType) -> NonzeroGasPrice { + self.gas_price_vector(fee_type).l1_gas_price + } + + pub fn l1_data_gas_price(&self, fee_type: &FeeType) -> NonzeroGasPrice { + self.gas_price_vector(fee_type).l1_data_gas_price + } + + pub fn l2_gas_price(&self, fee_type: &FeeType) -> NonzeroGasPrice { + self.gas_price_vector(fee_type).l2_gas_price + } + + pub fn gas_price_vector(&self, fee_type: &FeeType) -> &GasPriceVector { + match fee_type { + FeeType::Strk => &self.strk_gas_prices, + FeeType::Eth => &self.eth_gas_prices, + } + } +} + /// The timestamp of a [Block](`crate::block::Block`). #[derive( Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord, diff --git a/crates/starknet_batcher/src/block_builder.rs b/crates/starknet_batcher/src/block_builder.rs index 94a8fbb69a..0e72c761ff 100644 --- a/crates/starknet_batcher/src/block_builder.rs +++ b/crates/starknet_batcher/src/block_builder.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use async_trait::async_trait; -use blockifier::blockifier::block::{BlockInfo, GasPrices}; +use blockifier::blockifier::block::{validated_gas_prices, BlockInfo}; use blockifier::blockifier::config::TransactionExecutorConfig; use blockifier::blockifier::transaction_executor::{ TransactionExecutor, @@ -312,7 +312,7 @@ impl BlockBuilderFactory { // TODO (yael 7/10/2024): add logic to compute gas prices gas_prices: { let tmp_val = NonzeroGasPrice::MIN; - GasPrices::validated_new(tmp_val, tmp_val, tmp_val, tmp_val, tmp_val, tmp_val) + validated_gas_prices(tmp_val, tmp_val, tmp_val, tmp_val, tmp_val, tmp_val) }, use_kzg_da: block_builder_config.use_kzg_da, }; diff --git a/crates/starknet_gateway/src/rpc_objects.rs b/crates/starknet_gateway/src/rpc_objects.rs index 1209a4f459..5333f6e1cc 100644 --- a/crates/starknet_gateway/src/rpc_objects.rs +++ b/crates/starknet_gateway/src/rpc_objects.rs @@ -1,4 +1,4 @@ -use blockifier::blockifier::block::{BlockInfo, GasPrices}; +use blockifier::blockifier::block::{validated_gas_prices, BlockInfo}; use serde::{Deserialize, Serialize}; use serde_json::Value; use starknet_api::block::{BlockHash, BlockNumber, BlockTimestamp, GasPrice, NonzeroGasPrice}; @@ -86,7 +86,7 @@ impl TryInto for BlockHeader { block_number: self.block_number, sequencer_address: self.sequencer_address, block_timestamp: self.timestamp, - gas_prices: GasPrices::validated_new( + gas_prices: validated_gas_prices( parse_gas_price(self.l1_gas_price.price_in_wei)?, parse_gas_price(self.l1_gas_price.price_in_fri)?, parse_gas_price(self.l1_data_gas_price.price_in_wei)?, diff --git a/crates/starknet_integration_tests/src/state_reader.rs b/crates/starknet_integration_tests/src/state_reader.rs index 5015d52629..ca88fb9cb3 100644 --- a/crates/starknet_integration_tests/src/state_reader.rs +++ b/crates/starknet_integration_tests/src/state_reader.rs @@ -12,7 +12,6 @@ use blockifier::test_utils::{ DEFAULT_STRK_L1_GAS_PRICE, TEST_SEQUENCER_ADDRESS, }; -use blockifier::transaction::objects::FeeType; use blockifier::versioned_constants::VersionedConstants; use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; use indexmap::IndexMap; @@ -33,6 +32,7 @@ use starknet_api::block::{ BlockHeaderWithoutHash, BlockNumber, BlockTimestamp, + FeeType, GasPricePerToken, }; use starknet_api::core::{ChainId, ClassHash, ContractAddress, Nonce, SequencerContractAddress}; From f1c5c373744a4fb9b907b5153fab1c0b3d51e211 Mon Sep 17 00:00:00 2001 From: Itay Tsabary Date: Wed, 27 Nov 2024 19:54:44 +0200 Subject: [PATCH 11/25] chore(tests_integration): move http client test util commit-id:2d145538 --- Cargo.lock | 4 +- crates/starknet_http_server/Cargo.toml | 5 ++ crates/starknet_http_server/src/lib.rs | 2 + crates/starknet_http_server/src/test_utils.rs | 55 +++++++++++++++++++ crates/starknet_integration_tests/Cargo.toml | 4 +- .../src/flow_test_setup.rs | 3 +- .../src/integration_test_setup.rs | 3 +- .../starknet_integration_tests/src/utils.rs | 47 +--------------- .../tests/mempool_p2p_flow_test.rs | 2 +- 9 files changed, 71 insertions(+), 54 deletions(-) create mode 100644 crates/starknet_http_server/src/test_utils.rs diff --git a/Cargo.lock b/Cargo.lock index 3fddafbc6b..763688914b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10415,7 +10415,9 @@ version = "0.0.0" dependencies = [ "axum", "hyper 0.14.30", + "mempool_test_utils", "papyrus_config", + "reqwest 0.11.27", "serde", "serde_json", "starknet_api", @@ -10433,7 +10435,6 @@ version = "0.0.0" dependencies = [ "anyhow", "assert_matches", - "axum", "blockifier", "cairo-lang-starknet-classes", "futures", @@ -10448,7 +10449,6 @@ dependencies = [ "papyrus_rpc", "papyrus_storage", "pretty_assertions", - "reqwest 0.11.27", "rstest", "serde_json", "starknet-types-core", diff --git a/crates/starknet_http_server/Cargo.toml b/crates/starknet_http_server/Cargo.toml index 0503a48283..1e62232cb5 100644 --- a/crates/starknet_http_server/Cargo.toml +++ b/crates/starknet_http_server/Cargo.toml @@ -5,13 +5,18 @@ edition.workspace = true license.workspace = true repository.workspace = true +[features] +testing = ["mempool_test_utils", "reqwest"] + [lints] workspace = true [dependencies] axum.workspace = true hyper.workspace = true +mempool_test_utils = { workspace = true, optional = true } papyrus_config.workspace = true +reqwest = { workspace = true, optional = true } serde.workspace = true starknet_api.workspace = true starknet_gateway_types.workspace = true diff --git a/crates/starknet_http_server/src/lib.rs b/crates/starknet_http_server/src/lib.rs index 762c8af043..350df0d4c2 100644 --- a/crates/starknet_http_server/src/lib.rs +++ b/crates/starknet_http_server/src/lib.rs @@ -2,3 +2,5 @@ pub mod communication; pub mod config; pub mod errors; pub mod http_server; +#[cfg(feature = "testing")] +pub mod test_utils; diff --git a/crates/starknet_http_server/src/test_utils.rs b/crates/starknet_http_server/src/test_utils.rs new file mode 100644 index 0000000000..8a319a8121 --- /dev/null +++ b/crates/starknet_http_server/src/test_utils.rs @@ -0,0 +1,55 @@ +use std::net::SocketAddr; + +use axum::body::Body; +use mempool_test_utils::starknet_api_test_utils::rpc_tx_to_json; +use reqwest::{Client, Response}; +use starknet_api::rpc_transaction::RpcTransaction; +use starknet_api::transaction::TransactionHash; +use starknet_gateway_types::errors::GatewaySpecError; +use starknet_sequencer_infra::test_utils::get_available_socket; + +use crate::config::HttpServerConfig; + +/// A test utility client for interacting with an http server. +pub struct HttpTestClient { + socket: SocketAddr, + client: Client, +} + +impl HttpTestClient { + pub fn new(socket: SocketAddr) -> Self { + let client = Client::new(); + Self { socket, client } + } + + pub async fn assert_add_tx_success(&self, rpc_tx: RpcTransaction) -> TransactionHash { + let response = self.add_tx(rpc_tx).await; + assert!(response.status().is_success()); + + response.json().await.unwrap() + } + + // TODO: implement when usage eventually arises. + pub async fn assert_add_tx_error(&self, _tx: RpcTransaction) -> GatewaySpecError { + todo!() + } + + // Prefer using assert_add_tx_success or other higher level methods of this client, to ensure + // tests are boilerplate and implementation-detail free. + pub async fn add_tx(&self, rpc_tx: RpcTransaction) -> Response { + let tx_json = rpc_tx_to_json(&rpc_tx); + self.client + .post(format!("http://{}/add_tx", self.socket)) + .header("content-type", "application/json") + .body(Body::from(tx_json)) + .send() + .await + .unwrap() + } +} + +pub async fn create_http_server_config() -> HttpServerConfig { + // TODO(Tsabary): use ser_generated_param. + let socket = get_available_socket().await; + HttpServerConfig { ip: socket.ip(), port: socket.port() } +} diff --git a/crates/starknet_integration_tests/Cargo.toml b/crates/starknet_integration_tests/Cargo.toml index 8b3b43ef64..88427a77e5 100644 --- a/crates/starknet_integration_tests/Cargo.toml +++ b/crates/starknet_integration_tests/Cargo.toml @@ -11,7 +11,6 @@ workspace = true [dependencies] anyhow.workspace = true assert_matches.workspace = true -axum.workspace = true blockifier.workspace = true cairo-lang-starknet-classes.workspace = true futures.workspace = true @@ -24,7 +23,6 @@ papyrus_network = { workspace = true, features = ["testing"] } papyrus_protobuf.workspace = true papyrus_rpc.workspace = true papyrus_storage = { workspace = true, features = ["testing"] } -reqwest.workspace = true serde_json.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true @@ -33,7 +31,7 @@ starknet_client.workspace = true starknet_consensus_manager.workspace = true starknet_gateway = { workspace = true, features = ["testing"] } starknet_gateway_types.workspace = true -starknet_http_server.workspace = true +starknet_http_server = { workspace = true, features = ["testing"] } starknet_mempool_p2p.workspace = true starknet_monitoring_endpoint = { workspace = true, features = ["testing"] } starknet_sequencer_infra = { workspace = true, features = ["testing"] } diff --git a/crates/starknet_integration_tests/src/flow_test_setup.rs b/crates/starknet_integration_tests/src/flow_test_setup.rs index cecefd60cd..500746aa7f 100644 --- a/crates/starknet_integration_tests/src/flow_test_setup.rs +++ b/crates/starknet_integration_tests/src/flow_test_setup.rs @@ -7,6 +7,7 @@ use starknet_api::rpc_transaction::RpcTransaction; use starknet_api::transaction::TransactionHash; use starknet_gateway_types::errors::GatewaySpecError; use starknet_http_server::config::HttpServerConfig; +use starknet_http_server::test_utils::HttpTestClient; use starknet_sequencer_infra::trace_util::configure_tracing; use starknet_sequencer_node::servers::run_component_servers; use starknet_sequencer_node::utils::create_node_modules; @@ -16,7 +17,7 @@ use tokio::runtime::Handle; use tokio::task::JoinHandle; use crate::state_reader::{spawn_test_rpc_state_reader, StorageTestSetup}; -use crate::utils::{create_chain_info, create_config, HttpTestClient}; +use crate::utils::{create_chain_info, create_config}; pub struct FlowTestSetup { pub task_executor: TokioExecutor, diff --git a/crates/starknet_integration_tests/src/integration_test_setup.rs b/crates/starknet_integration_tests/src/integration_test_setup.rs index 3beaf9cf17..770c5be416 100644 --- a/crates/starknet_integration_tests/src/integration_test_setup.rs +++ b/crates/starknet_integration_tests/src/integration_test_setup.rs @@ -4,13 +4,14 @@ use std::path::PathBuf; use mempool_test_utils::starknet_api_test_utils::MultiAccountTransactionGenerator; use papyrus_storage::StorageConfig; use starknet_http_server::config::HttpServerConfig; +use starknet_http_server::test_utils::HttpTestClient; use starknet_monitoring_endpoint::config::MonitoringEndpointConfig; use starknet_monitoring_endpoint::test_utils::IsAliveClient; use tempfile::{tempdir, TempDir}; use crate::config_utils::dump_config_file_changes; use crate::state_reader::{spawn_test_rpc_state_reader, StorageTestSetup}; -use crate::utils::{create_chain_info, create_config, HttpTestClient}; +use crate::utils::{create_chain_info, create_config}; pub struct IntegrationTestSetup { // Client for adding transactions to the sequencer node. diff --git a/crates/starknet_integration_tests/src/utils.rs b/crates/starknet_integration_tests/src/utils.rs index fb89e98051..f8cf3f1e06 100644 --- a/crates/starknet_integration_tests/src/utils.rs +++ b/crates/starknet_integration_tests/src/utils.rs @@ -2,21 +2,15 @@ use std::future::Future; use std::net::SocketAddr; use std::time::Duration; -use axum::body::Body; use blockifier::context::ChainInfo; use blockifier::test_utils::contracts::FeatureContract; use blockifier::test_utils::CairoVersion; -use mempool_test_utils::starknet_api_test_utils::{ - rpc_tx_to_json, - AccountId, - MultiAccountTransactionGenerator, -}; +use mempool_test_utils::starknet_api_test_utils::{AccountId, MultiAccountTransactionGenerator}; use papyrus_consensus::config::ConsensusConfig; use papyrus_network::network_manager::test_utils::create_network_config_connected_to_broadcast_channels; use papyrus_network::network_manager::BroadcastTopicChannels; use papyrus_protobuf::consensus::ProposalPart; use papyrus_storage::StorageConfig; -use reqwest::{Client, Response}; use starknet_api::block::BlockNumber; use starknet_api::contract_address; use starknet_api::core::ContractAddress; @@ -31,7 +25,6 @@ use starknet_gateway::config::{ StatefulTransactionValidatorConfig, StatelessTransactionValidatorConfig, }; -use starknet_gateway_types::errors::GatewaySpecError; use starknet_http_server::config::HttpServerConfig; use starknet_sequencer_infra::test_utils::get_available_socket; use starknet_sequencer_node::config::node_config::SequencerNodeConfig; @@ -105,44 +98,6 @@ pub fn test_rpc_state_reader_config(rpc_server_addr: SocketAddr) -> RpcStateRead } } -/// A test utility client for interacting with an http server. -pub struct HttpTestClient { - socket: SocketAddr, - client: Client, -} - -impl HttpTestClient { - pub fn new(socket: SocketAddr) -> Self { - let client = Client::new(); - Self { socket, client } - } - - pub async fn assert_add_tx_success(&self, rpc_tx: RpcTransaction) -> TransactionHash { - let response = self.add_tx(rpc_tx).await; - assert!(response.status().is_success()); - - response.json().await.unwrap() - } - - // TODO: implement when usage eventually arises. - pub async fn assert_add_tx_error(&self, _tx: RpcTransaction) -> GatewaySpecError { - todo!() - } - - // Prefer using assert_add_tx_success or other higher level methods of this client, to ensure - // tests are boilerplate and implementation-detail free. - pub async fn add_tx(&self, rpc_tx: RpcTransaction) -> Response { - let tx_json = rpc_tx_to_json(&rpc_tx); - self.client - .post(format!("http://{}/add_tx", self.socket)) - .header("content-type", "application/json") - .body(Body::from(tx_json)) - .send() - .await - .unwrap() - } -} - /// Creates a multi-account transaction generator for integration tests. pub fn create_integration_test_tx_generator() -> MultiAccountTransactionGenerator { let mut tx_generator: MultiAccountTransactionGenerator = diff --git a/crates/starknet_integration_tests/tests/mempool_p2p_flow_test.rs b/crates/starknet_integration_tests/tests/mempool_p2p_flow_test.rs index 2c1f5d42ae..e67fddad95 100644 --- a/crates/starknet_integration_tests/tests/mempool_p2p_flow_test.rs +++ b/crates/starknet_integration_tests/tests/mempool_p2p_flow_test.rs @@ -9,6 +9,7 @@ use papyrus_protobuf::mempool::RpcTransactionWrapper; use rstest::{fixture, rstest}; use starknet_api::rpc_transaction::RpcTransaction; use starknet_http_server::config::HttpServerConfig; +use starknet_http_server::test_utils::HttpTestClient; use starknet_integration_tests::state_reader::{spawn_test_rpc_state_reader, StorageTestSetup}; use starknet_integration_tests::utils::{ create_batcher_config, @@ -18,7 +19,6 @@ use starknet_integration_tests::utils::{ create_integration_test_tx_generator, run_integration_test_scenario, test_rpc_state_reader_config, - HttpTestClient, }; use starknet_mempool_p2p::config::MempoolP2pConfig; use starknet_mempool_p2p::MEMPOOL_TOPIC; From 1b94f6e3c22d0095f30eabe171da04d026124c3d Mon Sep 17 00:00:00 2001 From: Itay Tsabary Date: Wed, 27 Nov 2024 20:18:04 +0200 Subject: [PATCH 12/25] chore(tests_integration): move node runner test util commit-id:2959cc90 --- .../tests/end_to_end_integration_test.rs | 40 +------------------ .../src/test_utils/compilation.rs | 37 ++++++++++++++++- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/crates/starknet_integration_tests/tests/end_to_end_integration_test.rs b/crates/starknet_integration_tests/tests/end_to_end_integration_test.rs index d2af0e5e30..ab0ba4d67b 100644 --- a/crates/starknet_integration_tests/tests/end_to_end_integration_test.rs +++ b/crates/starknet_integration_tests/tests/end_to_end_integration_test.rs @@ -1,9 +1,5 @@ -use std::path::PathBuf; -use std::process::Stdio; use std::time::Duration; -use infra_utils::command::create_shell_command; -use infra_utils::path::resolve_project_relative_path; use mempool_test_utils::starknet_api_test_utils::{AccountId, MultiAccountTransactionGenerator}; use papyrus_execution::execution_utils::get_nonce_at; use papyrus_storage::state::StateStorageReader; @@ -15,10 +11,8 @@ use starknet_api::state::StateNumber; use starknet_integration_tests::integration_test_setup::IntegrationTestSetup; use starknet_integration_tests::utils::{create_integration_test_tx_generator, send_account_txs}; use starknet_sequencer_infra::trace_util::configure_tracing; -use starknet_sequencer_node::test_utils::compilation::{compile_node_result, NODE_EXECUTABLE_PATH}; +use starknet_sequencer_node::test_utils::compilation::spawn_run_node; use starknet_types_core::felt::Felt; -use tokio::process::Child; -use tokio::task::{self, JoinHandle}; use tokio::time::interval; use tracing::{error, info}; @@ -27,38 +21,6 @@ fn tx_generator() -> MultiAccountTransactionGenerator { create_integration_test_tx_generator() } -// TODO(Tsabary): Move to a suitable util location. -async fn spawn_node_child_task(node_config_path: PathBuf) -> Child { - // TODO(Tsabary): Capture output to a log file, and present it in case of a failure. - info!("Compiling the node."); - compile_node_result().await.expect("Failed to compile the sequencer node."); - let node_executable = resolve_project_relative_path(NODE_EXECUTABLE_PATH) - .expect("Node executable should be available") - .to_string_lossy() - .to_string(); - - info!("Running the node from: {}", node_executable); - create_shell_command(node_executable.as_str()) - .arg("--config_file") - .arg(node_config_path.to_str().unwrap()) - .stderr(Stdio::inherit()) - .stdout(Stdio::null()) - .kill_on_drop(true) // Required for stopping the node when the handle is dropped. - .spawn() - .expect("Failed to spawn the sequencer node.") -} - -async fn spawn_run_node(node_config_path: PathBuf) -> JoinHandle<()> { - task::spawn(async move { - info!("Running the node from its spawned task."); - let _node_run_result = spawn_node_child_task(node_config_path). - await. // awaits the completion of spawn_node_child_task. - wait(). // runs the node until completion -- should be running indefinitely. - await; // awaits the completion of the node. - panic!("Node stopped unexpectedly."); - }) -} - /// Reads the latest block number from the storage. fn get_latest_block_number(storage_reader: &StorageReader) -> BlockNumber { let txn = storage_reader.begin_ro_txn().unwrap(); diff --git a/crates/starknet_sequencer_node/src/test_utils/compilation.rs b/crates/starknet_sequencer_node/src/test_utils/compilation.rs index 5975f44073..b1fa967fb8 100644 --- a/crates/starknet_sequencer_node/src/test_utils/compilation.rs +++ b/crates/starknet_sequencer_node/src/test_utils/compilation.rs @@ -1,8 +1,12 @@ use std::io; +use std::path::PathBuf; use std::process::{ExitStatus, Stdio}; use infra_utils::command::create_shell_command; -use tracing::info; +use infra_utils::path::resolve_project_relative_path; +use tokio::process::Child; +use tokio::task::{self, JoinHandle}; +use tracing::{error, info}; pub const NODE_EXECUTABLE_PATH: &str = "target/debug/starknet_sequencer_node"; @@ -47,3 +51,34 @@ pub async fn compile_node_result() -> Result<(), NodeCompilationError> { Err(e) => Err(NodeCompilationError::IO(e)), } } + +pub async fn spawn_run_node(node_config_path: PathBuf) -> JoinHandle<()> { + task::spawn(async move { + info!("Running the node from its spawned task."); + let _node_run_result = spawn_node_child_task(node_config_path). + await. // awaits the completion of spawn_node_child_task. + wait(). // runs the node until completion -- should be running indefinitely. + await; // awaits the completion of the node. + panic!("Node stopped unexpectedly."); + }) +} + +async fn spawn_node_child_task(node_config_path: PathBuf) -> Child { + // TODO(Tsabary): Capture output to a log file, and present it in case of a failure. + info!("Compiling the node."); + compile_node_result().await.expect("Failed to compile the sequencer node."); + let node_executable = resolve_project_relative_path(NODE_EXECUTABLE_PATH) + .expect("Node executable should be available") + .to_string_lossy() + .to_string(); + + info!("Running the node from: {}", node_executable); + create_shell_command(node_executable.as_str()) + .arg("--config_file") + .arg(node_config_path.to_str().unwrap()) + .stderr(Stdio::inherit()) + .stdout(Stdio::null()) + .kill_on_drop(true) // Required for stopping the node when the handle is dropped. + .spawn() + .expect("Failed to spawn the sequencer node.") +} From 50403e46def735140f81d634a224d6f784ff7462 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 28 Nov 2024 12:43:38 +0200 Subject: [PATCH 13/25] chore(blockifier): move block info to starknet api (#2246) --- crates/blockifier/src/blockifier/block.rs | 13 ------------- crates/blockifier/src/context.rs | 3 +-- .../deprecated_syscalls/hint_processor.rs | 2 +- crates/blockifier/src/fee/fee_utils.rs | 3 +-- crates/blockifier/src/test_utils/struct_impls.rs | 15 ++++++++++----- crates/blockifier/src/transaction/objects.rs | 3 +-- .../src/state_reader/raw_rpc_json_test.rs | 3 +-- .../src/state_reader/rpc_https_test.rs | 3 +-- .../src/state_reader/test_state_reader.rs | 3 +-- crates/native_blockifier/src/py_state_diff.rs | 4 ++-- crates/papyrus_execution/src/lib.rs | 10 ++++++++-- crates/starknet_api/src/block.rs | 12 ++++++++++++ crates/starknet_batcher/src/block_builder.rs | 10 ++++++++-- crates/starknet_gateway/src/rpc_objects.rs | 11 +++++++++-- crates/starknet_gateway/src/rpc_state_reader.rs | 3 +-- crates/starknet_gateway/src/state_reader.rs | 3 +-- .../src/state_reader_test_utils.rs | 3 +-- .../src/stateful_transaction_validator.rs | 2 +- 18 files changed, 60 insertions(+), 46 deletions(-) diff --git a/crates/blockifier/src/blockifier/block.rs b/crates/blockifier/src/blockifier/block.rs index 59a8a1ec0f..5383d645f5 100644 --- a/crates/blockifier/src/blockifier/block.rs +++ b/crates/blockifier/src/blockifier/block.rs @@ -1,9 +1,7 @@ use log::warn; -use serde::{Deserialize, Serialize}; use starknet_api::block::{ BlockHashAndNumber, BlockNumber, - BlockTimestamp, GasPrice, GasPriceVector, GasPrices, @@ -21,17 +19,6 @@ use crate::versioned_constants::VersionedConstants; #[path = "block_test.rs"] pub mod block_test; -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct BlockInfo { - pub block_number: BlockNumber, - pub block_timestamp: BlockTimestamp, - - // Fee-related. - pub sequencer_address: ContractAddress, - pub gas_prices: GasPrices, - pub use_kzg_da: bool, -} - /// Warns if the submitted gas prices do not match the expected gas prices. fn validate_l2_gas_price(gas_prices: &GasPrices) { // TODO(Aner): fix backwards compatibility. diff --git a/crates/blockifier/src/context.rs b/crates/blockifier/src/context.rs index 069fcb53e6..bd69be574f 100644 --- a/crates/blockifier/src/context.rs +++ b/crates/blockifier/src/context.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use papyrus_config::dumping::{append_sub_config_name, ser_param, SerializeConfig}; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::{Deserialize, Serialize}; -use starknet_api::block::{FeeType, GasPriceVector}; +use starknet_api::block::{BlockInfo, FeeType, GasPriceVector}; use starknet_api::core::{ChainId, ContractAddress}; use starknet_api::transaction::fields::{ AllResourceBounds, @@ -11,7 +11,6 @@ use starknet_api::transaction::fields::{ ValidResourceBounds, }; -use crate::blockifier::block::BlockInfo; use crate::bouncer::BouncerConfig; use crate::transaction::objects::{ CurrentTransactionInfo, diff --git a/crates/blockifier/src/execution/deprecated_syscalls/hint_processor.rs b/crates/blockifier/src/execution/deprecated_syscalls/hint_processor.rs index 0ea7f175f6..16f24ce504 100644 --- a/crates/blockifier/src/execution/deprecated_syscalls/hint_processor.rs +++ b/crates/blockifier/src/execution/deprecated_syscalls/hint_processor.rs @@ -17,6 +17,7 @@ use cairo_vm::vm::errors::vm_errors::VirtualMachineError; use cairo_vm::vm::runners::cairo_runner::{ResourceTracker, RunResources}; use cairo_vm::vm::vm_core::VirtualMachine; use num_bigint::{BigUint, TryFromBigIntError}; +use starknet_api::block::BlockInfo; use starknet_api::contract_class::EntryPointType; use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector}; use starknet_api::state::StorageKey; @@ -25,7 +26,6 @@ use starknet_api::StarknetApiError; use starknet_types_core::felt::{Felt, FromStrError}; use thiserror::Error; -use crate::blockifier::block::BlockInfo; use crate::context::TransactionContext; use crate::execution::call_info::{CallInfo, OrderedEvent, OrderedL2ToL1Message}; use crate::execution::common_hints::{ diff --git a/crates/blockifier/src/fee/fee_utils.rs b/crates/blockifier/src/fee/fee_utils.rs index 32c12710b0..097ccf9c56 100644 --- a/crates/blockifier/src/fee/fee_utils.rs +++ b/crates/blockifier/src/fee/fee_utils.rs @@ -4,7 +4,7 @@ use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use num_bigint::BigUint; use starknet_api::abi::abi_utils::get_fee_token_var_address; -use starknet_api::block::FeeType; +use starknet_api::block::{BlockInfo, FeeType}; use starknet_api::core::ContractAddress; use starknet_api::execution_resources::GasVector; use starknet_api::state::StorageKey; @@ -12,7 +12,6 @@ use starknet_api::transaction::fields::ValidResourceBounds::{AllResources, L1Gas use starknet_api::transaction::fields::{Fee, GasVectorComputationMode, Resource}; use starknet_types_core::felt::Felt; -use crate::blockifier::block::BlockInfo; use crate::context::{BlockContext, TransactionContext}; use crate::fee::resources::TransactionFeeResult; use crate::state::state_api::StateReader; diff --git a/crates/blockifier/src/test_utils/struct_impls.rs b/crates/blockifier/src/test_utils/struct_impls.rs index 71d64061f9..fe9fdebff5 100644 --- a/crates/blockifier/src/test_utils/struct_impls.rs +++ b/crates/blockifier/src/test_utils/struct_impls.rs @@ -10,7 +10,7 @@ use cairo_lang_starknet_classes::contract_class::ContractClass as SierraContract #[cfg(feature = "cairo_native")] use cairo_native::executor::AotContractExecutor; use serde_json::Value; -use starknet_api::block::{BlockNumber, BlockTimestamp, NonzeroGasPrice}; +use starknet_api::block::{BlockInfo, BlockNumber, BlockTimestamp, NonzeroGasPrice}; use starknet_api::contract_address; use starknet_api::core::{ChainId, ClassHash}; use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; @@ -21,7 +21,7 @@ use super::{ TEST_ERC20_CONTRACT_ADDRESS2, TEST_SEQUENCER_ADDRESS, }; -use crate::blockifier::block::{validated_gas_prices, BlockInfo}; +use crate::blockifier::block::validated_gas_prices; use crate::bouncer::{BouncerConfig, BouncerWeights, BuiltinCount}; use crate::context::{BlockContext, ChainInfo, FeeTokenAddresses, TransactionContext}; use crate::execution::call_info::{CallExecution, CallInfo, Retdata}; @@ -146,8 +146,13 @@ impl ChainInfo { } } -impl BlockInfo { - pub fn create_for_testing() -> Self { +pub trait BlockInfoExt { + fn create_for_testing() -> Self; + fn create_for_testing_with_kzg(use_kzg_da: bool) -> Self; +} + +impl BlockInfoExt for BlockInfo { + fn create_for_testing() -> Self { Self { block_number: BlockNumber(CURRENT_BLOCK_NUMBER), block_timestamp: BlockTimestamp(CURRENT_BLOCK_TIMESTAMP), @@ -172,7 +177,7 @@ impl BlockInfo { } } - pub fn create_for_testing_with_kzg(use_kzg_da: bool) -> Self { + fn create_for_testing_with_kzg(use_kzg_da: bool) -> Self { Self { use_kzg_da, ..Self::create_for_testing() } } } diff --git a/crates/blockifier/src/transaction/objects.rs b/crates/blockifier/src/transaction/objects.rs index 0ce713a6a0..4cfef890e6 100644 --- a/crates/blockifier/src/transaction/objects.rs +++ b/crates/blockifier/src/transaction/objects.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; -use starknet_api::block::FeeType; +use starknet_api::block::{BlockInfo, FeeType}; use starknet_api::core::{ContractAddress, Nonce}; use starknet_api::data_availability::DataAvailabilityMode; use starknet_api::execution_resources::GasVector; @@ -25,7 +25,6 @@ use starknet_api::transaction::{ }; use crate::abi::constants as abi_constants; -use crate::blockifier::block::BlockInfo; use crate::execution::call_info::{CallInfo, ExecutionSummary}; use crate::execution::stack_trace::ErrorStack; use crate::fee::fee_checks::FeeCheckError; diff --git a/crates/blockifier_reexecution/src/state_reader/raw_rpc_json_test.rs b/crates/blockifier_reexecution/src/state_reader/raw_rpc_json_test.rs index 0fdd100f81..04a422b9c8 100644 --- a/crates/blockifier_reexecution/src/state_reader/raw_rpc_json_test.rs +++ b/crates/blockifier_reexecution/src/state_reader/raw_rpc_json_test.rs @@ -1,11 +1,10 @@ use std::collections::HashMap; use assert_matches::assert_matches; -use blockifier::blockifier::block::BlockInfo; use blockifier::state::cached_state::StateMaps; use pretty_assertions::assert_eq; use rstest::{fixture, rstest}; -use starknet_api::block::BlockNumber; +use starknet_api::block::{BlockInfo, BlockNumber}; use starknet_api::test_utils::read_json_file; use starknet_api::transaction::{ DeclareTransaction, diff --git a/crates/blockifier_reexecution/src/state_reader/rpc_https_test.rs b/crates/blockifier_reexecution/src/state_reader/rpc_https_test.rs index d3595d67a6..bce11597c6 100644 --- a/crates/blockifier_reexecution/src/state_reader/rpc_https_test.rs +++ b/crates/blockifier_reexecution/src/state_reader/rpc_https_test.rs @@ -13,9 +13,8 @@ use std::env; use std::sync::{Arc, Mutex}; use assert_matches::assert_matches; -use blockifier::blockifier::block::BlockInfo; use rstest::{fixture, rstest}; -use starknet_api::block::BlockNumber; +use starknet_api::block::{BlockInfo, BlockNumber}; use starknet_api::class_hash; use starknet_api::core::ChainId; use starknet_api::transaction::{ diff --git a/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs b/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs index 7ebb38ac31..86cd5310a8 100644 --- a/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs +++ b/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs @@ -4,7 +4,6 @@ use std::sync::{Arc, Mutex}; use assert_matches::assert_matches; use blockifier::abi::constants; -use blockifier::blockifier::block::BlockInfo; use blockifier::blockifier::config::TransactionExecutorConfig; use blockifier::blockifier::transaction_executor::TransactionExecutor; use blockifier::bouncer::BouncerConfig; @@ -17,7 +16,7 @@ use blockifier::transaction::transaction_execution::Transaction as BlockifierTra use blockifier::versioned_constants::VersionedConstants; use serde::{Deserialize, Serialize}; use serde_json::{json, to_value}; -use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber, StarknetVersion}; +use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockInfo, BlockNumber, StarknetVersion}; use starknet_api::core::{ChainId, ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; use starknet_api::transaction::{Transaction, TransactionHash}; diff --git a/crates/native_blockifier/src/py_state_diff.rs b/crates/native_blockifier/src/py_state_diff.rs index 70ea8fb9d1..76a6063cbe 100644 --- a/crates/native_blockifier/src/py_state_diff.rs +++ b/crates/native_blockifier/src/py_state_diff.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::convert::TryFrom; -use blockifier::blockifier::block::{validated_gas_prices, BlockInfo}; +use blockifier::blockifier::block::validated_gas_prices; use blockifier::state::cached_state::CommitmentStateDiff; use blockifier::test_utils::{ DEFAULT_ETH_L1_DATA_GAS_PRICE, @@ -13,7 +13,7 @@ use blockifier::versioned_constants::VersionedConstants; use indexmap::IndexMap; use pyo3::prelude::*; use pyo3::FromPyObject; -use starknet_api::block::{BlockNumber, BlockTimestamp, NonzeroGasPrice}; +use starknet_api::block::{BlockInfo, BlockNumber, BlockTimestamp, NonzeroGasPrice}; use starknet_api::core::{ClassHash, ContractAddress, Nonce}; use starknet_api::state::{StateDiff, StorageKey}; diff --git a/crates/papyrus_execution/src/lib.rs b/crates/papyrus_execution/src/lib.rs index 6ed407c2dd..77e5348e4a 100644 --- a/crates/papyrus_execution/src/lib.rs +++ b/crates/papyrus_execution/src/lib.rs @@ -23,7 +23,7 @@ use std::cell::Cell; use std::collections::BTreeMap; use std::sync::{Arc, LazyLock}; -use blockifier::blockifier::block::{pre_process_block, validated_gas_prices, BlockInfo}; +use blockifier::blockifier::block::{pre_process_block, validated_gas_prices}; use blockifier::bouncer::BouncerConfig; use blockifier::context::{BlockContext, ChainInfo, FeeTokenAddresses, TransactionContext}; use blockifier::execution::call_info::CallExecution; @@ -51,7 +51,13 @@ use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use papyrus_storage::header::HeaderStorageReader; use papyrus_storage::{StorageError, StorageReader}; use serde::{Deserialize, Serialize}; -use starknet_api::block::{BlockHashAndNumber, BlockNumber, NonzeroGasPrice, StarknetVersion}; +use starknet_api::block::{ + BlockHashAndNumber, + BlockInfo, + BlockNumber, + NonzeroGasPrice, + StarknetVersion, +}; use starknet_api::contract_class::{ClassInfo, EntryPointType}; use starknet_api::core::{ChainId, ClassHash, ContractAddress, EntryPointSelector}; use starknet_api::data_availability::L1DataAvailabilityMode; diff --git a/crates/starknet_api/src/block.rs b/crates/starknet_api/src/block.rs index 2e89212e8e..cef053fd29 100644 --- a/crates/starknet_api/src/block.rs +++ b/crates/starknet_api/src/block.rs @@ -9,6 +9,7 @@ use starknet_types_core::hash::{Poseidon, StarkHash as CoreStarkHash}; use strum_macros::EnumIter; use crate::core::{ + ContractAddress, EventCommitment, GlobalRoot, ReceiptCommitment, @@ -484,6 +485,17 @@ impl GasPrices { )] pub struct BlockTimestamp(pub u64); +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct BlockInfo { + pub block_number: BlockNumber, + pub block_timestamp: BlockTimestamp, + + // Fee-related. + pub sequencer_address: ContractAddress, + pub gas_prices: GasPrices, + pub use_kzg_da: bool, +} + /// The signature of a [Block](`crate::block::Block`), signed by the sequencer. The signed message /// is defined as poseidon_hash(block_hash, state_diff_commitment). #[derive( diff --git a/crates/starknet_batcher/src/block_builder.rs b/crates/starknet_batcher/src/block_builder.rs index 0e72c761ff..ef7fcfb6e9 100644 --- a/crates/starknet_batcher/src/block_builder.rs +++ b/crates/starknet_batcher/src/block_builder.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use async_trait::async_trait; -use blockifier::blockifier::block::{validated_gas_prices, BlockInfo}; +use blockifier::blockifier::block::validated_gas_prices; use blockifier::blockifier::config::TransactionExecutorConfig; use blockifier::blockifier::transaction_executor::{ TransactionExecutor, @@ -26,7 +26,13 @@ use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use papyrus_state_reader::papyrus_state::PapyrusReader; use papyrus_storage::StorageReader; use serde::{Deserialize, Serialize}; -use starknet_api::block::{BlockHashAndNumber, BlockNumber, BlockTimestamp, NonzeroGasPrice}; +use starknet_api::block::{ + BlockHashAndNumber, + BlockInfo, + BlockNumber, + BlockTimestamp, + NonzeroGasPrice, +}; use starknet_api::core::ContractAddress; use starknet_api::executable_transaction::Transaction; use starknet_api::transaction::TransactionHash; diff --git a/crates/starknet_gateway/src/rpc_objects.rs b/crates/starknet_gateway/src/rpc_objects.rs index 5333f6e1cc..78ec71f82a 100644 --- a/crates/starknet_gateway/src/rpc_objects.rs +++ b/crates/starknet_gateway/src/rpc_objects.rs @@ -1,7 +1,14 @@ -use blockifier::blockifier::block::{validated_gas_prices, BlockInfo}; +use blockifier::blockifier::block::validated_gas_prices; use serde::{Deserialize, Serialize}; use serde_json::Value; -use starknet_api::block::{BlockHash, BlockNumber, BlockTimestamp, GasPrice, NonzeroGasPrice}; +use starknet_api::block::{ + BlockHash, + BlockInfo, + BlockNumber, + BlockTimestamp, + GasPrice, + NonzeroGasPrice, +}; use starknet_api::core::{ClassHash, ContractAddress, GlobalRoot}; use starknet_api::data_availability::L1DataAvailabilityMode; use starknet_api::state::StorageKey; diff --git a/crates/starknet_gateway/src/rpc_state_reader.rs b/crates/starknet_gateway/src/rpc_state_reader.rs index fa4e5fc684..a01ccdc703 100644 --- a/crates/starknet_gateway/src/rpc_state_reader.rs +++ b/crates/starknet_gateway/src/rpc_state_reader.rs @@ -1,4 +1,3 @@ -use blockifier::blockifier::block::BlockInfo; use blockifier::execution::contract_class::{ CompiledClassV0, CompiledClassV1, @@ -10,7 +9,7 @@ use papyrus_rpc::CompiledContractClass; use reqwest::blocking::Client as BlockingClient; use serde::Serialize; use serde_json::{json, Value}; -use starknet_api::block::BlockNumber; +use starknet_api::block::{BlockInfo, BlockNumber}; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; use starknet_types_core::felt::Felt; diff --git a/crates/starknet_gateway/src/state_reader.rs b/crates/starknet_gateway/src/state_reader.rs index 4109a426ee..b026bbe6ef 100644 --- a/crates/starknet_gateway/src/state_reader.rs +++ b/crates/starknet_gateway/src/state_reader.rs @@ -1,10 +1,9 @@ -use blockifier::blockifier::block::BlockInfo; use blockifier::execution::contract_class::RunnableCompiledClass; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader as BlockifierStateReader, StateResult}; #[cfg(test)] use mockall::automock; -use starknet_api::block::BlockNumber; +use starknet_api::block::{BlockInfo, BlockNumber}; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; use starknet_types_core::felt::Felt; diff --git a/crates/starknet_gateway/src/state_reader_test_utils.rs b/crates/starknet_gateway/src/state_reader_test_utils.rs index 45184de5d4..80c8fc8b51 100644 --- a/crates/starknet_gateway/src/state_reader_test_utils.rs +++ b/crates/starknet_gateway/src/state_reader_test_utils.rs @@ -1,4 +1,3 @@ -use blockifier::blockifier::block::BlockInfo; use blockifier::context::BlockContext; use blockifier::execution::contract_class::RunnableCompiledClass; use blockifier::state::errors::StateError; @@ -7,7 +6,7 @@ use blockifier::test_utils::contracts::FeatureContract; use blockifier::test_utils::dict_state_reader::DictStateReader; use blockifier::test_utils::initial_test_state::test_state; use blockifier::test_utils::{CairoVersion, BALANCE}; -use starknet_api::block::BlockNumber; +use starknet_api::block::{BlockInfo, BlockNumber}; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; use starknet_api::transaction::fields::Fee; diff --git a/crates/starknet_gateway/src/stateful_transaction_validator.rs b/crates/starknet_gateway/src/stateful_transaction_validator.rs index ddcbe80e87..db04f52c79 100644 --- a/crates/starknet_gateway/src/stateful_transaction_validator.rs +++ b/crates/starknet_gateway/src/stateful_transaction_validator.rs @@ -1,4 +1,3 @@ -use blockifier::blockifier::block::BlockInfo; use blockifier::blockifier::stateful_validator::{ StatefulValidator, StatefulValidatorResult as BlockifierStatefulValidatorResult, @@ -10,6 +9,7 @@ use blockifier::transaction::account_transaction::AccountTransaction; use blockifier::versioned_constants::VersionedConstants; #[cfg(test)] use mockall::automock; +use starknet_api::block::BlockInfo; use starknet_api::core::{ContractAddress, Nonce}; use starknet_api::executable_transaction::{ AccountTransaction as ExecutableTransaction, From be65c40c6b10f7a3a2d2b1e6966d17577afc5a37 Mon Sep 17 00:00:00 2001 From: aner-starkware <147302140+aner-starkware@users.noreply.github.com> Date: Thu, 28 Nov 2024 13:15:24 +0200 Subject: [PATCH 14/25] refactor(blockifier_reexecution): move offline reader to separate file (#2312) --- crates/blockifier_reexecution/src/main.rs | 6 +- .../src/state_reader.rs | 1 + .../src/state_reader/errors.rs | 2 + .../src/state_reader/offline_state_reader.rs | 259 ++++++++++++++++++ .../state_reader/reexecution_state_reader.rs | 22 +- .../src/state_reader/serde_utils.rs | 2 +- .../src/state_reader/test_state_reader.rs | 259 +----------------- .../src/state_reader/utils.rs | 11 +- 8 files changed, 297 insertions(+), 265 deletions(-) create mode 100644 crates/blockifier_reexecution/src/state_reader/offline_state_reader.rs diff --git a/crates/blockifier_reexecution/src/main.rs b/crates/blockifier_reexecution/src/main.rs index a60c2f39fc..fa99d0ecc2 100644 --- a/crates/blockifier_reexecution/src/main.rs +++ b/crates/blockifier_reexecution/src/main.rs @@ -1,10 +1,8 @@ use std::fs; use std::path::Path; -use blockifier_reexecution::state_reader::test_state_reader::{ - ConsecutiveTestStateReaders, - OfflineConsecutiveStateReaders, -}; +use blockifier_reexecution::state_reader::offline_state_reader::OfflineConsecutiveStateReaders; +use blockifier_reexecution::state_reader::test_state_reader::ConsecutiveTestStateReaders; use blockifier_reexecution::state_reader::utils::{ get_block_numbers_for_reexecution, guess_chain_id_from_node_url, diff --git a/crates/blockifier_reexecution/src/state_reader.rs b/crates/blockifier_reexecution/src/state_reader.rs index 8b5cb9b259..65e7dec158 100644 --- a/crates/blockifier_reexecution/src/state_reader.rs +++ b/crates/blockifier_reexecution/src/state_reader.rs @@ -1,5 +1,6 @@ pub mod compile; mod errors; +pub mod offline_state_reader; #[cfg(test)] pub mod raw_rpc_json_test; pub mod reexecution_state_reader; diff --git a/crates/blockifier_reexecution/src/state_reader/errors.rs b/crates/blockifier_reexecution/src/state_reader/errors.rs index 62068142c9..822bbf9c7a 100644 --- a/crates/blockifier_reexecution/src/state_reader/errors.rs +++ b/crates/blockifier_reexecution/src/state_reader/errors.rs @@ -24,3 +24,5 @@ pub enum ReexecutionError { #[error(transparent)] VersionedConstants(#[from] VersionedConstantsError), } + +pub type ReexecutionResult = Result; diff --git a/crates/blockifier_reexecution/src/state_reader/offline_state_reader.rs b/crates/blockifier_reexecution/src/state_reader/offline_state_reader.rs new file mode 100644 index 0000000000..bc2f1277a6 --- /dev/null +++ b/crates/blockifier_reexecution/src/state_reader/offline_state_reader.rs @@ -0,0 +1,259 @@ +use std::fs; + +use blockifier::abi::constants; +use blockifier::blockifier::block::BlockInfo; +use blockifier::blockifier::config::TransactionExecutorConfig; +use blockifier::blockifier::transaction_executor::TransactionExecutor; +use blockifier::bouncer::BouncerConfig; +use blockifier::context::BlockContext; +use blockifier::execution::contract_class::RunnableCompiledClass; +use blockifier::state::cached_state::{CommitmentStateDiff, StateMaps}; +use blockifier::state::errors::StateError; +use blockifier::state::state_api::{StateReader, StateResult}; +use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction; +use blockifier::versioned_constants::VersionedConstants; +use serde::{Deserialize, Serialize}; +use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber, StarknetVersion}; +use starknet_api::core::{ChainId, ClassHash, CompiledClassHash, ContractAddress, Nonce}; +use starknet_api::state::StorageKey; +use starknet_api::transaction::{Transaction, TransactionHash}; +use starknet_core::types::ContractClass as StarknetContractClass; +use starknet_types_core::felt::Felt; + +use crate::state_reader::compile::{legacy_to_contract_class_v0, sierra_to_contact_class_v1}; +use crate::state_reader::errors::ReexecutionResult; +use crate::state_reader::reexecution_state_reader::{ + ConsecutiveReexecutionStateReaders, + ReexecutionStateReader, +}; +use crate::state_reader::test_state_reader::StarknetContractClassMapping; +use crate::state_reader::utils::{get_chain_info, ReexecutionStateMaps}; + +pub struct OfflineReexecutionData { + offline_state_reader_prev_block: OfflineStateReader, + block_context_next_block: BlockContext, + transactions_next_block: Vec, + state_diff_next_block: CommitmentStateDiff, +} + +#[derive(Serialize, Deserialize)] +pub struct SerializableDataNextBlock { + pub block_info_next_block: BlockInfo, + pub starknet_version: StarknetVersion, + pub transactions_next_block: Vec<(Transaction, TransactionHash)>, + pub state_diff_next_block: CommitmentStateDiff, + pub declared_classes: StarknetContractClassMapping, +} + +#[derive(Serialize, Deserialize)] +pub struct SerializableDataPrevBlock { + pub state_maps: ReexecutionStateMaps, + pub contract_class_mapping: StarknetContractClassMapping, +} + +#[derive(Serialize, Deserialize)] +pub struct SerializableOfflineReexecutionData { + pub serializable_data_prev_block: SerializableDataPrevBlock, + pub serializable_data_next_block: SerializableDataNextBlock, + pub chain_id: ChainId, + pub old_block_hash: BlockHash, +} + +impl SerializableOfflineReexecutionData { + pub fn write_to_file(&self, full_file_path: &str) -> ReexecutionResult<()> { + let file_path = full_file_path.rsplit_once('/').expect("Invalid file path.").0; + fs::create_dir_all(file_path) + .unwrap_or_else(|err| panic!("Failed to create directory {file_path}. Error: {err}")); + fs::write(full_file_path, serde_json::to_string_pretty(&self)?) + .unwrap_or_else(|err| panic!("Failed to write to file {full_file_path}. Error: {err}")); + Ok(()) + } + + pub fn read_from_file(full_file_path: &str) -> ReexecutionResult { + let file_content = fs::read_to_string(full_file_path).unwrap_or_else(|err| { + panic!("Failed to read reexecution data from file {full_file_path}. Error: {err}") + }); + Ok(serde_json::from_str(&file_content)?) + } +} + +impl From for OfflineReexecutionData { + fn from(value: SerializableOfflineReexecutionData) -> Self { + let SerializableOfflineReexecutionData { + serializable_data_prev_block: + SerializableDataPrevBlock { state_maps, contract_class_mapping }, + serializable_data_next_block: + SerializableDataNextBlock { + block_info_next_block, + starknet_version, + transactions_next_block, + state_diff_next_block, + declared_classes, + }, + chain_id, + old_block_hash, + } = value; + + let offline_state_reader_prev_block = OfflineStateReader { + state_maps: state_maps.try_into().expect("Failed to deserialize state maps."), + contract_class_mapping, + old_block_hash, + }; + + // Use the declared classes from the next block to allow retrieving the class info. + let transactions_next_block = + OfflineStateReader { contract_class_mapping: declared_classes, ..Default::default() } + .api_txs_to_blockifier_txs_next_block(transactions_next_block) + .expect("Failed to convert starknet-api transactions to blockifier transactions."); + + Self { + offline_state_reader_prev_block, + block_context_next_block: BlockContext::new( + block_info_next_block, + get_chain_info(&chain_id), + VersionedConstants::get(&starknet_version).unwrap().clone(), + BouncerConfig::max(), + ), + transactions_next_block, + state_diff_next_block, + } + } +} + +#[derive(Default)] +pub struct OfflineStateReader { + pub state_maps: StateMaps, + pub contract_class_mapping: StarknetContractClassMapping, + pub old_block_hash: BlockHash, +} + +impl StateReader for OfflineStateReader { + fn get_storage_at( + &self, + contract_address: ContractAddress, + key: StorageKey, + ) -> StateResult { + Ok(*self.state_maps.storage.get(&(contract_address, key)).ok_or( + StateError::StateReadError(format!( + "Missing Storage Value at contract_address: {}, key:{:?}", + contract_address, key + )), + )?) + } + + fn get_nonce_at(&self, contract_address: ContractAddress) -> StateResult { + Ok(*self.state_maps.nonces.get(&contract_address).ok_or(StateError::StateReadError( + format!("Missing nonce at contract_address: {contract_address}"), + ))?) + } + + fn get_class_hash_at(&self, contract_address: ContractAddress) -> StateResult { + Ok(*self.state_maps.class_hashes.get(&contract_address).ok_or( + StateError::StateReadError(format!( + "Missing class hash at contract_address: {contract_address}" + )), + )?) + } + + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { + match self.get_contract_class(&class_hash)? { + StarknetContractClass::Sierra(sierra) => { + Ok(sierra_to_contact_class_v1(sierra).unwrap().try_into().unwrap()) + } + StarknetContractClass::Legacy(legacy) => { + Ok(legacy_to_contract_class_v0(legacy).unwrap().try_into().unwrap()) + } + } + } + + fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult { + Ok(*self + .state_maps + .compiled_class_hashes + .get(&class_hash) + .ok_or(StateError::UndeclaredClassHash(class_hash))?) + } +} + +impl ReexecutionStateReader for OfflineStateReader { + fn get_contract_class(&self, class_hash: &ClassHash) -> StateResult { + Ok(self + .contract_class_mapping + .get(class_hash) + .ok_or(StateError::UndeclaredClassHash(*class_hash))? + .clone()) + } + + fn get_old_block_hash(&self, _old_block_number: BlockNumber) -> ReexecutionResult { + Ok(self.old_block_hash) + } +} + +impl OfflineStateReader { + pub fn get_transaction_executor( + self, + block_context_next_block: BlockContext, + transaction_executor_config: Option, + ) -> ReexecutionResult> { + let old_block_number = BlockNumber( + block_context_next_block.block_info().block_number.0 + - constants::STORED_BLOCK_HASH_BUFFER, + ); + let hash = self.old_block_hash; + Ok(TransactionExecutor::::pre_process_and_create( + self, + block_context_next_block, + Some(BlockHashAndNumber { number: old_block_number, hash }), + transaction_executor_config.unwrap_or_default(), + )?) + } +} + +pub struct OfflineConsecutiveStateReaders { + pub offline_state_reader_prev_block: OfflineStateReader, + pub block_context_next_block: BlockContext, + pub transactions_next_block: Vec, + pub state_diff_next_block: CommitmentStateDiff, +} + +impl OfflineConsecutiveStateReaders { + pub fn new_from_file(full_file_path: &str) -> ReexecutionResult { + let serializable_offline_reexecution_data = + SerializableOfflineReexecutionData::read_from_file(full_file_path)?; + Ok(Self::new(serializable_offline_reexecution_data.into())) + } + + pub fn new( + OfflineReexecutionData { + offline_state_reader_prev_block, + block_context_next_block, + transactions_next_block, + state_diff_next_block, + }: OfflineReexecutionData, + ) -> Self { + Self { + offline_state_reader_prev_block, + block_context_next_block, + transactions_next_block, + state_diff_next_block, + } + } +} + +impl ConsecutiveReexecutionStateReaders for OfflineConsecutiveStateReaders { + fn pre_process_and_create_executor( + self, + transaction_executor_config: Option, + ) -> ReexecutionResult> { + self.offline_state_reader_prev_block + .get_transaction_executor(self.block_context_next_block, transaction_executor_config) + } + + fn get_next_block_txs(&self) -> ReexecutionResult> { + Ok(self.transactions_next_block.clone()) + } + + fn get_next_block_state_diff(&self) -> ReexecutionResult { + Ok(self.state_diff_next_block.clone()) + } +} diff --git a/crates/blockifier_reexecution/src/state_reader/reexecution_state_reader.rs b/crates/blockifier_reexecution/src/state_reader/reexecution_state_reader.rs index c500344c84..3e3c3f030d 100644 --- a/crates/blockifier_reexecution/src/state_reader/reexecution_state_reader.rs +++ b/crates/blockifier_reexecution/src/state_reader/reexecution_state_reader.rs @@ -1,4 +1,7 @@ -use blockifier::state::state_api::StateResult; +use blockifier::blockifier::config::TransactionExecutorConfig; +use blockifier::blockifier::transaction_executor::TransactionExecutor; +use blockifier::state::cached_state::CommitmentStateDiff; +use blockifier::state::state_api::{StateReader, StateResult}; use blockifier::test_utils::MAX_FEE; use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction; use papyrus_execution::DEPRECATED_CONTRACT_SIERRA_SIZE; @@ -8,9 +11,8 @@ use starknet_api::core::ClassHash; use starknet_api::transaction::{Transaction, TransactionHash}; use starknet_core::types::ContractClass as StarknetContractClass; -use super::compile::{legacy_to_contract_class_v0, sierra_to_contact_class_v1}; -use crate::state_reader::errors::ReexecutionError; -use crate::state_reader::test_state_reader::ReexecutionResult; +use crate::state_reader::compile::{legacy_to_contract_class_v0, sierra_to_contact_class_v1}; +use crate::state_reader::errors::{ReexecutionError, ReexecutionResult}; pub trait ReexecutionStateReader { fn get_contract_class(&self, class_hash: &ClassHash) -> StateResult; @@ -76,3 +78,15 @@ pub trait ReexecutionStateReader { fn get_old_block_hash(&self, old_block_number: BlockNumber) -> ReexecutionResult; } + +/// Trait of the functions \ queries required for reexecution. +pub trait ConsecutiveReexecutionStateReaders { + fn pre_process_and_create_executor( + self, + transaction_executor_config: Option, + ) -> ReexecutionResult>; + + fn get_next_block_txs(&self) -> ReexecutionResult>; + + fn get_next_block_state_diff(&self) -> ReexecutionResult; +} diff --git a/crates/blockifier_reexecution/src/state_reader/serde_utils.rs b/crates/blockifier_reexecution/src/state_reader/serde_utils.rs index 568da2b3b1..d57d95b1ef 100644 --- a/crates/blockifier_reexecution/src/state_reader/serde_utils.rs +++ b/crates/blockifier_reexecution/src/state_reader/serde_utils.rs @@ -8,7 +8,7 @@ use starknet_api::transaction::{ Transaction, }; -use crate::state_reader::test_state_reader::ReexecutionResult; +use crate::state_reader::errors::ReexecutionResult; /// In old transaction, the resource bounds names are lowercase. /// need to convert to uppercase for deserialization to work. diff --git a/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs b/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs index 86cd5310a8..a17432379a 100644 --- a/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs +++ b/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; -use std::fs; use std::sync::{Arc, Mutex}; use assert_matches::assert_matches; @@ -9,12 +8,12 @@ use blockifier::blockifier::transaction_executor::TransactionExecutor; use blockifier::bouncer::BouncerConfig; use blockifier::context::BlockContext; use blockifier::execution::contract_class::RunnableCompiledClass; -use blockifier::state::cached_state::{CommitmentStateDiff, StateMaps}; +use blockifier::state::cached_state::CommitmentStateDiff; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader, StateResult}; use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction; use blockifier::versioned_constants::VersionedConstants; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use serde_json::{json, to_value}; use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockInfo, BlockNumber, StarknetVersion}; use starknet_api::core::{ChainId, ClassHash, CompiledClassHash, ContractAddress, Nonce}; @@ -34,8 +33,12 @@ use starknet_types_core::felt::Felt; use crate::retry_request; use crate::state_reader::compile::{legacy_to_contract_class_v0, sierra_to_contact_class_v1}; -use crate::state_reader::errors::ReexecutionError; -use crate::state_reader::reexecution_state_reader::ReexecutionStateReader; +use crate::state_reader::errors::ReexecutionResult; +use crate::state_reader::offline_state_reader::SerializableDataNextBlock; +use crate::state_reader::reexecution_state_reader::{ + ConsecutiveReexecutionStateReaders, + ReexecutionStateReader, +}; use crate::state_reader::serde_utils::{ deserialize_transaction_json_to_starknet_api_tx, hashmap_from_raw, @@ -45,7 +48,6 @@ use crate::state_reader::utils::{ disjoint_hashmap_union, get_chain_info, get_rpc_state_reader_config, - ReexecutionStateMaps, }; pub const DEFAULT_RETRY_COUNT: usize = 3; @@ -54,101 +56,8 @@ pub const DEFAULT_EXPECTED_ERROR_STRINGS: [&str; 3] = ["Connection error", "RPCError", "429 Too Many Requests"]; pub const DEFAULT_RETRY_FAILURE_MESSAGE: &str = "Failed to connect to the RPC node."; -pub type ReexecutionResult = Result; - pub type StarknetContractClassMapping = HashMap; -pub struct OfflineReexecutionData { - offline_state_reader_prev_block: OfflineStateReader, - block_context_next_block: BlockContext, - transactions_next_block: Vec, - state_diff_next_block: CommitmentStateDiff, -} - -#[derive(Serialize, Deserialize)] -pub struct SerializableDataNextBlock { - pub block_info_next_block: BlockInfo, - pub starknet_version: StarknetVersion, - pub transactions_next_block: Vec<(Transaction, TransactionHash)>, - pub state_diff_next_block: CommitmentStateDiff, - pub declared_classes: StarknetContractClassMapping, -} - -#[derive(Serialize, Deserialize)] -pub struct SerializableDataPrevBlock { - pub state_maps: ReexecutionStateMaps, - pub contract_class_mapping: StarknetContractClassMapping, -} - -#[derive(Serialize, Deserialize)] -pub struct SerializableOfflineReexecutionData { - pub serializable_data_prev_block: SerializableDataPrevBlock, - pub serializable_data_next_block: SerializableDataNextBlock, - pub chain_id: ChainId, - pub old_block_hash: BlockHash, -} - -impl SerializableOfflineReexecutionData { - pub fn write_to_file(&self, full_file_path: &str) -> ReexecutionResult<()> { - let file_path = full_file_path.rsplit_once('/').expect("Invalid file path.").0; - fs::create_dir_all(file_path) - .unwrap_or_else(|err| panic!("Failed to create directory {file_path}. Error: {err}")); - fs::write(full_file_path, serde_json::to_string_pretty(&self)?) - .unwrap_or_else(|err| panic!("Failed to write to file {full_file_path}. Error: {err}")); - Ok(()) - } - - pub fn read_from_file(full_file_path: &str) -> ReexecutionResult { - let file_content = fs::read_to_string(full_file_path).unwrap_or_else(|err| { - panic!("Failed to read reexecution data from file {full_file_path}. Error: {err}") - }); - Ok(serde_json::from_str(&file_content)?) - } -} - -impl From for OfflineReexecutionData { - fn from(value: SerializableOfflineReexecutionData) -> Self { - let SerializableOfflineReexecutionData { - serializable_data_prev_block: - SerializableDataPrevBlock { state_maps, contract_class_mapping }, - serializable_data_next_block: - SerializableDataNextBlock { - block_info_next_block, - starknet_version, - transactions_next_block, - state_diff_next_block, - declared_classes, - }, - chain_id, - old_block_hash, - } = value; - - let offline_state_reader_prev_block = OfflineStateReader { - state_maps: state_maps.try_into().expect("Failed to deserialize state maps."), - contract_class_mapping, - old_block_hash, - }; - - // Use the declared classes from the next block to allow retrieving the class info. - let transactions_next_block = - OfflineStateReader { contract_class_mapping: declared_classes, ..Default::default() } - .api_txs_to_blockifier_txs_next_block(transactions_next_block) - .expect("Failed to convert starknet-api transactions to blockifier transactions."); - - Self { - offline_state_reader_prev_block, - block_context_next_block: BlockContext::new( - block_info_next_block, - get_chain_info(&chain_id), - VersionedConstants::get(&starknet_version).unwrap().clone(), - BouncerConfig::max(), - ), - transactions_next_block, - state_diff_next_block, - } - } -} - // TODO(Aviv): Consider moving to the gateway state reader. /// Params for the RPC request "starknet_getTransactionByHash". #[derive(Serialize)] @@ -453,18 +362,6 @@ impl ReexecutionStateReader for TestStateReader { } } -/// Trait of the functions \ queries required for reexecution. -pub trait ConsecutiveStateReaders { - fn pre_process_and_create_executor( - self, - transaction_executor_config: Option, - ) -> ReexecutionResult>; - - fn get_next_block_txs(&self) -> ReexecutionResult>; - - fn get_next_block_state_diff(&self) -> ReexecutionResult; -} - pub struct ConsecutiveTestStateReaders { pub last_block_state_reader: TestStateReader, pub next_block_state_reader: TestStateReader, @@ -530,7 +427,7 @@ impl ConsecutiveTestStateReaders { } } -impl ConsecutiveStateReaders for ConsecutiveTestStateReaders { +impl ConsecutiveReexecutionStateReaders for ConsecutiveTestStateReaders { fn pre_process_and_create_executor( self, transaction_executor_config: Option, @@ -551,141 +448,3 @@ impl ConsecutiveStateReaders for ConsecutiveTestStateReaders { self.next_block_state_reader.get_state_diff() } } - -#[derive(Default)] -pub struct OfflineStateReader { - pub state_maps: StateMaps, - pub contract_class_mapping: StarknetContractClassMapping, - pub old_block_hash: BlockHash, -} - -impl StateReader for OfflineStateReader { - fn get_storage_at( - &self, - contract_address: ContractAddress, - key: StorageKey, - ) -> StateResult { - Ok(*self.state_maps.storage.get(&(contract_address, key)).ok_or( - StateError::StateReadError(format!( - "Missing Storage Value at contract_address: {}, key:{:?}", - contract_address, key - )), - )?) - } - - fn get_nonce_at(&self, contract_address: ContractAddress) -> StateResult { - Ok(*self.state_maps.nonces.get(&contract_address).ok_or(StateError::StateReadError( - format!("Missing nonce at contract_address: {contract_address}"), - ))?) - } - - fn get_class_hash_at(&self, contract_address: ContractAddress) -> StateResult { - Ok(*self.state_maps.class_hashes.get(&contract_address).ok_or( - StateError::StateReadError(format!( - "Missing class hash at contract_address: {contract_address}" - )), - )?) - } - - fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { - match self.get_contract_class(&class_hash)? { - StarknetContractClass::Sierra(sierra) => { - Ok(sierra_to_contact_class_v1(sierra).unwrap().try_into().unwrap()) - } - StarknetContractClass::Legacy(legacy) => { - Ok(legacy_to_contract_class_v0(legacy).unwrap().try_into().unwrap()) - } - } - } - - fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult { - Ok(*self - .state_maps - .compiled_class_hashes - .get(&class_hash) - .ok_or(StateError::UndeclaredClassHash(class_hash))?) - } -} - -impl ReexecutionStateReader for OfflineStateReader { - fn get_contract_class(&self, class_hash: &ClassHash) -> StateResult { - Ok(self - .contract_class_mapping - .get(class_hash) - .ok_or(StateError::UndeclaredClassHash(*class_hash))? - .clone()) - } - - fn get_old_block_hash(&self, _old_block_number: BlockNumber) -> ReexecutionResult { - Ok(self.old_block_hash) - } -} - -impl OfflineStateReader { - pub fn get_transaction_executor( - self, - block_context_next_block: BlockContext, - transaction_executor_config: Option, - ) -> ReexecutionResult> { - let old_block_number = BlockNumber( - block_context_next_block.block_info().block_number.0 - - constants::STORED_BLOCK_HASH_BUFFER, - ); - let hash = self.old_block_hash; - Ok(TransactionExecutor::::pre_process_and_create( - self, - block_context_next_block, - Some(BlockHashAndNumber { number: old_block_number, hash }), - transaction_executor_config.unwrap_or_default(), - )?) - } -} - -pub struct OfflineConsecutiveStateReaders { - pub offline_state_reader_prev_block: OfflineStateReader, - pub block_context_next_block: BlockContext, - pub transactions_next_block: Vec, - pub state_diff_next_block: CommitmentStateDiff, -} - -impl OfflineConsecutiveStateReaders { - pub fn new_from_file(full_file_path: &str) -> ReexecutionResult { - let serializable_offline_reexecution_data = - SerializableOfflineReexecutionData::read_from_file(full_file_path)?; - Ok(Self::new(serializable_offline_reexecution_data.into())) - } - - pub fn new( - OfflineReexecutionData { - offline_state_reader_prev_block, - block_context_next_block, - transactions_next_block, - state_diff_next_block, - }: OfflineReexecutionData, - ) -> Self { - Self { - offline_state_reader_prev_block, - block_context_next_block, - transactions_next_block, - state_diff_next_block, - } - } -} - -impl ConsecutiveStateReaders for OfflineConsecutiveStateReaders { - fn pre_process_and_create_executor( - self, - transaction_executor_config: Option, - ) -> ReexecutionResult> { - self.offline_state_reader_prev_block - .get_transaction_executor(self.block_context_next_block, transaction_executor_config) - } - - fn get_next_block_txs(&self) -> ReexecutionResult> { - Ok(self.transactions_next_block.clone()) - } - - fn get_next_block_state_diff(&self) -> ReexecutionResult { - Ok(self.state_diff_next_block.clone()) - } -} diff --git a/crates/blockifier_reexecution/src/state_reader/utils.rs b/crates/blockifier_reexecution/src/state_reader/utils.rs index 8a6d55801a..3742e1e033 100644 --- a/crates/blockifier_reexecution/src/state_reader/utils.rs +++ b/crates/blockifier_reexecution/src/state_reader/utils.rs @@ -18,15 +18,14 @@ use starknet_gateway::config::RpcStateReaderConfig; use starknet_types_core::felt::Felt; use crate::assert_eq_state_diff; -use crate::state_reader::errors::ReexecutionError; -use crate::state_reader::test_state_reader::{ - ConsecutiveStateReaders, - ConsecutiveTestStateReaders, +use crate::state_reader::errors::{ReexecutionError, ReexecutionResult}; +use crate::state_reader::offline_state_reader::{ OfflineConsecutiveStateReaders, - ReexecutionResult, SerializableDataPrevBlock, SerializableOfflineReexecutionData, }; +use crate::state_reader::reexecution_state_reader::ConsecutiveReexecutionStateReaders; +use crate::state_reader::test_state_reader::ConsecutiveTestStateReaders; pub static RPC_NODE_URL: LazyLock = LazyLock::new(|| { env::var("TEST_URL") @@ -218,7 +217,7 @@ impl From for ComparableStateDiff { pub fn reexecute_and_verify_correctness< S: StateReader + Send + Sync, - T: ConsecutiveStateReaders, + T: ConsecutiveReexecutionStateReaders, >( consecutive_state_readers: T, ) -> Option> { From 097b23ab20ab041be2ad1bcaf4427d09d6cd63bf Mon Sep 17 00:00:00 2001 From: Yael Doweck Date: Thu, 28 Nov 2024 11:12:32 +0200 Subject: [PATCH 15/25] fix(batcher): assert when using the transaction_provider with n_txs=0 --- crates/starknet_batcher/src/transaction_provider.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/starknet_batcher/src/transaction_provider.rs b/crates/starknet_batcher/src/transaction_provider.rs index 50324a890b..672daed899 100644 --- a/crates/starknet_batcher/src/transaction_provider.rs +++ b/crates/starknet_batcher/src/transaction_provider.rs @@ -83,6 +83,7 @@ impl ProposeTransactionProvider { #[async_trait] impl TransactionProvider for ProposeTransactionProvider { async fn get_txs(&mut self, n_txs: usize) -> Result { + assert!(n_txs > 0, "The number of transactions requested must be greater than zero."); let mut txs = vec![]; if self.phase == TxProviderPhase::L1 { let n_l1handler_txs_to_get = @@ -118,6 +119,7 @@ pub struct ValidateTransactionProvider { #[async_trait] impl TransactionProvider for ValidateTransactionProvider { async fn get_txs(&mut self, n_txs: usize) -> Result { + assert!(n_txs > 0, "The number of transactions requested must be greater than zero."); let mut buffer = Vec::with_capacity(n_txs); self.tx_receiver.recv_many(&mut buffer, n_txs).await; // If the buffer is empty, it means that the stream was dropped, otherwise it would have From 822f957c1242bfea2ff730c58eb6df0b871362c3 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 28 Nov 2024 14:31:41 +0200 Subject: [PATCH 16/25] chore(blockifier): fix block info import post merge conflict (#2334) --- .../src/state_reader/offline_state_reader.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/blockifier_reexecution/src/state_reader/offline_state_reader.rs b/crates/blockifier_reexecution/src/state_reader/offline_state_reader.rs index bc2f1277a6..d3f9b3ce89 100644 --- a/crates/blockifier_reexecution/src/state_reader/offline_state_reader.rs +++ b/crates/blockifier_reexecution/src/state_reader/offline_state_reader.rs @@ -1,7 +1,6 @@ use std::fs; use blockifier::abi::constants; -use blockifier::blockifier::block::BlockInfo; use blockifier::blockifier::config::TransactionExecutorConfig; use blockifier::blockifier::transaction_executor::TransactionExecutor; use blockifier::bouncer::BouncerConfig; @@ -13,7 +12,7 @@ use blockifier::state::state_api::{StateReader, StateResult}; use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction; use blockifier::versioned_constants::VersionedConstants; use serde::{Deserialize, Serialize}; -use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber, StarknetVersion}; +use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockInfo, BlockNumber, StarknetVersion}; use starknet_api::core::{ChainId, ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; use starknet_api::transaction::{Transaction, TransactionHash}; From d11aeecedde37900aee2852c5e48a7d59e48516e Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 28 Nov 2024 14:50:17 +0200 Subject: [PATCH 17/25] test(starknet_api): remove warning on clone in transaction test (#2335) --- crates/starknet_api/src/transaction_test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/starknet_api/src/transaction_test.rs b/crates/starknet_api/src/transaction_test.rs index 3c029603b5..82759324a9 100644 --- a/crates/starknet_api/src/transaction_test.rs +++ b/crates/starknet_api/src/transaction_test.rs @@ -49,7 +49,7 @@ fn convert_executable_transaction_and_back() { } } }; - let executable_tx: ExecutableTransaction = (tx.clone(), tx_hash.clone()).into(); + let executable_tx: ExecutableTransaction = (tx.clone(), tx_hash).into(); let tx_back = Transaction::from(executable_tx); assert_eq!(tx, tx_back); } From 8d94e22c216a7757582208587454bda2749fb010 Mon Sep 17 00:00:00 2001 From: avi-starkware Date: Thu, 28 Nov 2024 15:09:47 +0200 Subject: [PATCH 18/25] feat(cairo_native): add batcher compiler struct (#2187) --- Cargo.lock | 1 + crates/blockifier/Cargo.toml | 3 +- crates/blockifier/src/state.rs | 2 + .../src/state/contract_class_manager.rs | 129 ++++++++++++++++++ crates/blockifier/src/state/global_cache.rs | 28 ++-- 5 files changed, 148 insertions(+), 15 deletions(-) create mode 100644 crates/blockifier/src/state/contract_class_manager.rs diff --git a/Cargo.lock b/Cargo.lock index 763688914b..1b299a5a8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1518,6 +1518,7 @@ dependencies = [ "sha2", "starknet-types-core", "starknet_api", + "starknet_sierra_compile", "strum 0.25.0", "strum_macros 0.25.3", "tempfile", diff --git a/crates/blockifier/Cargo.toml b/crates/blockifier/Cargo.toml index 0df3a1419b..7f05e3127d 100644 --- a/crates/blockifier/Cargo.toml +++ b/crates/blockifier/Cargo.toml @@ -10,7 +10,7 @@ description = "The transaction-executing component in the Starknet sequencer." workspace = true [features] -cairo_native = ["dep:cairo-native"] +cairo_native = ["dep:cairo-native", "starknet_sierra_compile/cairo_native"] jemalloc = ["dep:tikv-jemallocator"] reexecution = ["transaction_serde"] testing = ["rand", "rstest", "starknet_api/testing"] @@ -50,6 +50,7 @@ serde_json = { workspace = true, features = ["arbitrary_precision"] } sha2.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true +starknet_sierra_compile = { workspace = true, optional = true } strum.workspace = true strum_macros.workspace = true tempfile.workspace = true diff --git a/crates/blockifier/src/state.rs b/crates/blockifier/src/state.rs index e027d2b301..8aa857c963 100644 --- a/crates/blockifier/src/state.rs +++ b/crates/blockifier/src/state.rs @@ -1,4 +1,6 @@ pub mod cached_state; +#[cfg(feature = "cairo_native")] +pub mod contract_class_manager; #[cfg(test)] pub mod error_format_test; pub mod errors; diff --git a/crates/blockifier/src/state/contract_class_manager.rs b/crates/blockifier/src/state/contract_class_manager.rs new file mode 100644 index 0000000000..6fcac067c1 --- /dev/null +++ b/crates/blockifier/src/state/contract_class_manager.rs @@ -0,0 +1,129 @@ +use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TrySendError}; +use std::sync::Arc; + +use log::{error, info}; +use starknet_api::core::ClassHash; +use starknet_api::state::SierraContractClass; +use starknet_sierra_compile::command_line_compiler::CommandLineCompiler; +use starknet_sierra_compile::config::SierraToCasmCompilationConfig; +use starknet_sierra_compile::utils::into_contract_class_for_compilation; +use starknet_sierra_compile::SierraToNativeCompiler; + +use crate::execution::contract_class::{CompiledClassV1, RunnableCompiledClass}; +use crate::execution::native::contract_class::NativeCompiledClassV1; +use crate::state::global_cache::{CachedCairoNative, ContractCaches}; + +const CHANNEL_SIZE: usize = 1000; + +/// Represents a request to compile a sierra contract class to a native compiled class. +/// +/// # Fields: +/// * `class_hash` - used to identify the contract class in the cache. +/// * `sierra_contract_class` - the sierra contract class to be compiled. +/// * `casm_compiled_class` - stored in [`NativeCompiledClassV1`] to allow fallback to cairo_vm +/// execution in case of unxecpected failure during native execution. +type CompilationRequest = (ClassHash, Arc, CompiledClassV1); + +/// Manages the global cache of contract classes and handles sierra-to-native compilation requests. +struct ContractClassManager { + // The global cache of contract classes: casm, sierra, and native. + contract_caches: Arc, + // The sending half of the compilation request channel. + sender: SyncSender, +} + +#[allow(dead_code)] +impl ContractClassManager { + /// Creates a new contract class manager and spawns a thread that listens for compilation + /// requests and processes them (a.k.a. the compilation worker). + /// Returns the contract class manager. + pub fn start(contract_caches: ContractCaches) -> ContractClassManager { + // TODO(Avi, 15/12/2024): Add the size of the channel to the config. + let contract_caches = Arc::new(contract_caches); + let (sender, receiver) = sync_channel(CHANNEL_SIZE); + let compiler_config = SierraToCasmCompilationConfig::default(); + let compiler = CommandLineCompiler::new(compiler_config); + + std::thread::spawn({ + let contract_caches = Arc::clone(&contract_caches); + let compiler = Arc::new(compiler); + + move || run_compilation_worker(contract_caches, receiver, compiler) + }); + + ContractClassManager { contract_caches, sender } + } + + /// Sends a compilation request to the compilation worker. Does not block the sender. Logs an + /// error is the channel is full. + pub fn send_compilation_request(&self, request: CompilationRequest) { + self.cache_request_contracts(&request); + // TODO(Avi, 15/12/2024): Check for duplicated requests. + self.sender.try_send(request).unwrap_or_else(|err| match err { + TrySendError::Full((class_hash, _, _)) => { + error!( + "Compilation request channel is full (size: {}). Compilation request for \ + class hash {} was not sent.", + CHANNEL_SIZE, class_hash + ) + } + TrySendError::Disconnected(_) => { + panic!("Compilation request channel is closed.") + } + }); + } + + /// Returns the native compiled class for the given class hash, if it exists in cache. + pub fn get_native(&self, class_hash: &ClassHash) -> Option { + self.contract_caches.get_native(class_hash) + } + + /// Returns the Sierra contract class for the given class hash, if it exists in cache. + pub fn get_sierra(&self, class_hash: &ClassHash) -> Option> { + self.contract_caches.get_sierra(class_hash) + } + + /// Returns the casm compiled class for the given class hash, if it exists in cache. + pub fn get_casm(&self, class_hash: &ClassHash) -> Option { + self.contract_caches.get_casm(class_hash) + } + + /// Caches the sierra and casm contract classes of a compilation request. + fn cache_request_contracts(&self, request: &CompilationRequest) { + let (class_hash, sierra, casm) = request.clone(); + self.contract_caches.set_sierra(class_hash, sierra); + let cached_casm = RunnableCompiledClass::from(casm); + self.contract_caches.set_casm(class_hash, cached_casm); + } +} + +/// Handles compilation requests from the channel, holding the receiver end of the channel. +/// If no request is available, non-busy-waits until a request is available. +/// When the sender is dropped, the worker processes all pending requests and terminates. +fn run_compilation_worker( + contract_caches: Arc, + receiver: Receiver, + compiler: Arc, +) { + info!("Compilation worker started."); + for (class_hash, sierra, casm) in receiver.iter() { + if contract_caches.get_native(&class_hash).is_some() { + // The contract class is already compiled to native - skip the compilation. + continue; + } + let sierra_for_compilation = into_contract_class_for_compilation(sierra.as_ref()); + let compilation_result = compiler.compile_to_native(sierra_for_compilation); + match compilation_result { + Ok(executor) => { + let native_compiled_class = NativeCompiledClassV1::new(executor, casm); + contract_caches + .set_native(class_hash, CachedCairoNative::Compiled(native_compiled_class)); + } + Err(err) => { + error!("Error compiling contract class: {}", err); + contract_caches.set_native(class_hash, CachedCairoNative::CompilationFailed); + } + } + } + info!("Compilation worker terminated."); +} diff --git a/crates/blockifier/src/state/global_cache.rs b/crates/blockifier/src/state/global_cache.rs index 46534a1839..f60df02f01 100644 --- a/crates/blockifier/src/state/global_cache.rs +++ b/crates/blockifier/src/state/global_cache.rs @@ -1,27 +1,27 @@ use std::sync::{Arc, Mutex, MutexGuard}; use cached::{Cached, SizedCache}; -#[cfg(feature = "cairo_native")] -use cairo_native::executor::AotContractExecutor; use starknet_api::core::ClassHash; #[cfg(feature = "cairo_native")] use starknet_api::state::SierraContractClass; #[cfg(feature = "cairo_native")] use crate::execution::contract_class::RunnableCompiledClass; +#[cfg(feature = "cairo_native")] +use crate::execution::native::contract_class::NativeCompiledClassV1; -type ContractClassLRUCache = SizedCache; -pub type LockedContractClassCache<'a, T> = MutexGuard<'a, ContractClassLRUCache>; +type ContractLRUCache = SizedCache; +pub type LockedClassCache<'a, T> = MutexGuard<'a, ContractLRUCache>; #[derive(Debug, Clone)] -// Thread-safe LRU cache for contract classes, optimized for inter-language sharing when -// `blockifier` compiles as a shared library. +// Thread-safe LRU cache for contract classes (Seirra or compiled Casm/Native), optimized for +// inter-language sharing when `blockifier` compiles as a shared library. // TODO(Yoni, 1/1/2025): consider defining CachedStateReader. -pub struct GlobalContractCache(pub Arc>>); +pub struct GlobalContractCache(pub Arc>>); #[cfg(feature = "cairo_native")] #[derive(Debug, Clone)] pub enum CachedCairoNative { - Compiled(AotContractExecutor), + Compiled(NativeCompiledClassV1), CompilationFailed, } @@ -30,7 +30,7 @@ pub const GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST: usize = 400; impl GlobalContractCache { /// Locks the cache for atomic access. Although conceptually shared, writing to this cache is /// only possible for one writer at a time. - pub fn lock(&self) -> LockedContractClassCache<'_, T> { + pub fn lock(&self) -> LockedClassCache<'_, T> { self.0.lock().expect("Global contract cache is poisoned.") } @@ -47,25 +47,25 @@ impl GlobalContractCache { } pub fn new(cache_size: usize) -> Self { - Self(Arc::new(Mutex::new(ContractClassLRUCache::::with_size(cache_size)))) + Self(Arc::new(Mutex::new(ContractLRUCache::::with_size(cache_size)))) } } #[cfg(feature = "cairo_native")] -pub struct GlobalContractCacheManager { +pub struct ContractCaches { pub casm_cache: GlobalContractCache, pub native_cache: GlobalContractCache, pub sierra_cache: GlobalContractCache>, } #[cfg(feature = "cairo_native")] -impl GlobalContractCacheManager { +impl ContractCaches { pub fn get_casm(&self, class_hash: &ClassHash) -> Option { self.casm_cache.get(class_hash) } - pub fn set_casm(&self, class_hash: ClassHash, contract_class: RunnableCompiledClass) { - self.casm_cache.set(class_hash, contract_class); + pub fn set_casm(&self, class_hash: ClassHash, compiled_class: RunnableCompiledClass) { + self.casm_cache.set(class_hash, compiled_class); } pub fn get_native(&self, class_hash: &ClassHash) -> Option { From acf13b2f8d80791dd808e2e60adad49213b62ae4 Mon Sep 17 00:00:00 2001 From: noam-starkware Date: Thu, 28 Nov 2024 15:28:14 +0200 Subject: [PATCH 19/25] refactor(starknet_api): use tx_hash constructor macro (#2287) --- .../deprecated_syscalls_test.rs | 5 ++--- .../syscall_tests/get_execution_info.rs | 6 ++--- .../src/converters/transaction_test.rs | 5 ++--- crates/papyrus_rpc/src/v0_8/api/test.rs | 22 +++++++++---------- crates/papyrus_rpc/src/v0_8/execution_test.rs | 20 ++++++++--------- .../src/v0_8/write_api_result_test.rs | 8 +++---- crates/papyrus_test_utils/src/lib.rs | 4 ++-- .../block_hash/block_hash_calculator_test.rs | 5 ++--- .../src/block_hash/event_commitment_test.rs | 6 ++--- .../src/block_hash/receipt_commitment_test.rs | 10 +++------ .../block_hash/transaction_commitment_test.rs | 7 +++--- crates/starknet_api/src/transaction.rs | 9 ++++++++ crates/starknet_batcher/src/batcher_test.rs | 4 ++-- .../src/block_builder_test.rs | 8 +++---- crates/starknet_batcher/src/test_utils.rs | 5 ++--- .../src/transaction_provider_test.rs | 5 ++--- .../src/reader/objects/block_test.rs | 6 ++--- .../src/l1_provider_tests.rs | 12 ++-------- crates/starknet_mempool/src/test_utils.rs | 12 ++++------ 19 files changed, 72 insertions(+), 87 deletions(-) diff --git a/crates/blockifier/src/execution/deprecated_syscalls/deprecated_syscalls_test.rs b/crates/blockifier/src/execution/deprecated_syscalls/deprecated_syscalls_test.rs index 33aad71bbe..7f04bb9abd 100644 --- a/crates/blockifier/src/execution/deprecated_syscalls/deprecated_syscalls_test.rs +++ b/crates/blockifier/src/execution/deprecated_syscalls/deprecated_syscalls_test.rs @@ -12,11 +12,10 @@ use starknet_api::transaction::{ EventContent, EventData, EventKey, - TransactionHash, TransactionVersion, QUERY_VERSION_BASE, }; -use starknet_api::{calldata, felt, nonce, storage_key}; +use starknet_api::{calldata, felt, nonce, storage_key, tx_hash}; use starknet_types_core::felt::Felt; use test_case::test_case; @@ -467,7 +466,7 @@ fn test_tx_info(#[values(false, true)] only_query: bool) { let simulate_version_base = *QUERY_VERSION_BASE; version += simulate_version_base; } - let tx_hash = TransactionHash(felt!(1991_u16)); + let tx_hash = tx_hash!(1991); let max_fee = Fee(0); let nonce = nonce!(3_u16); let sender_address = test_contract.get_instance_address(0); diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/get_execution_info.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/get_execution_info.rs index 834ca9c530..c7657beaec 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/get_execution_info.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/get_execution_info.rs @@ -13,8 +13,8 @@ use starknet_api::transaction::fields::{ Tip, ValidResourceBounds, }; -use starknet_api::transaction::{TransactionHash, TransactionVersion, QUERY_VERSION_BASE}; -use starknet_api::{felt, nonce}; +use starknet_api::transaction::{TransactionVersion, QUERY_VERSION_BASE}; +use starknet_api::{felt, nonce, tx_hash}; use starknet_types_core::felt::Felt; use test_case::test_case; @@ -200,7 +200,7 @@ fn test_get_execution_info( version = TransactionVersion(query_version); } - let tx_hash = TransactionHash(felt!(1991_u16)); + let tx_hash = tx_hash!(1991); let max_fee = Fee(42); let nonce = nonce!(3_u16); let sender_address = test_contract_address; diff --git a/crates/papyrus_protobuf/src/converters/transaction_test.rs b/crates/papyrus_protobuf/src/converters/transaction_test.rs index ce5d02eabe..6f03abf290 100644 --- a/crates/papyrus_protobuf/src/converters/transaction_test.rs +++ b/crates/papyrus_protobuf/src/converters/transaction_test.rs @@ -15,10 +15,9 @@ use starknet_api::transaction::{ InvokeTransactionOutput, L1HandlerTransactionOutput, Transaction as StarknetApiTransaction, - TransactionHash, TransactionOutput, }; -use starknet_types_core::felt::Felt; +use starknet_api::tx_hash; use crate::sync::DataOrFin; @@ -167,7 +166,7 @@ fn assert_transaction_to_vec_u8_and_back( transaction: StarknetApiTransaction, transaction_output: TransactionOutput, ) { - let random_transaction_hash = TransactionHash(Felt::from(random::())); + let random_transaction_hash = tx_hash!(random::()); let data = DataOrFin(Some(FullTransaction { transaction, transaction_output, diff --git a/crates/papyrus_rpc/src/v0_8/api/test.rs b/crates/papyrus_rpc/src/v0_8/api/test.rs index 5bfb5c6c8e..fe2b144322 100644 --- a/crates/papyrus_rpc/src/v0_8/api/test.rs +++ b/crates/papyrus_rpc/src/v0_8/api/test.rs @@ -68,7 +68,6 @@ use starknet_api::deprecated_contract_class::{ FunctionAbiEntry, FunctionStateMutability, }; -use starknet_api::hash::StarkHash; use starknet_api::state::{SierraContractClass as StarknetApiContractClass, StateDiff}; use starknet_api::transaction::{ Event as StarknetApiEvent, @@ -81,7 +80,7 @@ use starknet_api::transaction::{ TransactionOffsetInBlock, TransactionOutput as StarknetApiTransactionOutput, }; -use starknet_api::{class_hash, contract_address, felt, storage_key}; +use starknet_api::{class_hash, contract_address, felt, storage_key, tx_hash}; use starknet_client::reader::objects::pending_data::{ DeprecatedPendingBlock, PendingBlockOrDeprecated, @@ -1350,7 +1349,7 @@ async fn get_transaction_status() { call_api_then_assert_and_validate_schema_for_err::<_, TransactionStatus>( &module, method_name, - vec![Box::new(TransactionHash(StarkHash::from(1_u8)))], + vec![Box::new(tx_hash!(1))], &VERSION, SpecFile::StarknetApiOpenrpc, &TRANSACTION_HASH_NOT_FOUND.into(), @@ -1474,7 +1473,7 @@ async fn get_transaction_receipt() { call_api_then_assert_and_validate_schema_for_err::<_, TransactionReceipt>( &module, method_name, - vec![Box::new(TransactionHash(StarkHash::from(1_u8)))], + vec![Box::new(tx_hash!(1))], &VERSION, SpecFile::StarknetApiOpenrpc, &TRANSACTION_HASH_NOT_FOUND.into(), @@ -2202,7 +2201,7 @@ async fn get_storage_at() { fn generate_client_transaction_client_receipt_rpc_transaction_and_rpc_receipt( rng: &mut ChaCha8Rng, ) -> (ClientTransaction, ClientTransactionReceipt, Transaction, PendingTransactionReceipt) { - let pending_transaction_hash = TransactionHash(StarkHash::from(rng.next_u64())); + let pending_transaction_hash = tx_hash!(rng.next_u64()); let mut client_transaction_receipt = ClientTransactionReceipt::get_test_instance(rng); client_transaction_receipt.transaction_hash = pending_transaction_hash; client_transaction_receipt.execution_resources.n_memory_holes = 1; @@ -2279,7 +2278,7 @@ async fn get_transaction_by_hash() { let mut block = get_test_block(1, None, None, None); // Change the transaction hash from 0 to a random value, so that later on we can add a // transaction with 0 hash to the pending block. - block.body.transaction_hashes[0] = TransactionHash(StarkHash::from(random::())); + block.body.transaction_hashes[0] = tx_hash!(random::()); storage_writer .begin_rw_txn() .unwrap() @@ -2333,7 +2332,7 @@ async fn get_transaction_by_hash() { call_api_then_assert_and_validate_schema_for_err::<_, TransactionWithHash>( &module, method_name, - vec![Box::new(TransactionHash(StarkHash::from(1_u8)))], + vec![Box::new(tx_hash!(1))], &VERSION, SpecFile::StarknetApiOpenrpc, &TRANSACTION_HASH_NOT_FOUND.into(), @@ -2344,7 +2343,7 @@ async fn get_transaction_by_hash() { #[tokio::test] async fn get_transaction_by_hash_state_only() { let method_name = "starknet_V0_8_getTransactionByHash"; - let params = [TransactionHash(StarkHash::from(1_u8))]; + let params = [tx_hash!(1)]; let (module, _) = get_test_rpc_server_and_storage_writer_from_params::( None, None, @@ -2736,7 +2735,7 @@ impl BlockMetadata { block.header.block_hash = BlockHash(rng.next_u64().into()); // Randomize the transaction hashes because get_test_block returns constant hashes for transaction_hash in &mut block.body.transaction_hashes { - *transaction_hash = TransactionHash(rng.next_u64().into()); + *transaction_hash = tx_hash!(rng.next_u64()); } for (output, event_metadatas_of_tx) in @@ -2761,9 +2760,8 @@ impl BlockMetadata { rng: &mut ChaCha8Rng, parent_hash: BlockHash, ) -> PendingBlockOrDeprecated { - let transaction_hashes = iter::repeat_with(|| TransactionHash(rng.next_u64().into())) - .take(self.0.len()) - .collect::>(); + let transaction_hashes = + iter::repeat_with(|| tx_hash!(rng.next_u64())).take(self.0.len()).collect::>(); PendingBlockOrDeprecated::Deprecated(DeprecatedPendingBlock { parent_block_hash: parent_hash, transactions: transaction_hashes diff --git a/crates/papyrus_rpc/src/v0_8/execution_test.rs b/crates/papyrus_rpc/src/v0_8/execution_test.rs index 6566ba0ad3..732525a62f 100644 --- a/crates/papyrus_rpc/src/v0_8/execution_test.rs +++ b/crates/papyrus_rpc/src/v0_8/execution_test.rs @@ -71,7 +71,7 @@ use starknet_api::transaction::{ TransactionOffsetInBlock, TransactionVersion, }; -use starknet_api::{calldata, class_hash, contract_address, felt, nonce}; +use starknet_api::{calldata, class_hash, contract_address, felt, nonce, tx_hash}; use starknet_client::reader::objects::pending_data::{ PendingBlock, PendingBlockOrDeprecated, @@ -302,7 +302,7 @@ async fn execution_call() { *BLOCK_TIMESTAMP, *SEQUENCER_ADDRESS, &InvokeTransactionV1::default(), - TransactionHash(StarkHash::ZERO), + tx_hash!(0), Some(Felt::ZERO), ); // Calling the contract directly and not through the account contract. @@ -363,7 +363,7 @@ async fn pending_execution_call() { *BLOCK_TIMESTAMP, *SEQUENCER_ADDRESS, &InvokeTransactionV1::default(), - TransactionHash(StarkHash::ZERO), + tx_hash!(0), Some(Felt::ZERO), ); // Calling the contract directly and not through the account contract. @@ -630,7 +630,7 @@ async fn test_call_simulate( // Because the transaction hash depends on the calldata and the calldata needs to contain // the transaction hash, there's no way to put the correct hash here. Instead, we'll check // that the function `test_get_execution_info` fails on the transaction hash validation. - TransactionHash(StarkHash::ZERO), + tx_hash!(0), None, ); invoke_v1.calldata = calldata; @@ -763,8 +763,8 @@ async fn trace_block_transactions_regular_and_pending() { let mut writer = prepare_storage_for_execution(storage_writer); - let tx_hash1 = TransactionHash(felt!("0x1234")); - let tx_hash2 = TransactionHash(felt!("0x5678")); + let tx_hash1 = tx_hash!(0x1234); + let tx_hash2 = tx_hash!(0x5678); let client_tx1 = ClientTransaction::Invoke(ClientInvokeTransaction { max_fee: Some(*MAX_FEE), @@ -945,8 +945,8 @@ async fn trace_block_transactions_regular_and_pending() { #[tokio::test] async fn trace_block_transactions_and_trace_transaction_execution_context() { - let tx_hash1 = TransactionHash(felt!("0x1234")); - let tx_hash2 = TransactionHash(felt!("0x5678")); + let tx_hash1 = tx_hash!(0x1234); + let tx_hash2 = tx_hash!(0x5678); let mut invoke_tx1 = starknet_api::transaction::InvokeTransactionV1 { max_fee: *MAX_FEE, @@ -1084,8 +1084,8 @@ async fn trace_block_transactions_and_trace_transaction_execution_context() { #[tokio::test] async fn pending_trace_block_transactions_and_trace_transaction_execution_context() { - let tx_hash1 = TransactionHash(felt!("0x1234")); - let tx_hash2 = TransactionHash(felt!("0x5678")); + let tx_hash1 = tx_hash!(0x1234); + let tx_hash2 = tx_hash!(0x5678); let mut client_invoke_tx1 = ClientInvokeTransaction { max_fee: Some(*MAX_FEE), diff --git a/crates/papyrus_rpc/src/v0_8/write_api_result_test.rs b/crates/papyrus_rpc/src/v0_8/write_api_result_test.rs index d4d0bbfeb0..7be59678c2 100644 --- a/crates/papyrus_rpc/src/v0_8/write_api_result_test.rs +++ b/crates/papyrus_rpc/src/v0_8/write_api_result_test.rs @@ -2,7 +2,7 @@ use papyrus_test_utils::{auto_impl_get_test_instance, get_rng, GetTestInstance}; use serde::Serialize; use starknet_api::core::{ClassHash, ContractAddress, PatriciaKey}; use starknet_api::transaction::TransactionHash; -use starknet_api::{class_hash, felt}; +use starknet_api::{class_hash, felt, tx_hash}; use starknet_client::writer::objects::response::{ DeclareResponse, DeployAccountResponse, @@ -54,7 +54,7 @@ fn add_deploy_account_ok_result_fits_rpc() { #[test] fn add_invoke_ok_result_from_response() { - let transaction_hash = TransactionHash(felt!("0x12345")); + let transaction_hash = tx_hash!(0x12345); let ok_result = AddInvokeOkResult::from(InvokeResponse { code: SuccessfulStarknetErrorCode::default(), transaction_hash, @@ -65,7 +65,7 @@ fn add_invoke_ok_result_from_response() { #[test] fn add_declare_ok_result_from_response() { - let transaction_hash = TransactionHash(felt!("0x12345")); + let transaction_hash = tx_hash!(0x12345); let class_hash = class_hash!("0xabcde"); let ok_result = AddDeclareOkResult::from(DeclareResponse { code: SuccessfulStarknetErrorCode::default(), @@ -78,7 +78,7 @@ fn add_declare_ok_result_from_response() { #[test] fn add_deploy_account_ok_result_from_response() { - let transaction_hash = TransactionHash(felt!("0x12345")); + let transaction_hash = tx_hash!(0x12345); let contract_address = ContractAddress(PatriciaKey::try_from(felt!("0xabcde")).unwrap()); let ok_result = AddDeployAccountOkResult::from(DeployAccountResponse { code: SuccessfulStarknetErrorCode::default(), diff --git a/crates/papyrus_test_utils/src/lib.rs b/crates/papyrus_test_utils/src/lib.rs index 2dbf884e80..9f6937a73c 100644 --- a/crates/papyrus_test_utils/src/lib.rs +++ b/crates/papyrus_test_utils/src/lib.rs @@ -49,7 +49,6 @@ use starknet_api::block::{ GasPricePerToken, StarknetVersion, }; -use starknet_api::class_hash; use starknet_api::contract_class::EntryPointType; use starknet_api::core::{ ClassHash, @@ -156,6 +155,7 @@ use starknet_api::transaction::{ TransactionOutput, TransactionVersion, }; +use starknet_api::{class_hash, tx_hash}; use starknet_types_core::felt::Felt; ////////////////////////////////////////////////////////////////////////// @@ -280,7 +280,7 @@ fn get_rand_test_body_with_events( while is_v3_transaction(&transaction) { transaction = Transaction::get_test_instance(rng); } - transaction_hashes.push(TransactionHash(StarkHash::from(u128::try_from(i).unwrap()))); + transaction_hashes.push(tx_hash!(i)); let transaction_output = get_test_transaction_output(&transaction); transactions.push(transaction); transaction_outputs.push(transaction_output); diff --git a/crates/starknet_api/src/block_hash/block_hash_calculator_test.rs b/crates/starknet_api/src/block_hash/block_hash_calculator_test.rs index 7adb1ad094..396273ddae 100644 --- a/crates/starknet_api/src/block_hash/block_hash_calculator_test.rs +++ b/crates/starknet_api/src/block_hash/block_hash_calculator_test.rs @@ -28,10 +28,9 @@ use crate::core::{ TransactionCommitment, }; use crate::data_availability::L1DataAvailabilityMode; -use crate::felt; use crate::hash::PoseidonHash; use crate::transaction::fields::TransactionSignature; -use crate::transaction::TransactionHash; +use crate::{felt, tx_hash}; /// Macro to test if changing any field in the header or commitments /// results a change in the block hash. @@ -95,7 +94,7 @@ fn test_block_hash_regression( let transactions_data = vec![TransactionHashingData { transaction_signature: TransactionSignature(vec![Felt::TWO, Felt::THREE]), transaction_output: get_transaction_output(), - transaction_hash: TransactionHash(Felt::ONE), + transaction_hash: tx_hash!(1), }]; let state_diff = get_state_diff(); diff --git a/crates/starknet_api/src/block_hash/event_commitment_test.rs b/crates/starknet_api/src/block_hash/event_commitment_test.rs index 5c48384268..7fc0752bfb 100644 --- a/crates/starknet_api/src/block_hash/event_commitment_test.rs +++ b/crates/starknet_api/src/block_hash/event_commitment_test.rs @@ -3,8 +3,8 @@ use starknet_types_core::hash::Poseidon; use super::{calculate_event_commitment, calculate_event_hash, EventLeafElement}; use crate::core::EventCommitment; -use crate::transaction::{Event, EventContent, EventData, EventKey, TransactionHash}; -use crate::{contract_address, felt}; +use crate::transaction::{Event, EventContent, EventData, EventKey}; +use crate::{contract_address, felt, tx_hash}; #[test] fn test_event_commitment_regression() { @@ -39,6 +39,6 @@ fn get_event_leaf_element(seed: u8) -> EventLeafElement { ), }, }, - transaction_hash: TransactionHash(felt!("0x1234")), + transaction_hash: tx_hash!(0x1234), } } diff --git a/crates/starknet_api/src/block_hash/receipt_commitment_test.rs b/crates/starknet_api/src/block_hash/receipt_commitment_test.rs index 53dc119f78..3d9c5c5720 100644 --- a/crates/starknet_api/src/block_hash/receipt_commitment_test.rs +++ b/crates/starknet_api/src/block_hash/receipt_commitment_test.rs @@ -10,17 +10,13 @@ use crate::block_hash::receipt_commitment::{ }; use crate::block_hash::test_utils::{generate_message_to_l1, get_transaction_output}; use crate::core::ReceiptCommitment; -use crate::felt; -use crate::transaction::{ - RevertedTransactionExecutionStatus, - TransactionExecutionStatus, - TransactionHash, -}; +use crate::transaction::{RevertedTransactionExecutionStatus, TransactionExecutionStatus}; +use crate::{felt, tx_hash}; #[test] fn test_receipt_hash_regression() { let transaction_receipt = ReceiptElement { - transaction_hash: TransactionHash(Felt::from(1234_u16)), + transaction_hash: tx_hash!(1234), transaction_output: get_transaction_output(), }; diff --git a/crates/starknet_api/src/block_hash/transaction_commitment_test.rs b/crates/starknet_api/src/block_hash/transaction_commitment_test.rs index a8287d28c1..df48e36013 100644 --- a/crates/starknet_api/src/block_hash/transaction_commitment_test.rs +++ b/crates/starknet_api/src/block_hash/transaction_commitment_test.rs @@ -7,9 +7,8 @@ use crate::block_hash::transaction_commitment::{ calculate_transaction_leaf, }; use crate::core::TransactionCommitment; -use crate::felt; use crate::transaction::fields::TransactionSignature; -use crate::transaction::TransactionHash; +use crate::{felt, tx_hash}; #[test] fn test_transaction_leaf_regression() { @@ -22,7 +21,7 @@ fn test_transaction_leaf_regression() { #[test] fn test_transaction_leaf_without_signature_regression() { let transaction_leaf_elements = TransactionLeafElement { - transaction_hash: TransactionHash(Felt::ONE), + transaction_hash: tx_hash!(1), transaction_signature: TransactionSignature(vec![]), }; let expected_leaf = felt!("0x579e8877c7755365d5ec1ec7d3a94a457eff5d1f40482bbe9729c064cdead2"); @@ -45,7 +44,7 @@ fn test_transaction_commitment_regression() { } fn get_transaction_leaf_element() -> TransactionLeafElement { - let transaction_hash = TransactionHash(Felt::ONE); + let transaction_hash = tx_hash!(1); let transaction_signature = TransactionSignature(vec![Felt::TWO, Felt::THREE]); TransactionLeafElement { transaction_hash, transaction_signature } } diff --git a/crates/starknet_api/src/transaction.rs b/crates/starknet_api/src/transaction.rs index 77eb7da72b..e964e225e0 100644 --- a/crates/starknet_api/src/transaction.rs +++ b/crates/starknet_api/src/transaction.rs @@ -807,6 +807,15 @@ impl From> for TransactionHash { } } +/// A utility macro to create a [`TransactionHash`] from an unsigned integer representation. +#[cfg(any(feature = "testing", test))] +#[macro_export] +macro_rules! tx_hash { + ($tx_hash:expr) => { + $crate::transaction::TransactionHash($crate::hash::StarkHash::from($tx_hash)) + }; +} + /// A transaction version. #[derive( Debug, diff --git a/crates/starknet_batcher/src/batcher_test.rs b/crates/starknet_batcher/src/batcher_test.rs index 3f6e2feb81..36f9baebe7 100644 --- a/crates/starknet_batcher/src/batcher_test.rs +++ b/crates/starknet_batcher/src/batcher_test.rs @@ -16,7 +16,7 @@ use starknet_api::executable_transaction::Transaction; use starknet_api::hash::PoseidonHash; use starknet_api::state::ThinStateDiff; use starknet_api::transaction::TransactionHash; -use starknet_api::{contract_address, felt, nonce}; +use starknet_api::{contract_address, felt, nonce, tx_hash}; use starknet_batcher_types::batcher_types::{ DecisionReachedInput, GetProposalContent, @@ -647,7 +647,7 @@ impl ProposalManagerTrait for T { } fn test_tx_hashes(range: std::ops::Range) -> HashSet { - range.map(|i| TransactionHash(felt!(i))).collect() + range.map(|i| tx_hash!(i)).collect() } fn test_contract_nonces(range: std::ops::Range) -> HashMap { diff --git a/crates/starknet_batcher/src/block_builder_test.rs b/crates/starknet_batcher/src/block_builder_test.rs index ea73200169..4176173770 100644 --- a/crates/starknet_batcher/src/block_builder_test.rs +++ b/crates/starknet_batcher/src/block_builder_test.rs @@ -10,9 +10,9 @@ use mockall::predicate::eq; use mockall::Sequence; use rstest::rstest; use starknet_api::executable_transaction::Transaction; -use starknet_api::felt; use starknet_api::transaction::fields::Fee; use starknet_api::transaction::TransactionHash; +use starknet_api::tx_hash; use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender}; use crate::block_builder::{ @@ -247,8 +247,8 @@ fn transaction_failed_test_expectations() -> TestExpectations { }); let execution_infos_mapping = indexmap![ - TransactionHash(felt!(u8::try_from(0).unwrap()))=> execution_info(), - TransactionHash(felt!(u8::try_from(2).unwrap()))=> execution_info(), + tx_hash!(0)=> execution_info(), + tx_hash!(2)=> execution_info(), ]; let expected_block_artifacts = block_execution_artifacts(execution_infos_mapping); let expected_block_artifacts_copy = expected_block_artifacts.clone(); @@ -275,7 +275,7 @@ fn transaction_failed_test_expectations() -> TestExpectations { fn block_builder_expected_output(execution_info_len: usize) -> BlockExecutionArtifacts { let execution_info_len_u8 = u8::try_from(execution_info_len).unwrap(); let execution_infos_mapping = - (0..execution_info_len_u8).map(|i| (TransactionHash(felt!(i)), execution_info())).collect(); + (0..execution_info_len_u8).map(|i| (tx_hash!(i), execution_info())).collect(); block_execution_artifacts(execution_infos_mapping) } diff --git a/crates/starknet_batcher/src/test_utils.rs b/crates/starknet_batcher/src/test_utils.rs index e6b8183638..b7243cc6dd 100644 --- a/crates/starknet_batcher/src/test_utils.rs +++ b/crates/starknet_batcher/src/test_utils.rs @@ -5,9 +5,8 @@ use blockifier::bouncer::BouncerWeights; use blockifier::state::cached_state::CommitmentStateDiff; use indexmap::IndexMap; use starknet_api::executable_transaction::{AccountTransaction, Transaction}; -use starknet_api::felt; use starknet_api::test_utils::invoke::{executable_invoke_tx, InvokeTxArgs}; -use starknet_api::transaction::TransactionHash; +use starknet_api::tx_hash; use crate::block_builder::BlockExecutionArtifacts; @@ -15,7 +14,7 @@ pub fn test_txs(tx_hash_range: Range) -> Vec { tx_hash_range .map(|i| { Transaction::Account(AccountTransaction::Invoke(executable_invoke_tx(InvokeTxArgs { - tx_hash: TransactionHash(felt!(u128::try_from(i).unwrap())), + tx_hash: tx_hash!(i), ..Default::default() }))) }) diff --git a/crates/starknet_batcher/src/transaction_provider_test.rs b/crates/starknet_batcher/src/transaction_provider_test.rs index 0e806a7248..5cfc69564b 100644 --- a/crates/starknet_batcher/src/transaction_provider_test.rs +++ b/crates/starknet_batcher/src/transaction_provider_test.rs @@ -5,9 +5,8 @@ use mockall::predicate::eq; use rstest::{fixture, rstest}; use starknet_api::executable_transaction::{AccountTransaction, L1HandlerTransaction, Transaction}; use starknet_api::test_utils::invoke::{executable_invoke_tx, InvokeTxArgs}; -use starknet_api::transaction::TransactionHash; +use starknet_api::tx_hash; use starknet_mempool_types::communication::MockMempoolClient; -use starknet_types_core::felt::Felt; use crate::transaction_provider::{ MockL1ProviderClient, @@ -95,7 +94,7 @@ fn tx_channel() -> (tokio::sync::mpsc::Sender, tokio::sync::mpsc::R } fn test_l1handler_tx() -> L1HandlerTransaction { - L1HandlerTransaction { tx_hash: TransactionHash(Felt::ONE), ..Default::default() } + L1HandlerTransaction { tx_hash: tx_hash!(1), ..Default::default() } } #[rstest] diff --git a/crates/starknet_client/src/reader/objects/block_test.rs b/crates/starknet_client/src/reader/objects/block_test.rs index 58325afc42..8e0657252a 100644 --- a/crates/starknet_client/src/reader/objects/block_test.rs +++ b/crates/starknet_client/src/reader/objects/block_test.rs @@ -4,8 +4,8 @@ use pretty_assertions::assert_eq; use starknet_api::block::BlockHash; use starknet_api::core::{CompiledClassHash, Nonce}; use starknet_api::hash::StarkHash; -use starknet_api::transaction::{TransactionHash, TransactionOffsetInBlock}; -use starknet_api::{class_hash, contract_address, felt, storage_key}; +use starknet_api::transaction::TransactionOffsetInBlock; +use starknet_api::{class_hash, contract_address, felt, storage_key, tx_hash}; use super::{Block, GlobalRoot, TransactionReceiptsError}; use crate::reader::objects::block::BlockPostV0_13_1; @@ -135,7 +135,7 @@ async fn to_starknet_api_block_and_version() { ); let mut err_block: BlockPostV0_13_1 = serde_json::from_str(&raw_block).unwrap(); - err_block.transaction_receipts[0].transaction_hash = TransactionHash(felt!("0x4")); + err_block.transaction_receipts[0].transaction_hash = tx_hash!(0x4); let err = err_block.to_starknet_api_block_and_version().unwrap_err(); assert_matches!( err, diff --git a/crates/starknet_l1_provider/src/l1_provider_tests.rs b/crates/starknet_l1_provider/src/l1_provider_tests.rs index 09bf6ce569..03c5f068be 100644 --- a/crates/starknet_l1_provider/src/l1_provider_tests.rs +++ b/crates/starknet_l1_provider/src/l1_provider_tests.rs @@ -1,9 +1,7 @@ use assert_matches::assert_matches; use pretty_assertions::assert_eq; -use starknet_api::hash::StarkHash; -use starknet_api::l1_handler_tx_args; use starknet_api::test_utils::l1_handler::executable_l1_handler_tx; -use starknet_api::transaction::TransactionHash; +use starknet_api::{l1_handler_tx_args, tx_hash}; use crate::errors::L1ProviderError; use crate::test_utils::L1ProviderContentBuilder; @@ -14,18 +12,12 @@ macro_rules! tx { (tx_hash: $tx_hash:expr) => {{ executable_l1_handler_tx( l1_handler_tx_args!( - tx_hash: TransactionHash(StarkHash::from($tx_hash)) , ..Default::default() + tx_hash: tx_hash!($tx_hash) , ..Default::default() ) ) }}; } -macro_rules! tx_hash { - ($tx_hash:expr) => { - TransactionHash(StarkHash::from($tx_hash)) - }; -} - #[test] fn get_txs_happy_flow() { // Setup. diff --git a/crates/starknet_mempool/src/test_utils.rs b/crates/starknet_mempool/src/test_utils.rs index 472b4ae91d..58bcbfc6f4 100644 --- a/crates/starknet_mempool/src/test_utils.rs +++ b/crates/starknet_mempool/src/test_utils.rs @@ -2,8 +2,7 @@ use std::collections::{HashMap, HashSet}; use pretty_assertions::assert_eq; use starknet_api::executable_transaction::AccountTransaction; -use starknet_api::transaction::TransactionHash; -use starknet_api::{contract_address, felt, nonce}; +use starknet_api::{contract_address, nonce, tx_hash}; use starknet_mempool_types::errors::MempoolError; use starknet_mempool_types::mempool_types::{AddTransactionArgs, CommitBlockArgs}; @@ -22,8 +21,7 @@ macro_rules! tx { ) => {{ use starknet_api::block::GasPrice; use starknet_api::executable_transaction::AccountTransaction; - use starknet_api::hash::StarkHash; - use starknet_api::invoke_tx_args; + use starknet_api::{invoke_tx_args, tx_hash}; use starknet_api::test_utils::invoke::executable_invoke_tx; use starknet_api::transaction::fields::{ AllResourceBounds, @@ -31,7 +29,6 @@ macro_rules! tx { Tip, ValidResourceBounds, }; - use starknet_api::transaction::TransactionHash; let resource_bounds = ValidResourceBounds::AllResources(AllResourceBounds { l2_gas: ResourceBounds { @@ -42,7 +39,7 @@ macro_rules! tx { }); AccountTransaction::Invoke(executable_invoke_tx(invoke_tx_args!{ - tx_hash: TransactionHash(StarkHash::from($tx_hash)), + tx_hash: tx_hash!($tx_hash), sender_address: contract_address!($address), nonce: nonce!($tx_nonce), tip: Tip($tip), @@ -242,8 +239,7 @@ pub fn commit_block( let nonces = HashMap::from_iter( nonces.into_iter().map(|(address, nonce)| (contract_address!(address), nonce!(nonce))), ); - let tx_hashes = - HashSet::from_iter(tx_hashes.into_iter().map(|tx_hash| TransactionHash(felt!(tx_hash)))); + let tx_hashes = HashSet::from_iter(tx_hashes.into_iter().map(|tx_hash| tx_hash!(tx_hash))); let args = CommitBlockArgs { address_to_nonce: nonces, tx_hashes }; assert_eq!(mempool.commit_block(args), Ok(())); From e81a262900d617e879f59b34a38b4c32b6405bd2 Mon Sep 17 00:00:00 2001 From: Asmaa Magdoub Date: Tue, 19 Nov 2024 13:59:11 +0200 Subject: [PATCH 20/25] feat(consensus): handle proposals from different rounds by context --- .../papyrus_consensus/src/manager_test.rs | 18 +- .../src/single_height_consensus.rs | 34 +++- .../src/single_height_consensus_test.rs | 9 +- .../papyrus_consensus/src/state_machine.rs | 4 + .../papyrus_consensus/src/test_utils.rs | 3 + .../sequencing/papyrus_consensus/src/types.rs | 6 + .../papyrus_consensus_orchestrator/Cargo.toml | 2 +- .../src/papyrus_consensus_context.rs | 5 + .../src/papyrus_consensus_context_test.rs | 4 +- .../src/sequencer_consensus_context.rs | 178 ++++++++++++----- .../src/sequencer_consensus_context_test.rs | 179 ++++++++++++++++-- 11 files changed, 358 insertions(+), 84 deletions(-) diff --git a/crates/sequencing/papyrus_consensus/src/manager_test.rs b/crates/sequencing/papyrus_consensus/src/manager_test.rs index 3f94d78fb4..99f8a01087 100644 --- a/crates/sequencing/papyrus_consensus/src/manager_test.rs +++ b/crates/sequencing/papyrus_consensus/src/manager_test.rs @@ -48,6 +48,7 @@ mock! { async fn validate_proposal( &mut self, height: BlockNumber, + round: Round, timeout: Duration, content: mpsc::Receiver ) -> oneshot::Receiver; @@ -69,6 +70,9 @@ mock! { block: ProposalContentId, precommits: Vec, ) -> Result<(), ConsensusError>; + + async fn set_height_and_round(&mut self, height: BlockNumber, round: Round); + } } @@ -95,7 +99,7 @@ async fn manager_multiple_heights_unordered() { // Run the manager for height 1. context .expect_validate_proposal() - .return_once(move |_, _, _| { + .return_once(move |_, _, _, _| { let (block_sender, block_receiver) = oneshot::channel(); block_sender.send(BlockHash(Felt::ONE)).unwrap(); block_receiver @@ -103,6 +107,7 @@ async fn manager_multiple_heights_unordered() { .times(1); context.expect_validators().returning(move |_| vec![*PROPOSER_ID, *VALIDATOR_ID]); context.expect_proposer().returning(move |_, _| *PROPOSER_ID); + context.expect_set_height_and_round().returning(move |_, _| ()); context.expect_broadcast().returning(move |_| Ok(())); let mut manager = MultiHeightManager::new(*VALIDATOR_ID, TIMEOUTS.clone()); @@ -114,7 +119,7 @@ async fn manager_multiple_heights_unordered() { // Run the manager for height 2. context .expect_validate_proposal() - .return_once(move |_, _, _| { + .return_once(move |_, _, _, _| { let (block_sender, block_receiver) = oneshot::channel(); block_sender.send(BlockHash(Felt::TWO)).unwrap(); block_receiver @@ -131,13 +136,14 @@ async fn run_consensus_sync() { let mut context = MockTestContext::new(); let (decision_tx, decision_rx) = oneshot::channel(); - context.expect_validate_proposal().return_once(move |_, _, _| { + context.expect_validate_proposal().return_once(move |_, _, _, _| { let (block_sender, block_receiver) = oneshot::channel(); block_sender.send(BlockHash(Felt::TWO)).unwrap(); block_receiver }); context.expect_validators().returning(move |_| vec![*PROPOSER_ID, *VALIDATOR_ID]); context.expect_proposer().returning(move |_, _| *PROPOSER_ID); + context.expect_set_height_and_round().returning(move |_, _| ()); context.expect_broadcast().returning(move |_| Ok(())); context.expect_decision_reached().return_once(move |block, votes| { assert_eq!(block, BlockHash(Felt::TWO)); @@ -190,13 +196,14 @@ async fn run_consensus_sync_cancellation_safety() { let (proposal_handled_tx, proposal_handled_rx) = oneshot::channel(); let (decision_tx, decision_rx) = oneshot::channel(); - context.expect_validate_proposal().return_once(move |_, _, _| { + context.expect_validate_proposal().return_once(move |_, _, _, _| { let (block_sender, block_receiver) = oneshot::channel(); block_sender.send(BlockHash(Felt::ONE)).unwrap(); block_receiver }); context.expect_validators().returning(move |_| vec![*PROPOSER_ID, *VALIDATOR_ID]); context.expect_proposer().returning(move |_, _| *PROPOSER_ID); + context.expect_set_height_and_round().returning(move |_, _| ()); context.expect_broadcast().with(eq(prevote(Some(Felt::ONE), 1, 0, *VALIDATOR_ID))).return_once( move |_| { proposal_handled_tx.send(()).unwrap(); @@ -260,7 +267,8 @@ async fn test_timeouts() { send(&mut sender, precommit(None, 1, 0, *VALIDATOR_ID_3)).await; let mut context = MockTestContext::new(); - context.expect_validate_proposal().returning(move |_, _, _| { + context.expect_set_height_and_round().returning(move |_, _| ()); + context.expect_validate_proposal().returning(move |_, _, _, _| { let (block_sender, block_receiver) = oneshot::channel(); block_sender.send(BlockHash(Felt::ONE)).unwrap(); block_receiver diff --git a/crates/sequencing/papyrus_consensus/src/single_height_consensus.rs b/crates/sequencing/papyrus_consensus/src/single_height_consensus.rs index f2ee23c7d3..856d08ca9f 100644 --- a/crates/sequencing/papyrus_consensus/src/single_height_consensus.rs +++ b/crates/sequencing/papyrus_consensus/src/single_height_consensus.rs @@ -114,7 +114,6 @@ impl ShcTask { ShcEvent::Precommit(event) } ShcTask::BuildProposal(round, receiver) => { - println!("Building proposal for round {}", round); let proposal_id = receiver.await.expect("Block building failed."); ShcEvent::BuildProposal(StateMachineEvent::GetProposal(Some(proposal_id), round)) } @@ -123,14 +122,18 @@ impl ShcTask { id_built_from_content_receiver, fin_from_proposer_receiver, ) => { + // Handle the result of the block validation: + // - If successful, set it as Some. + // - If there was an error (e.g., invalid proposal, no proposal received from the + // peer, or the process was interrupted), set it to None. + // TODO(Asmaa): Consider if we want to differentiate between an interrupt and other + // failures. let proposal_id = match id_built_from_content_receiver.await { Ok(proposal_id) => Some(proposal_id), - // Proposal never received from peer. Err(_) => None, }; let fin = match fin_from_proposer_receiver.await { Ok(fin) => Some(fin), - // ProposalFin never received from peer. Err(_) => None, }; ShcEvent::ValidateProposal( @@ -190,9 +193,12 @@ impl SingleHeightConsensus { context: &mut ContextT, ) -> Result { info!("Starting consensus with validators {:?}", self.validators); + context.set_height_and_round(self.height, self.state_machine.round()).await; let leader_fn = |round: Round| -> ValidatorId { context.proposer(self.height, round) }; let events = self.state_machine.start(&leader_fn); - self.handle_state_machine_events(context, events).await + let ret = self.handle_state_machine_events(context, events).await; + context.set_height_and_round(self.height, self.state_machine.round()).await; + ret } /// Process the proposal init and initiate block validation. See [`ShcTask::ValidateProposal`] @@ -231,8 +237,14 @@ impl SingleHeightConsensus { // twice in parallel. This could be caused by a network repeat or a malicious spam attack. proposal_entry.insert(None); let block_receiver = context - .validate_proposal(self.height, self.timeouts.proposal_timeout, p2p_messages_receiver) + .validate_proposal( + self.height, + init.round, + self.timeouts.proposal_timeout, + p2p_messages_receiver, + ) .await; + context.set_height_and_round(self.height, self.state_machine.round()).await; Ok(ShcReturn::Tasks(vec![ShcTask::ValidateProposal(init, block_receiver, fin_receiver)])) } @@ -258,7 +270,11 @@ impl SingleHeightConsensus { ConsensusMessage::Proposal(_) => { unimplemented!("Proposals should use `handle_proposal` due to fake streaming") } - ConsensusMessage::Vote(vote) => self.handle_vote(context, vote).await, + ConsensusMessage::Vote(vote) => { + let ret = self.handle_vote(context, vote).await; + context.set_height_and_round(self.height, self.state_machine.round()).await; + ret + } } } @@ -268,7 +284,7 @@ impl SingleHeightConsensus { event: ShcEvent, ) -> Result { debug!("Received ShcEvent: {:?}", event); - match event { + let ret = match event { ShcEvent::TimeoutPropose(event) | ShcEvent::TimeoutPrevote(event) | ShcEvent::TimeoutPrecommit(event) => { @@ -342,7 +358,9 @@ impl SingleHeightConsensus { self.handle_state_machine_events(context, sm_events).await } _ => unimplemented!("Unexpected event: {:?}", event), - } + }; + context.set_height_and_round(self.height, self.state_machine.round()).await; + ret } #[instrument(skip_all)] diff --git a/crates/sequencing/papyrus_consensus/src/single_height_consensus_test.rs b/crates/sequencing/papyrus_consensus/src/single_height_consensus_test.rs index deb0d937f8..3f0bd44856 100644 --- a/crates/sequencing/papyrus_consensus/src/single_height_consensus_test.rs +++ b/crates/sequencing/papyrus_consensus/src/single_height_consensus_test.rs @@ -94,6 +94,7 @@ async fn proposer() { block_sender.send(BLOCK.id).unwrap(); block_receiver }); + context.expect_set_height_and_round().returning(move |_, _| ()); context .expect_broadcast() .times(1) @@ -173,11 +174,12 @@ async fn validator(repeat_proposal: bool) { ); context.expect_proposer().returning(move |_, _| *PROPOSER_ID); - context.expect_validate_proposal().times(1).returning(move |_, _, _| { + context.expect_validate_proposal().times(1).returning(move |_, _, _, _| { let (block_sender, block_receiver) = oneshot::channel(); block_sender.send(BLOCK.id).unwrap(); block_receiver }); + context.expect_set_height_and_round().returning(move |_, _| ()); context .expect_broadcast() .times(1) @@ -251,11 +253,12 @@ async fn vote_twice(same_vote: bool) { ); context.expect_proposer().times(1).returning(move |_, _| *PROPOSER_ID); - context.expect_validate_proposal().times(1).returning(move |_, _, _| { + context.expect_validate_proposal().times(1).returning(move |_, _, _, _| { let (block_sender, block_receiver) = oneshot::channel(); block_sender.send(BLOCK.id).unwrap(); block_receiver }); + context.expect_set_height_and_round().returning(move |_, _| ()); context .expect_broadcast() .times(1) // Shows the repeat vote is ignored. @@ -324,6 +327,7 @@ async fn rebroadcast_votes() { block_sender.send(BLOCK.id).unwrap(); block_receiver }); + context.expect_set_height_and_round().returning(move |_, _| ()); context .expect_broadcast() .times(1) @@ -385,6 +389,7 @@ async fn repropose() { block_sender.send(BLOCK.id).unwrap(); block_receiver }); + context.expect_set_height_and_round().returning(move |_, _| ()); context .expect_broadcast() .times(1) diff --git a/crates/sequencing/papyrus_consensus/src/state_machine.rs b/crates/sequencing/papyrus_consensus/src/state_machine.rs index c4b3cd70f8..152d0d9daf 100644 --- a/crates/sequencing/papyrus_consensus/src/state_machine.rs +++ b/crates/sequencing/papyrus_consensus/src/state_machine.rs @@ -95,6 +95,10 @@ impl StateMachine { } } + pub fn round(&self) -> Round { + self.round + } + pub fn quorum_size(&self) -> u32 { self.quorum } diff --git a/crates/sequencing/papyrus_consensus/src/test_utils.rs b/crates/sequencing/papyrus_consensus/src/test_utils.rs index 303e30a049..6c91eae045 100644 --- a/crates/sequencing/papyrus_consensus/src/test_utils.rs +++ b/crates/sequencing/papyrus_consensus/src/test_utils.rs @@ -33,6 +33,7 @@ mock! { async fn validate_proposal( &mut self, height: BlockNumber, + round: Round, timeout: Duration, content: mpsc::Receiver ) -> oneshot::Receiver; @@ -54,6 +55,8 @@ mock! { block: ProposalContentId, precommits: Vec, ) -> Result<(), ConsensusError>; + + async fn set_height_and_round(&mut self, height: BlockNumber, round: Round); } } diff --git a/crates/sequencing/papyrus_consensus/src/types.rs b/crates/sequencing/papyrus_consensus/src/types.rs index a4fcd53f31..2082b23c2c 100644 --- a/crates/sequencing/papyrus_consensus/src/types.rs +++ b/crates/sequencing/papyrus_consensus/src/types.rs @@ -59,6 +59,7 @@ pub trait ConsensusContext { /// Params: /// - `height`: The height of the block to be built. Specifically this indicates the initial /// state of the block. + /// - `round`: The round of the block to be built. /// - `timeout`: The maximum time to wait for the block to be built. /// - `content`: A receiver for the stream of the block's content. /// @@ -68,6 +69,7 @@ pub trait ConsensusContext { async fn validate_proposal( &mut self, height: BlockNumber, + round: Round, timeout: Duration, content: mpsc::Receiver, ) -> oneshot::Receiver; @@ -101,6 +103,10 @@ pub trait ConsensusContext { block: ProposalContentId, precommits: Vec, ) -> Result<(), ConsensusError>; + + /// Update the context with the current height and round. + /// Must be called at the beginning of each height. + async fn set_height_and_round(&mut self, height: BlockNumber, round: Round); } #[derive(PartialEq)] diff --git a/crates/sequencing/papyrus_consensus_orchestrator/Cargo.toml b/crates/sequencing/papyrus_consensus_orchestrator/Cargo.toml index 7b91ad6ab3..6fb31cdd99 100644 --- a/crates/sequencing/papyrus_consensus_orchestrator/Cargo.toml +++ b/crates/sequencing/papyrus_consensus_orchestrator/Cargo.toml @@ -16,7 +16,7 @@ papyrus_protobuf.workspace = true papyrus_storage.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true -starknet_batcher_types.workspace = true +starknet_batcher_types = { workspace = true, features = ["testing"] } tokio = { workspace = true, features = ["full"] } tracing.workspace = true diff --git a/crates/sequencing/papyrus_consensus_orchestrator/src/papyrus_consensus_context.rs b/crates/sequencing/papyrus_consensus_orchestrator/src/papyrus_consensus_context.rs index 5779d8a156..2fc426d8ec 100644 --- a/crates/sequencing/papyrus_consensus_orchestrator/src/papyrus_consensus_context.rs +++ b/crates/sequencing/papyrus_consensus_orchestrator/src/papyrus_consensus_context.rs @@ -140,6 +140,7 @@ impl ConsensusContext for PapyrusConsensusContext { async fn validate_proposal( &mut self, height: BlockNumber, + _round: Round, _timeout: Duration, mut content: mpsc::Receiver, ) -> oneshot::Receiver { @@ -259,6 +260,10 @@ impl ConsensusContext for PapyrusConsensusContext { proposals.retain(|&h, _| h > BlockNumber(height)); Ok(()) } + + async fn set_height_and_round(&mut self, _height: BlockNumber, _round: Round) { + // No-op + } } const SLEEP_BETWEEN_CHECK_FOR_BLOCK: Duration = Duration::from_secs(10); diff --git a/crates/sequencing/papyrus_consensus_orchestrator/src/papyrus_consensus_context_test.rs b/crates/sequencing/papyrus_consensus_orchestrator/src/papyrus_consensus_context_test.rs index 9c7e5b9f96..fdcd4c3ad0 100644 --- a/crates/sequencing/papyrus_consensus_orchestrator/src/papyrus_consensus_context_test.rs +++ b/crates/sequencing/papyrus_consensus_orchestrator/src/papyrus_consensus_context_test.rs @@ -51,7 +51,7 @@ async fn validate_proposal_success() { validate_sender.close_channel(); let fin = papyrus_context - .validate_proposal(block_number, Duration::MAX, validate_receiver) + .validate_proposal(block_number, 0, Duration::MAX, validate_receiver) .await .await .unwrap(); @@ -72,7 +72,7 @@ async fn validate_proposal_fail() { validate_sender.close_channel(); let fin = papyrus_context - .validate_proposal(block_number, Duration::MAX, validate_receiver) + .validate_proposal(block_number, 0, Duration::MAX, validate_receiver) .await .await; assert_eq!(fin, Err(oneshot::Canceled)); diff --git a/crates/sequencing/papyrus_consensus_orchestrator/src/sequencer_consensus_context.rs b/crates/sequencing/papyrus_consensus_orchestrator/src/sequencer_consensus_context.rs index 8ee354a4f9..13cbc8302d 100644 --- a/crates/sequencing/papyrus_consensus_orchestrator/src/sequencer_consensus_context.rs +++ b/crates/sequencing/papyrus_consensus_orchestrator/src/sequencer_consensus_context.rs @@ -43,6 +43,8 @@ use starknet_batcher_types::batcher_types::{ ValidateBlockInput, }; use starknet_batcher_types::communication::BatcherClient; +use tokio::sync::Notify; +use tokio::task::JoinHandle; use tracing::{debug, debug_span, error, info, trace, warn, Instrument}; // {height: {proposal_id: (content, [proposal_ids])}} @@ -50,6 +52,7 @@ use tracing::{debug, debug_span, error, info, trace, warn, Instrument}; // store one of them. type HeightToIdToContent = BTreeMap, ProposalId)>>; +type ValidationParams = (BlockNumber, Duration, mpsc::Receiver>); pub struct SequencerConsensusContext { batcher: Arc, @@ -63,7 +66,15 @@ pub struct SequencerConsensusContext { // restarting. proposal_id: u64, current_height: Option, + current_round: Round, network_broadcast_client: BroadcastTopicClient, + // The active proposal refers to the proposal being validated at the current height/round. + // Building proposals are not tracked as active, as consensus can't move on to the next + // height/round until building is done. Context only works on proposals for the + // current round. + active_proposal: Option<(Arc, JoinHandle<()>)>, + // Stores proposals for future rounds until the round is reached. + queued_proposals: BTreeMap)>, } impl SequencerConsensusContext { @@ -79,6 +90,9 @@ impl SequencerConsensusContext { valid_proposals: Arc::new(Mutex::new(HeightToIdToContent::new())), proposal_id: 0, current_height: None, + current_round: 0, + active_proposal: None, + queued_proposals: BTreeMap::new(), } } } @@ -93,6 +107,8 @@ impl ConsensusContext for SequencerConsensusContext { proposal_init: ProposalInit, timeout: Duration, ) -> oneshot::Receiver { + // Handles interrupting an active proposal from a previous height/round + self.set_height_and_round(proposal_init.height, proposal_init.round).await; debug!( "Building proposal for height: {} with timeout: {:?}", proposal_init.height, timeout @@ -116,7 +132,6 @@ impl ConsensusContext for SequencerConsensusContext { hash: BlockHash::default(), }), }; - self.maybe_start_height(proposal_init.height).await; // TODO: Should we be returning an error? // I think this implies defining an error type in this crate and moving the trait definition // here also. @@ -152,47 +167,23 @@ impl ConsensusContext for SequencerConsensusContext { async fn validate_proposal( &mut self, height: BlockNumber, + round: Round, timeout: Duration, content: mpsc::Receiver, ) -> oneshot::Receiver { - debug!("Validating proposal for height: {height} with timeout: {timeout:?}"); + assert_eq!(Some(height), self.current_height); let (fin_sender, fin_receiver) = oneshot::channel(); - let batcher = Arc::clone(&self.batcher); - let valid_proposals = Arc::clone(&self.valid_proposals); - let proposal_id = ProposalId(self.proposal_id); - self.proposal_id += 1; - - let chrono_timeout = - chrono::Duration::from_std(timeout).expect("Can't convert timeout to chrono::Duration"); - let input = ValidateBlockInput { - proposal_id, - deadline: chrono::Utc::now() + chrono_timeout, - // TODO(Matan 3/11/2024): Add the real value of the retrospective block hash. - retrospective_block_hash: Some(BlockHashAndNumber { - number: BlockNumber::default(), - hash: BlockHash::default(), - }), - }; - self.maybe_start_height(height).await; - batcher.validate_block(input).await.expect("Failed to initiate proposal validation"); - tokio::spawn( - async move { - let validate_fut = stream_validate_proposal( - height, - proposal_id, - batcher, - valid_proposals, - content, - fin_sender, - ); - if let Err(e) = tokio::time::timeout(timeout, validate_fut).await { - error!("Validation timed out. {e:?}"); - } + match round.cmp(&self.current_round) { + std::cmp::Ordering::Less => fin_receiver, + std::cmp::Ordering::Greater => { + self.queued_proposals.insert(round, ((height, timeout, content), fin_sender)); + fin_receiver } - .instrument(debug_span!("consensus_validate_proposal")), - ); - - fin_receiver + std::cmp::Ordering::Equal => { + self.validate_current_round_proposal(height, timeout, content, fin_sender).await; + fin_receiver + } + } } async fn repropose(&mut self, id: ProposalContentId, init: ProposalInit) { @@ -245,22 +236,111 @@ impl ConsensusContext for SequencerConsensusContext { Ok(()) } + + async fn set_height_and_round(&mut self, height: BlockNumber, round: Round) { + if self.current_height.is_none_or(|h| height > h) { + self.current_height = Some(height); + assert_eq!(round, 0); + self.current_round = round; + self.interrupt_active_proposal(); + self.queued_proposals.clear(); + self.active_proposal = None; + // The Batcher must be told when we begin to work on a new height. The implicit model is + // that consensus works on a given height until it is done (either a decision is reached + // or sync causes us to move on) and then moves on to a different height, never to + // return to the old height. + self.batcher + .start_height(StartHeightInput { height }) + .await + .expect("Batcher should be ready to start the next height"); + return; + } + assert_eq!(Some(height), self.current_height); + if round == self.current_round { + return; + } + assert!(round > self.current_round); + self.interrupt_active_proposal(); + self.current_round = round; + let mut to_process = None; + while let Some(entry) = self.queued_proposals.first_entry() { + match self.current_round.cmp(entry.key()) { + std::cmp::Ordering::Less => { + entry.remove(); + } + std::cmp::Ordering::Equal => { + to_process = Some(entry.remove()); + break; + } + std::cmp::Ordering::Greater => return, + } + } + // Validate the proposal for the current round if exists. + let Some(((height, timeout, content), fin_sender)) = to_process else { + return; + }; + self.validate_current_round_proposal(height, timeout, content, fin_sender).await; + } } impl SequencerConsensusContext { - // The Batcher must be told when we begin to work on a new height. The implicit model is that - // consensus works on a given height until it is done (either a decision is reached or sync - // causes us to move on) and then moves on to a different height, never to return to the old - // height. - async fn maybe_start_height(&mut self, height: BlockNumber) { - if self.current_height == Some(height) { - return; + async fn validate_current_round_proposal( + &mut self, + height: BlockNumber, + timeout: Duration, + content: mpsc::Receiver>, + fin_sender: oneshot::Sender, + ) { + debug!("Validating proposal for height: {height} with timeout: {timeout:?}"); + let batcher = Arc::clone(&self.batcher); + let valid_proposals = Arc::clone(&self.valid_proposals); + let proposal_id = ProposalId(self.proposal_id); + self.proposal_id += 1; + + let chrono_timeout = + chrono::Duration::from_std(timeout).expect("Can't convert timeout to chrono::Duration"); + let input = ValidateBlockInput { + proposal_id, + deadline: chrono::Utc::now() + chrono_timeout, + // TODO(Matan 3/11/2024): Add the real value of the retrospective block hash. + retrospective_block_hash: Some(BlockHashAndNumber { + number: BlockNumber::default(), + hash: BlockHash::default(), + }), + }; + batcher.validate_block(input).await.expect("Failed to initiate proposal validation"); + + let notify = Arc::new(Notify::new()); + let notify_clone = Arc::clone(¬ify); + + let handle = tokio::spawn( + async move { + let validate_fut = stream_validate_proposal( + height, + proposal_id, + batcher, + valid_proposals, + content, + fin_sender, + ); + tokio::select! { + _ = notify_clone.notified() => {} + result = tokio::time::timeout(timeout, validate_fut) =>{ + if let Err(e) = result { + error!("Validation timed out. {e:?}"); + } + } + } + } + .instrument(debug_span!("consensus_validate_proposal")), + ); + self.active_proposal = Some((notify, handle)); + } + + fn interrupt_active_proposal(&self) { + if let Some((notify, _)) = &self.active_proposal { + notify.notify_one(); } - self.batcher - .start_height(StartHeightInput { height }) - .await - .expect("Batcher should be ready to start the next height"); - self.current_height = Some(height); } } diff --git a/crates/sequencing/papyrus_consensus_orchestrator/src/sequencer_consensus_context_test.rs b/crates/sequencing/papyrus_consensus_orchestrator/src/sequencer_consensus_context_test.rs index c5b1c127c5..58c8978022 100644 --- a/crates/sequencing/papyrus_consensus_orchestrator/src/sequencer_consensus_context_test.rs +++ b/crates/sequencing/papyrus_consensus_orchestrator/src/sequencer_consensus_context_test.rs @@ -3,7 +3,7 @@ use std::time::Duration; use std::vec; use futures::channel::mpsc; -use futures::SinkExt; +use futures::{FutureExt, SinkExt}; use lazy_static::lazy_static; use papyrus_consensus::types::ConsensusContext; use papyrus_network::network_manager::test_utils::{ @@ -28,7 +28,6 @@ use starknet_batcher_types::batcher_types::{ SendProposalContent, SendProposalContentInput, SendProposalContentResponse, - StartHeightInput, ValidateBlockInput, }; use starknet_batcher_types::communication::MockBatcherClient; @@ -61,10 +60,10 @@ async fn build_proposal() { proposal_id_clone.set(input.proposal_id).unwrap(); Ok(()) }); - batcher.expect_start_height().return_once(|input: StartHeightInput| { - assert_eq!(input.height, BlockNumber(0)); - Ok(()) - }); + batcher + .expect_start_height() + .withf(|input| input.height == BlockNumber(0)) + .return_once(|_| Ok(())); let proposal_id_clone = Arc::clone(&proposal_id); batcher.expect_get_proposal_content().times(1).returning(move |input| { assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); @@ -105,10 +104,10 @@ async fn validate_proposal_success() { proposal_id_clone.set(input.proposal_id).unwrap(); Ok(()) }); - batcher.expect_start_height().return_once(|input: StartHeightInput| { - assert_eq!(input.height, BlockNumber(0)); - Ok(()) - }); + batcher + .expect_start_height() + .withf(|input| input.height == BlockNumber(0)) + .return_once(|_| Ok(())); let proposal_id_clone = Arc::clone(&proposal_id); batcher.expect_send_proposal_content().times(1).returning( move |input: SendProposalContentInput| { @@ -116,7 +115,7 @@ async fn validate_proposal_success() { let SendProposalContent::Txs(txs) = input.content else { panic!("Expected SendProposalContent::Txs, got {:?}", input.content); }; - assert_eq!(txs, TX_BATCH.clone()); + assert_eq!(txs, *TX_BATCH); Ok(SendProposalContentResponse { response: ProposalStatus::Processing }) }, ); @@ -138,9 +137,12 @@ async fn validate_proposal_success() { subscriber_channels; let mut context = SequencerConsensusContext::new(Arc::new(batcher), broadcast_topic_client, NUM_VALIDATORS); + // Initialize the context for a specific height, starting with round 0. + context.set_height_and_round(BlockNumber(0), 0).await; let (mut content_sender, content_receiver) = mpsc::channel(CHANNEL_SIZE); content_sender.send(TX_BATCH.clone()).await.unwrap(); - let fin_receiver = context.validate_proposal(BlockNumber(0), TIMEOUT, content_receiver).await; + let fin_receiver = + context.validate_proposal(BlockNumber(0), 0, TIMEOUT, content_receiver).await; content_sender.close_channel(); assert_eq!(fin_receiver.await.unwrap().0, STATE_DIFF_COMMITMENT.0.0); } @@ -150,10 +152,10 @@ async fn repropose() { // Receive a proposal. Then re-retrieve it. let mut batcher = MockBatcherClient::new(); batcher.expect_validate_block().returning(move |_| Ok(())); - batcher.expect_start_height().return_once(|input: StartHeightInput| { - assert_eq!(input.height, BlockNumber(0)); - Ok(()) - }); + batcher + .expect_start_height() + .withf(|input| input.height == BlockNumber(0)) + .return_once(|_| Ok(())); batcher.expect_send_proposal_content().times(1).returning( move |input: SendProposalContentInput| { assert!(matches!(input.content, SendProposalContent::Txs(_))); @@ -176,12 +178,15 @@ async fn repropose() { subscriber_channels; let mut context = SequencerConsensusContext::new(Arc::new(batcher), broadcast_topic_client, NUM_VALIDATORS); + // Initialize the context for a specific height, starting with round 0. + context.set_height_and_round(BlockNumber(0), 0).await; // Receive a valid proposal. let (mut content_sender, content_receiver) = mpsc::channel(CHANNEL_SIZE); let txs = vec![generate_invoke_tx(Felt::TWO)]; content_sender.send(txs.clone()).await.unwrap(); - let fin_receiver = context.validate_proposal(BlockNumber(0), TIMEOUT, content_receiver).await; + let fin_receiver = + context.validate_proposal(BlockNumber(0), 0, TIMEOUT, content_receiver).await; content_sender.close_channel(); assert_eq!(fin_receiver.await.unwrap().0, STATE_DIFF_COMMITMENT.0.0); @@ -193,3 +198,143 @@ async fn repropose() { ) .await; } + +#[tokio::test] +async fn proposals_from_different_rounds() { + let mut batcher = MockBatcherClient::new(); + let proposal_id: Arc> = Arc::new(OnceLock::new()); + let proposal_id_clone = Arc::clone(&proposal_id); + batcher.expect_validate_block().returning(move |input: ValidateBlockInput| { + proposal_id_clone.set(input.proposal_id).unwrap(); + Ok(()) + }); + batcher + .expect_start_height() + .withf(|input| input.height == BlockNumber(0)) + .return_once(|_| Ok(())); + let proposal_id_clone = Arc::clone(&proposal_id); + batcher.expect_send_proposal_content().times(1).returning( + move |input: SendProposalContentInput| { + assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); + let SendProposalContent::Txs(txs) = input.content else { + panic!("Expected SendProposalContent::Txs, got {:?}", input.content); + }; + assert_eq!(txs, *TX_BATCH); + Ok(SendProposalContentResponse { response: ProposalStatus::Processing }) + }, + ); + let proposal_id_clone = Arc::clone(&proposal_id); + batcher.expect_send_proposal_content().times(1).returning( + move |input: SendProposalContentInput| { + assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); + assert!(matches!(input.content, SendProposalContent::Finish)); + Ok(SendProposalContentResponse { + response: ProposalStatus::Finished(ProposalCommitment { + state_diff_commitment: STATE_DIFF_COMMITMENT, + }), + }) + }, + ); + let TestSubscriberChannels { mock_network: _, subscriber_channels } = + mock_register_broadcast_topic().expect("Failed to create mock network"); + let BroadcastTopicChannels { broadcasted_messages_receiver: _, broadcast_topic_client } = + subscriber_channels; + let mut context = + SequencerConsensusContext::new(Arc::new(batcher), broadcast_topic_client, NUM_VALIDATORS); + // Initialize the context for a specific height, starting with round 0. + context.set_height_and_round(BlockNumber(0), 0).await; + context.set_height_and_round(BlockNumber(0), 1).await; + + // The proposal from the past round is ignored. + let (mut content_sender, content_receiver) = mpsc::channel(CHANNEL_SIZE); + content_sender.send(TX_BATCH.clone()).await.unwrap(); + let fin_receiver_past_round = + context.validate_proposal(BlockNumber(0), 0, TIMEOUT, content_receiver).await; + content_sender.close_channel(); + assert!(fin_receiver_past_round.await.is_err()); + + // The proposal from the current round should be validated. + let (mut content_sender, content_receiver) = mpsc::channel(CHANNEL_SIZE); + content_sender.send(TX_BATCH.clone()).await.unwrap(); + let fin_receiver_curr_round = + context.validate_proposal(BlockNumber(0), 1, TIMEOUT, content_receiver).await; + content_sender.close_channel(); + assert_eq!(fin_receiver_curr_round.await.unwrap().0, STATE_DIFF_COMMITMENT.0.0); + + // The proposal from the future round should not be processed. + let (mut content_sender, content_receiver) = mpsc::channel(CHANNEL_SIZE); + content_sender.send(TX_BATCH.clone()).await.unwrap(); + let fin_receiver_future_round = + context.validate_proposal(BlockNumber(0), 2, TIMEOUT, content_receiver).await; + content_sender.close_channel(); + assert!(fin_receiver_future_round.now_or_never().is_none()); +} + +#[tokio::test] +async fn interrupt_active_proposal() { + let mut batcher = MockBatcherClient::new(); + batcher + .expect_start_height() + .withf(|input| input.height == BlockNumber(0)) + .return_once(|_| Ok(())); + batcher + .expect_validate_block() + .times(1) + .withf(|input| input.proposal_id == ProposalId(0)) + .returning(|_| Ok(())); + batcher + .expect_validate_block() + .times(1) + .withf(|input| input.proposal_id == ProposalId(1)) + .returning(|_| Ok(())); + batcher + .expect_send_proposal_content() + .withf(|input| { + input.proposal_id == ProposalId(1) + && input.content == SendProposalContent::Txs(TX_BATCH.clone()) + }) + .times(1) + .returning(move |_| { + Ok(SendProposalContentResponse { response: ProposalStatus::Processing }) + }); + batcher + .expect_send_proposal_content() + .withf(|input| { + input.proposal_id == ProposalId(1) + && matches!(input.content, SendProposalContent::Finish) + }) + .times(1) + .returning(move |_| { + Ok(SendProposalContentResponse { + response: ProposalStatus::Finished(ProposalCommitment { + state_diff_commitment: STATE_DIFF_COMMITMENT, + }), + }) + }); + let TestSubscriberChannels { mock_network: _, subscriber_channels } = + mock_register_broadcast_topic().expect("Failed to create mock network"); + let BroadcastTopicChannels { broadcasted_messages_receiver: _, broadcast_topic_client } = + subscriber_channels; + let mut context = + SequencerConsensusContext::new(Arc::new(batcher), broadcast_topic_client, NUM_VALIDATORS); + // Initialize the context for a specific height, starting with round 0. + context.set_height_and_round(BlockNumber(0), 0).await; + + // Keep the sender open, as closing it or sending Fin would cause the validate to complete + // without needing interrupt. + let (mut _content_sender_0, content_receiver) = mpsc::channel(CHANNEL_SIZE); + let fin_receiver_0 = + context.validate_proposal(BlockNumber(0), 0, TIMEOUT, content_receiver).await; + + let (mut content_sender_1, content_receiver) = mpsc::channel(CHANNEL_SIZE); + content_sender_1.send(TX_BATCH.clone()).await.unwrap(); + let fin_receiver_1 = + context.validate_proposal(BlockNumber(0), 1, TIMEOUT, content_receiver).await; + content_sender_1.close_channel(); + // Move the context to the next round. + context.set_height_and_round(BlockNumber(0), 1).await; + + // Interrupt active proposal. + assert!(fin_receiver_0.await.is_err()); + assert_eq!(fin_receiver_1.await.unwrap().0, STATE_DIFF_COMMITMENT.0.0); +} From eaa6fcd2710feddb3c55f9c1626621e172a5df78 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Thu, 28 Nov 2024 16:54:54 +0200 Subject: [PATCH 21/25] chore(starknet_api): move rpc tx test util convertion fn (#2337) commit-id:9275b3bb --- Cargo.lock | 1 - .../src/starknet_api_test_utils.rs | 21 ----------------- crates/starknet_api/src/test_utils.rs | 23 +++++++++++++++++++ crates/starknet_http_server/Cargo.toml | 3 +-- crates/starknet_http_server/src/test_utils.rs | 2 +- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1b299a5a8f..e934462c58 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10416,7 +10416,6 @@ version = "0.0.0" dependencies = [ "axum", "hyper 0.14.30", - "mempool_test_utils", "papyrus_config", "reqwest 0.11.27", "serde", diff --git a/crates/mempool_test_utils/src/starknet_api_test_utils.rs b/crates/mempool_test_utils/src/starknet_api_test_utils.rs index 74a1a7b5a4..666cb1720c 100644 --- a/crates/mempool_test_utils/src/starknet_api_test_utils.rs +++ b/crates/mempool_test_utils/src/starknet_api_test_utils.rs @@ -10,7 +10,6 @@ use blockifier::test_utils::contracts::FeatureContract; use blockifier::test_utils::{create_trivial_calldata, CairoVersion}; use infra_utils::path::resolve_project_relative_path; use pretty_assertions::assert_ne; -use serde_json::to_string_pretty; use starknet_api::block::GasPrice; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::executable_transaction::AccountTransaction; @@ -361,23 +360,3 @@ impl Contract { } } } - -pub fn rpc_tx_to_json(tx: &RpcTransaction) -> String { - let mut tx_json = serde_json::to_value(tx) - .unwrap_or_else(|tx| panic!("Failed to serialize transaction: {tx:?}")); - - // Add type and version manually - let type_string = match tx { - RpcTransaction::Declare(_) => "DECLARE", - RpcTransaction::DeployAccount(_) => "DEPLOY_ACCOUNT", - RpcTransaction::Invoke(_) => "INVOKE", - }; - - tx_json - .as_object_mut() - .unwrap() - .extend([("type".to_string(), type_string.into()), ("version".to_string(), "0x3".into())]); - - // Serialize back to pretty JSON string - to_string_pretty(&tx_json).expect("Failed to serialize transaction") -} diff --git a/crates/starknet_api/src/test_utils.rs b/crates/starknet_api/src/test_utils.rs index dd27509fef..2addfd0ae3 100644 --- a/crates/starknet_api/src/test_utils.rs +++ b/crates/starknet_api/src/test_utils.rs @@ -4,10 +4,12 @@ use std::path::{Path, PathBuf}; use infra_utils::path::cargo_manifest_dir; use serde::{Deserialize, Serialize}; +use serde_json::to_string_pretty; use starknet_types_core::felt::Felt; use crate::block::BlockNumber; use crate::core::{ChainId, ContractAddress, Nonce}; +use crate::rpc_transaction::RpcTransaction; use crate::transaction::{Transaction, TransactionHash}; pub mod declare; @@ -90,3 +92,24 @@ macro_rules! compiled_class_hash { $crate::core::CompiledClassHash(starknet_types_core::felt::Felt::from($s)) }; } + +/// Converts a [`RpcTransaction`] to a JSON string. +pub fn rpc_tx_to_json(tx: &RpcTransaction) -> String { + let mut tx_json = serde_json::to_value(tx) + .unwrap_or_else(|tx| panic!("Failed to serialize transaction: {tx:?}")); + + // Add type and version manually + let type_string = match tx { + RpcTransaction::Declare(_) => "DECLARE", + RpcTransaction::DeployAccount(_) => "DEPLOY_ACCOUNT", + RpcTransaction::Invoke(_) => "INVOKE", + }; + + tx_json + .as_object_mut() + .unwrap() + .extend([("type".to_string(), type_string.into()), ("version".to_string(), "0x3".into())]); + + // Serialize back to pretty JSON string + to_string_pretty(&tx_json).expect("Failed to serialize transaction") +} diff --git a/crates/starknet_http_server/Cargo.toml b/crates/starknet_http_server/Cargo.toml index 1e62232cb5..aab5cfec01 100644 --- a/crates/starknet_http_server/Cargo.toml +++ b/crates/starknet_http_server/Cargo.toml @@ -6,7 +6,7 @@ license.workspace = true repository.workspace = true [features] -testing = ["mempool_test_utils", "reqwest"] +testing = ["reqwest", "starknet_api/testing"] [lints] workspace = true @@ -14,7 +14,6 @@ workspace = true [dependencies] axum.workspace = true hyper.workspace = true -mempool_test_utils = { workspace = true, optional = true } papyrus_config.workspace = true reqwest = { workspace = true, optional = true } serde.workspace = true diff --git a/crates/starknet_http_server/src/test_utils.rs b/crates/starknet_http_server/src/test_utils.rs index 8a319a8121..8faf1e302c 100644 --- a/crates/starknet_http_server/src/test_utils.rs +++ b/crates/starknet_http_server/src/test_utils.rs @@ -1,9 +1,9 @@ use std::net::SocketAddr; use axum::body::Body; -use mempool_test_utils::starknet_api_test_utils::rpc_tx_to_json; use reqwest::{Client, Response}; use starknet_api::rpc_transaction::RpcTransaction; +use starknet_api::test_utils::rpc_tx_to_json; use starknet_api::transaction::TransactionHash; use starknet_gateway_types::errors::GatewaySpecError; use starknet_sequencer_infra::test_utils::get_available_socket; From 8219645225755f12ff98a17ae2e3773b54110837 Mon Sep 17 00:00:00 2001 From: Itay Tsabary Date: Wed, 27 Nov 2024 20:05:30 +0200 Subject: [PATCH 22/25] chore(ci): remove redundant udeps ignore tags commit-id:972449d9 --- crates/papyrus_config/Cargo.toml | 3 --- crates/papyrus_node/Cargo.toml | 3 --- crates/starknet_monitoring_endpoint/Cargo.toml | 3 --- 3 files changed, 9 deletions(-) diff --git a/crates/papyrus_config/Cargo.toml b/crates/papyrus_config/Cargo.toml index a8e385ec25..c5896100d2 100644 --- a/crates/papyrus_config/Cargo.toml +++ b/crates/papyrus_config/Cargo.toml @@ -6,9 +6,6 @@ repository.workspace = true license-file.workspace = true description = "A library for handling node configuration." -[package.metadata.cargo-udeps.ignore] -development = ["tempfile"] # Dependency of a doc-test - [dependencies] clap = { workspace = true, features = ["env", "string"] } infra_utils.workspace = true diff --git a/crates/papyrus_node/Cargo.toml b/crates/papyrus_node/Cargo.toml index 8f25b05355..fc8c9b25e4 100644 --- a/crates/papyrus_node/Cargo.toml +++ b/crates/papyrus_node/Cargo.toml @@ -5,9 +5,6 @@ edition.workspace = true repository.workspace = true license-file.workspace = true -[package.metadata.cargo-udeps.ignore] -normal = ["clap", "papyrus_base_layer", "reqwest", "tokio"] - [features] default = ["rpc"] rpc = ["papyrus_rpc"] diff --git a/crates/starknet_monitoring_endpoint/Cargo.toml b/crates/starknet_monitoring_endpoint/Cargo.toml index 657132f74c..775c7ef0ee 100644 --- a/crates/starknet_monitoring_endpoint/Cargo.toml +++ b/crates/starknet_monitoring_endpoint/Cargo.toml @@ -5,9 +5,6 @@ edition.workspace = true repository.workspace = true license-file.workspace = true -[package.metadata.cargo-udeps.ignore] -normal = ["tokio"] - [features] testing = ["tokio", "tower"] From d437b34a7a8d2a1f798050b77f3fee1fb8aa9e75 Mon Sep 17 00:00:00 2001 From: Itay Tsabary Date: Wed, 27 Nov 2024 20:07:59 +0200 Subject: [PATCH 23/25] chore: update papyrus doc commit-id:8659371e --- docs/papyrus/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/papyrus/CONTRIBUTING.md b/docs/papyrus/CONTRIBUTING.md index 57cce3dba0..afcc62da74 100644 --- a/docs/papyrus/CONTRIBUTING.md +++ b/docs/papyrus/CONTRIBUTING.md @@ -53,4 +53,4 @@ Your code will need to pass [CI](../.github/workflows/ci.yml) before it can be m - Pass all local tests and all integration tests. - Be formatted according to [rustfmt](https://github.com/rust-lang/rustfmt). - Be linted according to [clippy](https://github.com/rust-lang/rust-clippy) -- Not include unused dependencies (Checked by [udeps](https://github.com/est31/cargo-udeps)). +- Not include unused dependencies (Checked by [machete](https://github.com/bnjbvr/cargo-machete)). From e68acb380ea215162af365b6f6002e56e360838d Mon Sep 17 00:00:00 2001 From: Itay Tsabary Date: Thu, 28 Nov 2024 10:45:53 +0200 Subject: [PATCH 24/25] chore(tests_integration): read nonce of latest block commit-id:4d0abfb5 --- .../tests/end_to_end_integration_test.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/crates/starknet_integration_tests/tests/end_to_end_integration_test.rs b/crates/starknet_integration_tests/tests/end_to_end_integration_test.rs index ab0ba4d67b..32de6911c8 100644 --- a/crates/starknet_integration_tests/tests/end_to_end_integration_test.rs +++ b/crates/starknet_integration_tests/tests/end_to_end_integration_test.rs @@ -31,11 +31,8 @@ fn get_latest_block_number(storage_reader: &StorageReader) -> BlockNumber { } /// Reads an account nonce after a block number from storage. -fn get_account_nonce( - storage_reader: &StorageReader, - block_number: BlockNumber, - contract_address: ContractAddress, -) -> Nonce { +fn get_account_nonce(storage_reader: &StorageReader, contract_address: ContractAddress) -> Nonce { + let block_number = get_latest_block_number(storage_reader); let txn = storage_reader.begin_ro_txn().unwrap(); let state_number = StateNumber::unchecked_right_after_block(block_number); get_nonce_at(&txn, state_number, None, contract_address) @@ -136,6 +133,6 @@ async fn test_end_to_end_integration(mut tx_generator: MultiAccountTransactionGe let expected_nonce_value = tx_hashes.len() + 1; let expected_nonce = Nonce(Felt::from_hex_unchecked(format!("0x{:X}", expected_nonce_value).as_str())); - let nonce = get_account_nonce(&batcher_storage_reader, EXPECTED_BLOCK_NUMBER, sender_address); + let nonce = get_account_nonce(&batcher_storage_reader, sender_address); assert_eq!(nonce, expected_nonce); } From 6f268c8c3e7f755f9ddc95d58405784831281664 Mon Sep 17 00:00:00 2001 From: Noam Spiegelstein Date: Wed, 27 Nov 2024 15:36:50 +0200 Subject: [PATCH 25/25] feat(sync): create state sync client --- config/sequencer/default_config.json | 50 +++++++++++++++++++ crates/starknet_sequencer_node/src/clients.rs | 31 ++++++++++++ .../src/config/component_config.rs | 4 ++ .../src/config/component_execution_config.rs | 9 ++++ 4 files changed, 94 insertions(+) diff --git a/config/sequencer/default_config.json b/config/sequencer/default_config.json index b5941df09d..dfbb72e416 100644 --- a/config/sequencer/default_config.json +++ b/config/sequencer/default_config.json @@ -564,6 +564,56 @@ "privacy": "Public", "value": "0.0.0.0:8080" }, + "components.state_sync.execution_mode": { + "description": "The component execution mode.", + "privacy": "Public", + "value": "LocalExecutionWithRemoteDisabled" + }, + "components.state_sync.local_server_config.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": false + }, + "components.state_sync.local_server_config.channel_buffer_size": { + "description": "The communication channel buffer size.", + "privacy": "Public", + "value": 32 + }, + "components.state_sync.remote_client_config.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, + "components.state_sync.remote_client_config.idle_connections": { + "description": "The maximum number of idle connections to keep alive.", + "privacy": "Public", + "value": 18446744073709551615 + }, + "components.state_sync.remote_client_config.idle_timeout": { + "description": "The duration in seconds to keep an idle connection open before closing.", + "privacy": "Public", + "value": 90 + }, + "components.state_sync.remote_client_config.retries": { + "description": "The max number of retries for sending a message.", + "privacy": "Public", + "value": 3 + }, + "components.state_sync.remote_client_config.socket": { + "description": "The remote component server socket.", + "privacy": "Public", + "value": "0.0.0.0:8080" + }, + "components.state_sync.remote_server_config.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, + "components.state_sync.remote_server_config.socket": { + "description": "The remote component server socket.", + "privacy": "Public", + "value": "0.0.0.0:8080" + }, "consensus_manager_config.consensus_config.consensus_delay": { "description": "Delay (seconds) before starting consensus to give time for network peering.", "privacy": "Public", diff --git a/crates/starknet_sequencer_node/src/clients.rs b/crates/starknet_sequencer_node/src/clients.rs index 4ef7440f01..ba3745f3ce 100644 --- a/crates/starknet_sequencer_node/src/clients.rs +++ b/crates/starknet_sequencer_node/src/clients.rs @@ -29,6 +29,13 @@ use starknet_mempool_types::communication::{ SharedMempoolClient, }; use starknet_sequencer_infra::component_client::{Client, LocalComponentClient}; +use starknet_state_sync_types::communication::{ + LocalStateSyncClient, + RemoteStateSyncClient, + SharedStateSyncClient, + StateSyncRequest, + StateSyncResponse, +}; use crate::communication::SequencerNodeCommunication; use crate::config::component_execution_config::ComponentExecutionMode; @@ -41,6 +48,7 @@ pub struct SequencerNodeClients { // TODO (Lev): Change to Option>. mempool_p2p_propagator_client: Option>, + state_sync_client: Option>, } /// A macro to retrieve a shared client (either local or remote) from a specified field in a struct, @@ -148,6 +156,19 @@ impl SequencerNodeClients { None => None, } } + + pub fn get_state_sync_shared_client(&self) -> Option { + get_shared_client!(self, state_sync_client) + } + + pub fn get_state_sync_local_client( + &self, + ) -> Option> { + match &self.state_sync_client { + Some(client) => client.get_local_client(), + None => None, + } + } } /// A macro for creating a component client, determined by the component's execution mode. Returns a @@ -250,10 +271,20 @@ pub fn create_node_clients( channels.take_mempool_p2p_propagator_tx(), config.components.mempool_p2p.remote_client_config ); + + let state_sync_client = create_client!( + &config.components.state_sync.execution_mode, + LocalStateSyncClient, + RemoteStateSyncClient, + channels.take_state_sync_tx(), + config.components.state_sync.remote_client_config + ); + SequencerNodeClients { batcher_client, mempool_client, gateway_client, mempool_p2p_propagator_client, + state_sync_client, } } diff --git a/crates/starknet_sequencer_node/src/config/component_config.rs b/crates/starknet_sequencer_node/src/config/component_config.rs index fa5d3fcfc6..975a8289cd 100644 --- a/crates/starknet_sequencer_node/src/config/component_config.rs +++ b/crates/starknet_sequencer_node/src/config/component_config.rs @@ -24,6 +24,8 @@ pub struct ComponentConfig { pub mempool_p2p: ComponentExecutionConfig, #[validate] pub monitoring_endpoint: ComponentExecutionConfig, + #[validate] + pub state_sync: ComponentExecutionConfig, } impl Default for ComponentConfig { @@ -36,6 +38,7 @@ impl Default for ComponentConfig { mempool: ComponentExecutionConfig::mempool_default_config(), mempool_p2p: ComponentExecutionConfig::mempool_p2p_default_config(), monitoring_endpoint: ComponentExecutionConfig::monitoring_endpoint_default_config(), + state_sync: ComponentExecutionConfig::state_sync_default_config(), } } } @@ -50,6 +53,7 @@ impl SerializeConfig for ComponentConfig { append_sub_config_name(self.mempool.dump(), "mempool"), append_sub_config_name(self.mempool_p2p.dump(), "mempool_p2p"), append_sub_config_name(self.monitoring_endpoint.dump(), "monitoring_endpoint"), + append_sub_config_name(self.state_sync.dump(), "state_sync"), ]; sub_configs.into_iter().flatten().collect() diff --git a/crates/starknet_sequencer_node/src/config/component_execution_config.rs b/crates/starknet_sequencer_node/src/config/component_execution_config.rs index 61a8a1d0ee..36307210bb 100644 --- a/crates/starknet_sequencer_node/src/config/component_execution_config.rs +++ b/crates/starknet_sequencer_node/src/config/component_execution_config.rs @@ -133,6 +133,15 @@ impl ComponentExecutionConfig { remote_server_config: None, } } + + pub fn state_sync_default_config() -> Self { + Self { + execution_mode: ComponentExecutionMode::LocalExecutionWithRemoteDisabled, + local_server_config: Some(LocalServerConfig::default()), + remote_client_config: None, + remote_server_config: None, + } + } } pub fn validate_single_component_config(