From 320fae2aef6c56ef1398c73acca10d9daece5f58 Mon Sep 17 00:00:00 2001 From: fannyguthmann Date: Thu, 3 Aug 2023 14:57:19 +0300 Subject: [PATCH 01/44] added comments to syscalls/deprecated_business_logic_syscall_handler.rs --- ...precated_business_logic_syscall_handler.rs | 61 +++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/src/syscalls/deprecated_business_logic_syscall_handler.rs b/src/syscalls/deprecated_business_logic_syscall_handler.rs index 25e473abf..abb639fdc 100644 --- a/src/syscalls/deprecated_business_logic_syscall_handler.rs +++ b/src/syscalls/deprecated_business_logic_syscall_handler.rs @@ -50,23 +50,34 @@ use num_traits::{One, ToPrimitive, Zero}; /// Deprecated version of BusinessLogicSyscallHandler. #[derive(Debug)] pub struct DeprecatedBLSyscallHandler<'a, S: StateReader> { + /// Context of the transaction being executed pub(crate) tx_execution_context: TransactionExecutionContext, /// Events emitted by the current contract call. pub(crate) events: Vec, /// A list of dynamically allocated segments that are expected to be read-only. pub(crate) read_only_segments: Vec<(Relocatable, MaybeRelocatable)>, + /// Manages execution resources pub(crate) resources_manager: ExecutionResourcesManager, + /// Address of the contract pub(crate) contract_address: Address, + /// Address of the caller pub(crate) caller_address: Address, + /// Messages from L2 to L1 pub(crate) l2_to_l1_messages: Vec, + /// Context information related to the current block pub(crate) block_context: BlockContext, + /// Pointer to transaction information pub(crate) tx_info_ptr: Option, + /// State of the storage related to Starknet contract pub(crate) starknet_storage_state: ContractStorageState<'a, S>, + /// Information about internal calls pub(crate) internal_calls: Vec, + /// Pointer to the expected system call pub(crate) expected_syscall_ptr: Relocatable, } impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { + /// Constructor creates a new DeprecatedBLSyscallHandler instance pub fn new( tx_execution_context: TransactionExecutionContext, state: &'a mut CachedState, @@ -100,6 +111,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { } } + /// Constructor with default values, used for testing pub fn default_with(state: &'a mut CachedState) -> Self { DeprecatedBLSyscallHandler::new_for_testing(BlockInfo::default(), Default::default(), state) } @@ -110,6 +122,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { .increment_syscall_counter(syscall_name, 1); } + /// Constructor for testing purposes pub fn new_for_testing( block_info: BlockInfo, _contract_address: Address, @@ -181,6 +194,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(()) } + /// Checks if constructor entry points are empty fn constructor_entry_points_empty( &self, contract_class: CompiledClass, @@ -195,6 +209,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { } } + /// Executes a constructor entry point fn execute_constructor_entry_point( &mut self, contract_address: &Address, @@ -247,16 +262,18 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { } impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { + /// Emit an event. pub(crate) fn emit_event( &mut self, vm: &VirtualMachine, syscall_ptr: Relocatable, ) -> Result<(), SyscallHandlerError> { + // Read and validate the syscall request for emitting an event. let request = match self.read_and_validate_syscall_request("emit_event", vm, syscall_ptr) { Ok(DeprecatedSyscallRequest::EmitEvent(emit_event_struct)) => emit_event_struct, _ => return Err(SyscallHandlerError::InvalidSyscallReadRequest), }; - + // Extract keys and data. let keys_len = request.keys_len; let data_len = request.data_len; let order = self.tx_execution_context.n_emitted_events; @@ -269,6 +286,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(()) } + /// Allocate a segment in memory. pub(crate) fn allocate_segment( &mut self, vm: &mut VirtualMachine, @@ -283,6 +301,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(segment_start) } + /// Deploy a contract. pub(crate) fn syscall_deploy( &mut self, vm: &VirtualMachine, @@ -343,6 +362,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(deploy_contract_address) } + /// Call a contract. pub(crate) fn syscall_call_contract( &mut self, syscall_name: &str, @@ -461,10 +481,12 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(retdata) } + /// Returns the block information associated with the current context. pub(crate) fn get_block_info(&self) -> &BlockInfo { &self.block_context.block_info } + /// Get the caller's address from a virtual machine, using the syscall pointer. pub(crate) fn syscall_get_caller_address( &mut self, vm: &VirtualMachine, @@ -483,6 +505,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(self.caller_address.clone()) } + /// Handles the delegation of an L1 handler call. pub(crate) fn delegate_l1_handler( &mut self, vm: &mut VirtualMachine, @@ -491,6 +514,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { self.call_contract_and_write_response("delegate_l1_handler", vm, syscall_ptr) } + /// Get the contract address from a virtual machine, using the syscall pointer. pub(crate) fn syscall_get_contract_address( &mut self, vm: &VirtualMachine, @@ -509,6 +533,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(self.contract_address.clone()) } + /// Sends a message from L2 to L1, including the destination address and payload. pub(crate) fn send_message_to_l1( &mut self, vm: &VirtualMachine, @@ -538,6 +563,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(()) } + /// Get the pointer to transaction information. pub(crate) fn syscall_get_tx_info_ptr( &mut self, vm: &mut VirtualMachine, @@ -564,6 +590,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(tx_info_ptr_temp) } + /// Performs a storage read operation. pub(crate) fn storage_read( &mut self, vm: &mut VirtualMachine, @@ -586,6 +613,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { response.write_syscall_response(vm, syscall_ptr) } + /// Performs a storage write operation. pub(crate) fn storage_write( &mut self, vm: &mut VirtualMachine, @@ -607,6 +635,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(()) } + /// Deploys a contract to the virtual machine. pub(crate) fn deploy( &mut self, vm: &mut VirtualMachine, @@ -627,7 +656,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(()) } - // Executes the contract call and fills the DeprecatedCallContractResponse struct. + /// Executes the contract call and fills the DeprecatedCallContractResponse struct. pub(crate) fn call_contract_and_write_response( &mut self, syscall_name: &str, @@ -649,7 +678,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { self.write_syscall_response(&response, vm, syscall_ptr) } - + /// Writes the response of a syscall to the virtual machine. pub(crate) fn write_syscall_response( &self, response: &R, @@ -659,6 +688,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { response.write_syscall_response(vm, syscall_ptr) } + /// Get the block number pub(crate) fn get_block_number( &mut self, vm: &mut VirtualMachine, @@ -669,6 +699,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { .write_syscall_response(vm, syscall_ptr) } + /// Get the transactino info. pub(crate) fn get_tx_info( &mut self, vm: &mut VirtualMachine, @@ -686,6 +717,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { response.write_syscall_response(vm, syscall_ptr) } + /// Get the transaction signature. pub(crate) fn get_tx_signature( &mut self, vm: &mut VirtualMachine, @@ -709,6 +741,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { response.write_syscall_response(vm, syscall_ptr) } + /// Get the time stamp of the block. pub(crate) fn get_block_timestamp( &mut self, vm: &mut VirtualMachine, @@ -731,6 +764,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { response.write_syscall_response(vm, syscall_ptr) } + /// Get the caller address. pub(crate) fn get_caller_address( &mut self, vm: &mut VirtualMachine, @@ -741,6 +775,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { response.write_syscall_response(vm, syscall_ptr) } + /// Get the contract address pub(crate) fn get_contract_address( &mut self, vm: &mut VirtualMachine, @@ -751,6 +786,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { response.write_syscall_response(vm, syscall_ptr) } + /// Get the sequencer address pub(crate) fn get_sequencer_address( &mut self, vm: &mut VirtualMachine, @@ -773,6 +809,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { response.write_syscall_response(vm, syscall_ptr) } + /// Executes a library call pub(crate) fn library_call( &mut self, vm: &mut VirtualMachine, @@ -781,6 +818,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { self.call_contract_and_write_response("library_call", vm, syscall_ptr) } + /// Executes a library call specific to an L1 handler pub(crate) fn library_call_l1_handler( &mut self, vm: &mut VirtualMachine, @@ -789,6 +827,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { self.call_contract_and_write_response("library_call_l1_handler", vm, syscall_ptr) } + /// Executes a contract call pub(crate) fn call_contract( &mut self, vm: &mut VirtualMachine, @@ -797,6 +836,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { self.call_contract_and_write_response("call_contract", vm, syscall_ptr) } + /// Executes a delegate call pub(crate) fn delegate_call( &mut self, vm: &mut VirtualMachine, @@ -805,6 +845,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { self.call_contract_and_write_response("delegate_call", vm, syscall_ptr) } + /// Reads a value from the storage state using the specified address. pub(crate) fn syscall_storage_read( &mut self, address: Address, @@ -814,6 +855,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { .read(&felt_to_hash(&address.0))?) } + /// Writes a value to the storage state using the specified address. pub(crate) fn syscall_storage_write( &mut self, address: Address, @@ -825,6 +867,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(()) } + /// Reads and validates a syscall request, and updates the expected syscall pointer offset. pub(crate) fn read_and_validate_syscall_request( &mut self, syscall_name: &str, @@ -838,6 +881,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(syscall_request) } + /// Reads and validates syscall requests. Matches syscall names to their corresponding requests. pub(crate) fn read_syscall_request( &self, syscall_name: &str, @@ -876,6 +920,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { } } + /// Replaces class at the specified address with a new one based on the request. pub(crate) fn replace_class( &mut self, vm: &mut VirtualMachine, @@ -897,7 +942,8 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(()) } - + /// Performs validation after the Virtual Machine run. Validates that the stopping pointer is as expected, + /// and validates that the read only segments have not been altered. pub(crate) fn post_run( &self, runner: &mut VirtualMachine, @@ -914,6 +960,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { } } +/// Test module for the syscalls. #[cfg(test)] mod tests { use crate::{ @@ -941,6 +988,7 @@ mod tests { type DeprecatedBLSyscallHandler<'a> = super::DeprecatedBLSyscallHandler<'a, InMemoryStateReader>; + /// Tests that the hint application doesn't allow inconsistency in memory. #[test] fn run_alloc_hint_ap_is_not_empty() { let hint_code = "memory[ap] = segments.add()"; @@ -958,6 +1006,7 @@ mod tests { ); } + /// Tests error handling when trying to deploy from address zero. #[test] fn deploy_from_zero_error() { let mut state = CachedState::::default(); @@ -984,6 +1033,7 @@ mod tests { ) } + /// Tests if a segment can be allocated successfully. #[test] fn can_allocate_segment() { let mut state = CachedState::::default(); @@ -1000,6 +1050,7 @@ mod tests { assert_eq!(expected_value, 7.into()); } + /// Tests if the block number can be retrieved successfully. #[test] fn test_get_block_number() { let mut state = CachedState::::default(); @@ -1020,6 +1071,7 @@ mod tests { ); } + /// Tests if the contract address can be retrieved successfully. #[test] fn test_get_contract_address_ok() { let mut state = CachedState::::default(); @@ -1037,6 +1089,7 @@ mod tests { ) } + /// Tests if the empty storage read returns zero. #[test] fn test_storage_read_empty() { let mut state = CachedState::::default(); From c47e7f40efb8a01c93633ba02c6cbf4d6dbd2d98 Mon Sep 17 00:00:00 2001 From: fannyguthmann Date: Thu, 10 Aug 2023 10:10:19 +0300 Subject: [PATCH 02/44] corrected comments --- .../deprecated_business_logic_syscall_handler.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/syscalls/deprecated_business_logic_syscall_handler.rs b/src/syscalls/deprecated_business_logic_syscall_handler.rs index abb639fdc..41b151e72 100644 --- a/src/syscalls/deprecated_business_logic_syscall_handler.rs +++ b/src/syscalls/deprecated_business_logic_syscall_handler.rs @@ -70,14 +70,14 @@ pub struct DeprecatedBLSyscallHandler<'a, S: StateReader> { pub(crate) tx_info_ptr: Option, /// State of the storage related to Starknet contract pub(crate) starknet_storage_state: ContractStorageState<'a, S>, - /// Information about internal calls + /// List of internal calls during the syscall execution pub(crate) internal_calls: Vec, - /// Pointer to the expected system call + /// Get the expected pointer to the syscall pub(crate) expected_syscall_ptr: Relocatable, } impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { - /// Constructor creates a new DeprecatedBLSyscallHandler instance + /// Constructor creates a new [DeprecatedBLSyscallHandler] instance pub fn new( tx_execution_context: TransactionExecutionContext, state: &'a mut CachedState, @@ -656,7 +656,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(()) } - /// Executes the contract call and fills the DeprecatedCallContractResponse struct. + /// Executes the contract call and fills the [DeprecatedCallContractResponse] struct. pub(crate) fn call_contract_and_write_response( &mut self, syscall_name: &str, @@ -699,7 +699,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { .write_syscall_response(vm, syscall_ptr) } - /// Get the transactino info. + /// Get the transaction info. pub(crate) fn get_tx_info( &mut self, vm: &mut VirtualMachine, From 831b5f851e53e313dbdd71918b756a46a2ae8f9d Mon Sep 17 00:00:00 2001 From: fannyguthmann Date: Thu, 10 Aug 2023 10:50:38 +0300 Subject: [PATCH 03/44] added informations on system calls --- .../deprecated_business_logic_syscall_handler.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/syscalls/deprecated_business_logic_syscall_handler.rs b/src/syscalls/deprecated_business_logic_syscall_handler.rs index 41b151e72..222eb86dc 100644 --- a/src/syscalls/deprecated_business_logic_syscall_handler.rs +++ b/src/syscalls/deprecated_business_logic_syscall_handler.rs @@ -122,6 +122,8 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { .increment_syscall_counter(syscall_name, 1); } + /// System calls allow a contract to requires services from the Starknet OS + /// See further documentation on https://docs.starknet.io/documentation/architecture_and_concepts/Contracts/system-calls/ /// Constructor for testing purposes pub fn new_for_testing( block_info: BlockInfo, @@ -129,14 +131,23 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { state: &'a mut CachedState, ) -> Self { let syscalls = Vec::from([ + // Emits an event with a given set of keys and data. "emit_event".to_string(), + // Deploys a new instance of a previously declared class. "deploy".to_string(), + // Gets information about the original transaction. "get_tx_info".to_string(), + // Sends a message to L1. "send_message_to_l1".to_string(), + // Calls the requested function in any previously declared class. "library_call".to_string(), + // Returns the address of the calling contract, or 0 if the call was not initiated by another contract. "get_caller_address".to_string(), + // Gets the address of the contract who raised the system call. "get_contract_address".to_string(), + // Returns the address of the sequencer that generated the current block. "get_sequencer_address".to_string(), + // Gets the timestamp of the block in which the transaction is executed. "get_block_timestamp".to_string(), ]); let events = Vec::new(); From 19368fd3a92081dc85e4b48ddf3f28b1d1c1c0c7 Mon Sep 17 00:00:00 2001 From: fannyguthmann Date: Fri, 11 Aug 2023 15:14:30 +0300 Subject: [PATCH 04/44] change comments --- ...precated_business_logic_syscall_handler.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/syscalls/deprecated_business_logic_syscall_handler.rs b/src/syscalls/deprecated_business_logic_syscall_handler.rs index 222eb86dc..3187b1e02 100644 --- a/src/syscalls/deprecated_business_logic_syscall_handler.rs +++ b/src/syscalls/deprecated_business_logic_syscall_handler.rs @@ -273,7 +273,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { } impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { - /// Emit an event. + /// Emits an event with a given set of keys and data. pub(crate) fn emit_event( &mut self, vm: &VirtualMachine, @@ -312,7 +312,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(segment_start) } - /// Deploy a contract. + /// Deploys a new instance of a previously declared class. pub(crate) fn syscall_deploy( &mut self, vm: &VirtualMachine, @@ -497,7 +497,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { &self.block_context.block_info } - /// Get the caller's address from a virtual machine, using the syscall pointer. + /// Returns the address of the calling contract, or 0 if the call was not initiated by another contract. pub(crate) fn syscall_get_caller_address( &mut self, vm: &VirtualMachine, @@ -525,7 +525,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { self.call_contract_and_write_response("delegate_l1_handler", vm, syscall_ptr) } - /// Get the contract address from a virtual machine, using the syscall pointer. + /// Gets the address of the contract who raised the system call. pub(crate) fn syscall_get_contract_address( &mut self, vm: &VirtualMachine, @@ -544,7 +544,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { Ok(self.contract_address.clone()) } - /// Sends a message from L2 to L1, including the destination address and payload. + /// Sends a message to L1. pub(crate) fn send_message_to_l1( &mut self, vm: &VirtualMachine, @@ -710,7 +710,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { .write_syscall_response(vm, syscall_ptr) } - /// Get the transaction info. + /// Gets information about the original transaction pub(crate) fn get_tx_info( &mut self, vm: &mut VirtualMachine, @@ -752,7 +752,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { response.write_syscall_response(vm, syscall_ptr) } - /// Get the time stamp of the block. + /// Gets the timestamp of the block in which the transaction is executed. pub(crate) fn get_block_timestamp( &mut self, vm: &mut VirtualMachine, @@ -797,7 +797,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { response.write_syscall_response(vm, syscall_ptr) } - /// Get the sequencer address + /// Returns the address of the sequencer that generated the current block. pub(crate) fn get_sequencer_address( &mut self, vm: &mut VirtualMachine, @@ -820,7 +820,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { response.write_syscall_response(vm, syscall_ptr) } - /// Executes a library call + /// Calls the requested function in any previously declared class. pub(crate) fn library_call( &mut self, vm: &mut VirtualMachine, @@ -829,7 +829,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { self.call_contract_and_write_response("library_call", vm, syscall_ptr) } - /// Executes a library call specific to an L1 handler + /// Calls the requested function specific to an L1 handler pub(crate) fn library_call_l1_handler( &mut self, vm: &mut VirtualMachine, From d19dc790777f3ab62e8879173a3bbbcc478cb9ba Mon Sep 17 00:00:00 2001 From: Juan Bono Date: Tue, 29 Aug 2023 15:50:55 -0300 Subject: [PATCH 05/44] Added Starknet API / Blockifier RPC State Reader (#927) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * initial commit * add get_class_hash_at * Added get_nonce_at * Added get_storage_at * Remove comments * Added get block info * Fixed get_contract_class() * WIP fixing desearlization * WIP Fix * Finished fixing get_contract_class() * Uncommented tests, new get_contract_class * Remove file * WIP Fixing tests * Finish fixing simple tests * Fixed transaction trace and block info * Fix import * Refactor, fixes, added test * Fixed warnings, removed tests * Fixed get_transaction_receipt * Fixed actual_fee from get_transaction_receipt * Format Cargo.toml * Redid BlockValue * Removed middle response types * Changed unreachable with unimplemented * Move import inside fn * Fix tests --------- Co-authored-by: Estéfano Bargas --- Cargo.lock | 368 +++++++++-- Cargo.toml | 2 +- rpc_state_reader_sn_api/Cargo.toml | 24 + rpc_state_reader_sn_api/src/lib.rs | 972 +++++++++++++++++++++++++++++ 4 files changed, 1304 insertions(+), 62 deletions(-) create mode 100644 rpc_state_reader_sn_api/Cargo.toml create mode 100644 rpc_state_reader_sn_api/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 787d2cf04..fbf90ed9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -663,6 +663,40 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blockifier" +version = "0.2.0-rc0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cb4d375ae4ea55963350f296c9c22f245ceff91e7c9edcd61320792901b783f" +dependencies = [ + "ark-ff", + "ark-secp256k1", + "cached", + "cairo-felt", + "cairo-lang-casm", + "cairo-lang-runner", + "cairo-lang-starknet", + "cairo-vm", + "ctor", + "derive_more", + "indexmap 1.9.3", + "itertools 0.10.5", + "keccak", + "log", + "num-bigint", + "num-integer", + "num-traits 0.2.16", + "phf", + "serde", + "serde_json", + "sha3", + "starknet-crypto 0.5.1", + "starknet_api 0.4.1", + "strum", + "strum_macros", + "thiserror", +] + [[package]] name = "brotli" version = "3.3.4" @@ -717,6 +751,42 @@ dependencies = [ "bytes", ] +[[package]] +name = "cached" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b195e4fbc4b6862bbd065b991a34750399c119797efff72492f28a5864de8700" +dependencies = [ + "async-trait", + "cached_proc_macro", + "cached_proc_macro_types", + "futures", + "hashbrown 0.13.2", + "instant", + "once_cell", + "thiserror", + "tokio", +] + +[[package]] +name = "cached_proc_macro" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b48814962d2fd604c50d2b9433c2a41a0ab567779ee2c02f7fba6eca1221f082" +dependencies = [ + "cached_proc_macro_types", + "darling 0.14.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cached_proc_macro_types" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663" + [[package]] name = "cairo-felt" version = "0.8.5" @@ -732,9 +802,9 @@ dependencies = [ [[package]] name = "cairo-lang-casm" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb23212923a656f06d49ff2a953d83a40c916dc01802bf43a6a8b230cc1ae5" +checksum = "213103e1cf9049abd443f97088939d9cf6ef5500b295003be2b244c702d8fe9c" dependencies = [ "cairo-lang-utils", "indoc", @@ -749,9 +819,9 @@ dependencies = [ [[package]] name = "cairo-lang-compiler" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb8e62e8ea8ec8953900c591e8ec8afadeacb5414c66c391e2374cd33e75265" +checksum = "4eb857feb6d7a73fd33193a2cc141c04ab345d47bcbd9e2c014ef3422ebc6d55" dependencies = [ "anyhow", "cairo-lang-defs", @@ -774,18 +844,18 @@ dependencies = [ [[package]] name = "cairo-lang-debug" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688919661be70385834619abb6e91b822c2e36ee0d5490efa6a3c708741cb1a9" +checksum = "af06d0c89bd515707d6f0140a880f6463b955189fa5f97719edd62348c36ee2c" dependencies = [ "cairo-lang-utils", ] [[package]] name = "cairo-lang-defs" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ae52e506409795292e5fa5a06cda8cc705a1b714d31071841827b74453dad3" +checksum = "59ead2773a4d8147c3c25666d9a97a41161eeb59e0d0d1060b5f9b6fa68d0da1" dependencies = [ "cairo-lang-debug", "cairo-lang-diagnostics", @@ -801,9 +871,9 @@ dependencies = [ [[package]] name = "cairo-lang-diagnostics" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f53df12acc714e2fc505fba706c754c0d19d092710b4527dbec489b59589b1" +checksum = "a6924bc3d558495a5327955da3aec15e6ab71c0f83e955258ffbb0e1a20ead87" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -814,9 +884,9 @@ dependencies = [ [[package]] name = "cairo-lang-eq-solver" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be26fab051abb2ff8e53cd3bd728db6e85d5b044c6779c0ac202c68613844bbb" +checksum = "3ac8853dae37b4f3b4d3d8d36002b2fb0b52aa5f578f15b0bf47cedd2ec7358b" dependencies = [ "cairo-lang-utils", "good_lp", @@ -826,9 +896,9 @@ dependencies = [ [[package]] name = "cairo-lang-filesystem" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22faaa72b212e6dd21a9d1547e86cea65a3cb7c7f4d43be1f7b051e4a1613a46" +checksum = "acb3fc0d5582fd27910e63cca94a7c9d41acc0045a815ff99ed941eb45183375" dependencies = [ "cairo-lang-debug", "cairo-lang-utils", @@ -840,9 +910,9 @@ dependencies = [ [[package]] name = "cairo-lang-lowering" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2160203c5556d680f155e1a24432c77ada4bf04c1701e08cfb8e35d33a717b6" +checksum = "a7d7f5acc6e4c67a6f2232df1d1f13039453cb50d2971183a1fd254067735cd0" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -865,9 +935,9 @@ dependencies = [ [[package]] name = "cairo-lang-parser" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b25cb9b8be9bf706739030a282d088cb0a2de42e2ec0a21e720ec5bb34a41218" +checksum = "7a9716a807fd4430a4af396ad9f7bd1228414c972a24a7e4211ac83d83f538d1" dependencies = [ "cairo-lang-diagnostics", "cairo-lang-filesystem", @@ -886,9 +956,9 @@ dependencies = [ [[package]] name = "cairo-lang-plugins" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b685065afc3305b780e9713132a4a747de5f0d71bcf101201474ad0ebfe3f06e" +checksum = "bb782377b1cb01ccb3e00aec3903912895ae3cf6b5a8e05918bc0e4a837c1929" dependencies = [ "cairo-lang-defs", "cairo-lang-diagnostics", @@ -906,9 +976,9 @@ dependencies = [ [[package]] name = "cairo-lang-proc-macros" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1a49e58ad1eeefe0b1efc667a6ee544b5f906c6123d6d1e77e0321b4d1db92" +checksum = "4756fe3fdb86d3d8fda40ee250d146300381e98110ec7e4a624407c7e0b7e63f" dependencies = [ "cairo-lang-debug", "quote", @@ -917,9 +987,9 @@ dependencies = [ [[package]] name = "cairo-lang-project" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29d3e28ff80fb8fd94f4e6db12c42bacbe6e3ab7a991aa997861b99d0cb2fa2" +checksum = "913cdcd5e567d7ca13d1b37822feeac19973f5133a4fbab76b67e12c847bff3a" dependencies = [ "cairo-lang-filesystem", "cairo-lang-utils", @@ -931,9 +1001,9 @@ dependencies = [ [[package]] name = "cairo-lang-runner" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abcc2ff6ebb5fbdd9578f3506a6ffab3944da5383e38546ed30eebaa992df01b" +checksum = "55ce3aa736c0180b5ed5320138b3f8ed70696618f2cb23bc86217eebfa2274ea" dependencies = [ "anyhow", "ark-ff", @@ -968,9 +1038,9 @@ dependencies = [ [[package]] name = "cairo-lang-semantic" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc0538b422abaff683425ceb945d29d956172e2748f28924904226303d07486" +checksum = "a6962d05da3c355f8fc49e97dda4252dfa71969399ef5658130b9cdc86d8a805" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -991,9 +1061,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b84a986fa30c459447cbe7175243d50ba55e5659d8efc3a867b051ca7a629b0" +checksum = "872cf03415aa48c7757e4cee4b0223a158fcc9abddf55574f6c387324f25cc1f" dependencies = [ "cairo-lang-utils", "const-fnv1a-hash", @@ -1014,9 +1084,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-ap-change" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224dad404d483b4c3ea9cb08d94285c2b4755539eaf78dcd5e280bf1a2ca96cb" +checksum = "7eba2fbd5f13210a46c2050fe156776490c556f6f0335401bda810640c1e65fd" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -1028,9 +1098,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-gas" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1246a3fc5249d5fc7e7d1b0611dd41e6b13e88c4fd4ce5d77708581975baa6a" +checksum = "c9f4cec68f861b86dd6429592d9c0c535cbb983a9b7c21fc906b659b35e7882e" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -1042,9 +1112,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-generator" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91b4e0a3a883348e262ca84ca085ff402b52dc206278352c0d74db476d76e960" +checksum = "65f050d6c717090ee10be52950cfe639709af27138eb9cd4122b0ab171a5cf2a" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -1068,9 +1138,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-to-casm" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ba03115b3cf4d3fe691f5574ff1a95565f1abc430fba717d6605db11d7e2cd4" +checksum = "58c53fa4c6013827c42c1e02ee9a58fa5901cb18a711bdfeb1af379f69d2055c" dependencies = [ "assert_matches", "cairo-felt", @@ -1090,9 +1160,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-type-size" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff65da8fd75ab9020159b072817c8a516d859b0b0bc60ab3693681b635339729" +checksum = "07a5e70b5a5826edeb61ec375886847f51e1b995709e3f36d657844fbd703d45" dependencies = [ "cairo-lang-sierra", "cairo-lang-utils", @@ -1100,9 +1170,9 @@ dependencies = [ [[package]] name = "cairo-lang-starknet" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "326f47941e94a8cdbb420a041411df44a4328a5b8190bb5647092499ed4d3fa9" +checksum = "cfaa6629cd5a9cc13543d59bd5494fc01cc4118efbcc5b13528be4539a35f77f" dependencies = [ "anyhow", "cairo-felt", @@ -1141,9 +1211,9 @@ dependencies = [ [[package]] name = "cairo-lang-syntax" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84885246b2b8626034fe8fe2fc7360f8618b695769413bd8f8b31063c8964d8d" +checksum = "b23b312f07e45bc0bb2d240187a37db2816393c285896c9ab453c8ca8e128d25" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -1158,9 +1228,9 @@ dependencies = [ [[package]] name = "cairo-lang-syntax-codegen" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a87271440bc2624da4b5411db90403302224c39f2cdac4293f52967439238e6c" +checksum = "0225e4b5f09523bc424fae216ea899cb8f9132fb0da164096cee5e2ce79076fe" dependencies = [ "genco", "xshell", @@ -1168,9 +1238,9 @@ dependencies = [ [[package]] name = "cairo-lang-utils" -version = "2.1.0-rc4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22628c2fcd2d249ed6655a0fb7ba29a668a6b65741016b8ed562bd5ef906778a" +checksum = "b2b4bdb1d6509e2579d04d1757070f88c2542ff033194f749772669a1615c7e4" dependencies = [ "indexmap 2.0.0", "itertools 0.11.0", @@ -1410,6 +1480,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctor" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f34ba9a9bcb8645379e9de8cb3ecfcf4d1c85ba66d90deb3259206fa5aa193b" +dependencies = [ + "quote", + "syn 2.0.28", +] + [[package]] name = "ctr" version = "0.9.2" @@ -1419,14 +1499,38 @@ dependencies = [ "cipher", ] +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + [[package]] name = "darling" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.3", + "darling_macro 0.20.3", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", ] [[package]] @@ -1443,13 +1547,24 @@ dependencies = [ "syn 2.0.28", ] +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + [[package]] name = "darling_macro" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ - "darling_core", + "darling_core 0.20.3", "quote", "syn 2.0.28", ] @@ -1692,6 +1807,20 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.28" @@ -1699,6 +1828,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -1707,6 +1837,12 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + [[package]] name = "futures-macro" version = "0.3.28" @@ -1753,7 +1889,7 @@ dependencies = [ "honggfuzz", "num-traits 0.2.16", "serde_json", - "starknet_api", + "starknet_api 0.3.0", "starknet_in_rust", "tempfile", ] @@ -2639,6 +2775,39 @@ dependencies = [ "indexmap 1.9.3", ] +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.28", +] + [[package]] name = "phf_shared" version = "0.10.0" @@ -2648,6 +2817,15 @@ dependencies = [ "siphasher", ] +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pico-args" version = "0.5.0" @@ -2940,12 +3118,31 @@ dependencies = [ "serde_json", "serde_with 3.1.0", "starknet", - "starknet_api", + "starknet_api 0.3.0", "starknet_in_rust", "thiserror", "ureq", ] +[[package]] +name = "rpc_state_reader_sn_api" +version = "0.3.1" +dependencies = [ + "blockifier", + "cairo-lang-starknet", + "cairo-lang-utils", + "cairo-vm", + "dotenv", + "flate2", + "serde", + "serde_json", + "serde_with 3.1.0", + "starknet", + "starknet_api 0.4.1", + "thiserror", + "ureq", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -3138,18 +3335,18 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" -version = "1.0.180" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.180" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", @@ -3258,7 +3455,7 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" dependencies = [ - "darling", + "darling 0.20.3", "proc-macro2", "quote", "syn 2.0.28", @@ -3270,7 +3467,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea3cee93715c2e266b9338b7544da68a9f24e227722ba482bd1c024367c77c65" dependencies = [ - "darling", + "darling 0.20.3", "proc-macro2", "quote", "syn 2.0.28", @@ -3600,6 +3797,24 @@ dependencies = [ "thiserror", ] +[[package]] +name = "starknet_api" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6e445fbd6bf3826dda26fd64aa5311353b4799c9bd1119d6ec1906be4c73bf" +dependencies = [ + "cairo-lang-starknet", + "derive_more", + "hex", + "indexmap 1.9.3", + "once_cell", + "primitive-types", + "serde", + "serde_json", + "starknet-crypto 0.5.1", + "thiserror", +] + [[package]] name = "starknet_in_rust" version = "0.3.1" @@ -3630,7 +3845,7 @@ dependencies = [ "sha3", "starknet", "starknet-crypto 0.5.1", - "starknet_api", + "starknet_api 0.3.0", "thiserror", ] @@ -3649,7 +3864,7 @@ dependencies = [ "new_debug_unreachable", "once_cell", "parking_lot 0.12.1", - "phf_shared", + "phf_shared 0.10.0", "precomputed-hash", ] @@ -3659,6 +3874,25 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + [[package]] name = "subtle" version = "2.5.0" @@ -3824,9 +4058,21 @@ dependencies = [ "pin-project-lite", "signal-hook-registry", "socket2", + "tokio-macros", "windows-sys", ] +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + [[package]] name = "tokio-rustls" version = "0.24.1" diff --git a/Cargo.toml b/Cargo.toml index 002157c15..e3110c53b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ with_mimalloc = ["dep:mimalloc"] cairo_1_tests = [] [workspace] -members = ["cli", "fuzzer", "rpc_state_reader"] +members = ["cli", "fuzzer", "rpc_state_reader", "rpc_state_reader_sn_api"] [workspace.dependencies] cairo-vm = { version = "0.8.5", features = ["cairo-1-hints"] } diff --git a/rpc_state_reader_sn_api/Cargo.toml b/rpc_state_reader_sn_api/Cargo.toml new file mode 100644 index 000000000..ba20520ba --- /dev/null +++ b/rpc_state_reader_sn_api/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "rpc_state_reader_sn_api" +version = "0.3.1" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ureq = { version = "2.7.1", features = ["json"] } +serde = { version = "=1.0.171", features = ["derive"] } +serde_json = { version = "1.0", features = [ + "arbitrary_precision", + "raw_value", +] } +starknet_api = "0.4.1" +cairo-lang-starknet = { workspace = true } +cairo-lang-utils = { workspace = true } +starknet = { workspace = true } +thiserror = { workspace = true } +flate2 = "1.0.25" +serde_with = "3.0.0" +dotenv = "0.15.0" +cairo-vm = "0.8.5" +blockifier = "0.2.0-rc0" diff --git a/rpc_state_reader_sn_api/src/lib.rs b/rpc_state_reader_sn_api/src/lib.rs new file mode 100644 index 000000000..b05492451 --- /dev/null +++ b/rpc_state_reader_sn_api/src/lib.rs @@ -0,0 +1,972 @@ +use blockifier::execution::contract_class::{ + ContractClass as BlockifierContractClass, ContractClassV0, ContractClassV0Inner, +}; +use cairo_lang_starknet::casm_contract_class::CasmContractClass; +use cairo_lang_starknet::contract_class::{ + ContractClass as SierraContractClass, ContractEntryPoints, +}; +use cairo_vm::types::program::Program; +use cairo_vm::vm::runners::cairo_runner::ExecutionResources as VmExecutionResources; +use core::fmt; +use dotenv::dotenv; +use serde::{Deserialize, Deserializer}; +use serde_json::json; +use starknet::core::types::ContractClass as SNContractClass; +use starknet_api::block::{BlockNumber, BlockTimestamp}; +use starknet_api::core::{ChainId, ClassHash, EntryPointSelector}; +use starknet_api::deprecated_contract_class::EntryPointOffset; +use starknet_api::hash::StarkFelt; +use starknet_api::transaction::{InvokeTransaction, Transaction, TransactionHash}; +use starknet_api::{core::ContractAddress, hash::StarkHash, state::StorageKey}; +use std::collections::HashMap; +use std::env; +use std::fmt::Display; +use std::sync::Arc; +use thiserror::Error; + +/// Starknet chains supported in Infura. +#[derive(Debug, Clone, Copy)] +pub enum RpcChain { + MainNet, + TestNet, + TestNet2, +} + +impl fmt::Display for RpcChain { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + RpcChain::MainNet => write!(f, "starknet-mainnet"), + RpcChain::TestNet => write!(f, "starknet-goerli"), + RpcChain::TestNet2 => write!(f, "starknet-goerli2"), + } + } +} + +/// A [StateReader] that holds all the data in memory. +/// +/// This implementation is uses HTTP requests to call the RPC endpoint, +/// using Infura. +/// In order to use it an Infura API key is necessary. +pub struct RpcState { + /// Enum with one of the supported Infura chains/ + chain: RpcChain, + /// Infura API key. + api_key: String, + /// Struct that holds information on the block where we are going to use to read the state. + block: BlockValue, +} + +#[derive(Debug, Error)] +enum RpcError { + #[error("RPC call failed with error: {0}")] + RpcCall(String), + #[error("Request failed with error: {0}")] + Request(String), +} + +/// Represents the tag of a block value. +#[derive(Copy, Clone)] +pub enum BlockTag { + Latest, + Pending, +} + +impl Display for BlockTag { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let string = match self { + BlockTag::Latest => "latest", + BlockTag::Pending => "pending", + }; + write!(f, "{}", string) + } +} + +/// [`BlockValue`] is an Enum that represent which block we are going to use to retrieve information. +#[allow(dead_code)] +#[derive(Copy, Clone)] +pub enum BlockValue { + /// String one of: ["latest", "pending"] + Tag(BlockTag), + /// Integer + Number(BlockNumber), + /// String with format: 0x{felt252} + Hash(StarkHash), +} + +impl From for BlockValue { + fn from(value: BlockTag) -> Self { + BlockValue::Tag(value) + } +} + +impl From for BlockValue { + fn from(value: BlockNumber) -> Self { + BlockValue::Number(value) + } +} + +impl From for BlockValue { + fn from(value: StarkHash) -> Self { + BlockValue::Hash(value) + } +} + +impl BlockValue { + fn to_value(self) -> Result { + serde_json::to_value(match self { + BlockValue::Tag(block_tag) => block_tag.to_string().into(), + BlockValue::Number(block_number) => json!({ "block_number": block_number }), + BlockValue::Hash(block_hash) => json!({ "block_hash": block_hash }), + }) + } +} + +pub struct RpcBlockInfo { + /// The sequence number of the last block created. + pub block_number: BlockNumber, + /// Timestamp of the beginning of the last block creation attempt. + pub block_timestamp: BlockTimestamp, + /// The sequencer address of this block. + pub sequencer_address: ContractAddress, +} + +#[derive(Deserialize)] +pub struct RpcResponse { + result: T, +} + +impl RpcState { + pub fn new(chain: RpcChain, block: BlockValue) -> Self { + if env::var("INFURA_API_KEY").is_err() { + dotenv().expect("Missing .env file"); + } + Self { + chain, + api_key: env::var("INFURA_API_KEY") + .expect("Missing API Key in environment: INFURA_API_KEY"), + block, + } + } + + fn rpc_call_result Deserialize<'a>>( + &self, + params: &serde_json::Value, + ) -> Result { + Ok(self.rpc_call::>(params)?.result) + } + + fn rpc_call Deserialize<'a>>( + &self, + params: &serde_json::Value, + ) -> Result { + Self::deserialize_call(self.rpc_call_no_deserialize(params)?.into_json().unwrap()) + } + + fn rpc_call_no_deserialize( + &self, + params: &serde_json::Value, + ) -> Result { + ureq::post(&format!( + "https://{}.infura.io/v3/{}", + self.chain, self.api_key + )) + .set("Content-Type", "application/json") + .set("accept", "application/json") + .send_json(params) + .map_err(|err| RpcError::Request(err.to_string())) + } + + fn deserialize_call Deserialize<'a>>( + response: serde_json::Value, + ) -> Result { + serde_json::from_value(response).map_err(|err| RpcError::RpcCall(err.to_string())) + } +} + +#[derive(Debug)] +pub struct TransactionTrace { + pub validate_invocation: RpcCallInfo, + pub function_invocation: RpcCallInfo, + pub fee_transfer_invocation: RpcCallInfo, + pub signature: Vec, +} + +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)] +pub struct RpcExecutionResources { + pub n_steps: usize, + pub n_memory_holes: usize, + pub builtin_instance_counter: HashMap, +} + +#[derive(Debug)] +pub struct RpcCallInfo { + pub execution_resources: VmExecutionResources, + pub retdata: Option>, + pub calldata: Option>, + pub internal_calls: Vec, +} + +#[allow(unused)] +#[derive(Debug, Deserialize)] +pub struct RpcTransactionReceipt { + #[serde(deserialize_with = "actual_fee_deser")] + actual_fee: u128, + block_hash: StarkHash, + block_number: u64, + execution_status: String, + #[serde(rename = "type")] + tx_type: String, +} + +fn actual_fee_deser<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let hex: String = Deserialize::deserialize(deserializer)?; + Ok(u128::from_str_radix(&hex[2..], 16).unwrap()) +} + +impl<'de> Deserialize<'de> for RpcCallInfo { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let value: serde_json::Value = Deserialize::deserialize(deserializer)?; + + // Parse execution_resources + let execution_resources_value = value["execution_resources"].clone(); + + let execution_resources = VmExecutionResources { + n_steps: serde_json::from_value(execution_resources_value["n_steps"].clone()) + .map_err(serde::de::Error::custom)?, + n_memory_holes: serde_json::from_value( + execution_resources_value["n_memory_holes"].clone(), + ) + .map_err(serde::de::Error::custom)?, + builtin_instance_counter: serde_json::from_value( + execution_resources_value["builtin_instance_counter"].clone(), + ) + .map_err(serde::de::Error::custom)?, + }; + + // Parse retdata + let retdata_value = value["result"].clone(); + let retdata = serde_json::from_value(retdata_value).unwrap(); + + // Parse calldata + let calldata_value = value["calldata"].clone(); + let calldata = serde_json::from_value(calldata_value).unwrap(); + + // Parse internal calls + let internal_calls_value = value["internal_calls"].clone(); + let mut internal_calls = vec![]; + + for call in internal_calls_value.as_array().unwrap() { + internal_calls + .push(serde_json::from_value(call.clone()).map_err(serde::de::Error::custom)?); + } + + Ok(RpcCallInfo { + execution_resources, + retdata, + calldata, + internal_calls, + }) + } +} + +impl<'de> Deserialize<'de> for TransactionTrace { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let value: serde_json::Value = Deserialize::deserialize(deserializer)?; + + let validate_invocation = value["validate_invocation"].clone(); + let function_invocation = value["function_invocation"].clone(); + let fee_transfer_invocation = value["fee_transfer_invocation"].clone(); + let signature_value = value["signature"].clone(); + + Ok(TransactionTrace { + validate_invocation: serde_json::from_value(validate_invocation) + .map_err(serde::de::Error::custom)?, + function_invocation: serde_json::from_value(function_invocation) + .map_err(serde::de::Error::custom)?, + fee_transfer_invocation: serde_json::from_value(fee_transfer_invocation) + .map_err(serde::de::Error::custom)?, + signature: serde_json::from_value(signature_value).map_err(serde::de::Error::custom)?, + }) + } +} + +impl RpcState { + /// Requests the transaction trace to the Feeder Gateway API. + /// It's useful for testing the transaction outputs like: + /// - execution resources + /// - actual fee + /// - events + /// - return data + pub fn get_transaction_trace(&self, hash: &TransactionHash) -> TransactionTrace { + let chain_name = self.get_chain_name(); + let response = ureq::get(&format!( + "https://{}.starknet.io/feeder_gateway/get_transaction_trace", + chain_name + )) + .query("transactionHash", &hash.0.to_string()) + .call() + .unwrap(); + + serde_json::from_str(&response.into_string().unwrap()).unwrap() + } + + /// Requests the given transaction to the Feeder Gateway API. + pub fn get_transaction(&self, hash: &TransactionHash) -> Transaction { + let params = ureq::json!({ + "jsonrpc": "2.0", + "method": "starknet_getTransactionByHash", + "params": [hash.to_string()], + "id": 1 + }); + let result = self.rpc_call::(¶ms).unwrap()["result"].clone(); + + match result["type"].as_str().unwrap() { + "INVOKE" => match result["version"].as_str().unwrap() { + "0x0" => Transaction::Invoke(InvokeTransaction::V0( + serde_json::from_value(result).unwrap(), + )), + "0x1" => Transaction::Invoke(InvokeTransaction::V1( + serde_json::from_value(result).unwrap(), + )), + _ => unimplemented!(), + }, + _ => unimplemented!(), + } + } + + pub fn get_chain_name(&self) -> ChainId { + ChainId(match self.chain { + RpcChain::MainNet => "alpha-mainnet".to_string(), + RpcChain::TestNet => "alpha4".to_string(), + RpcChain::TestNet2 => "alpha4-2".to_string(), + }) + } + + pub fn get_block_info(&self) -> RpcBlockInfo { + let get_block_info_params = ureq::json!({ + "jsonrpc": "2.0", + "method": "starknet_getBlockWithTxHashes", + "params": [self.block.to_value().unwrap()], + "id": 1 + }); + + let block_info: serde_json::Value = self.rpc_call(&get_block_info_params).unwrap(); + let sequencer_address: StarkFelt = + serde_json::from_value(block_info["result"]["sequencer_address"].clone()).unwrap(); + + RpcBlockInfo { + block_number: BlockNumber( + block_info["result"]["block_number"] + .to_string() + .parse::() + .unwrap(), + ), + block_timestamp: BlockTimestamp( + block_info["result"]["timestamp"] + .to_string() + .parse::() + .unwrap(), + ), + sequencer_address: ContractAddress(sequencer_address.try_into().unwrap()), + } + } + + pub fn get_contract_class( + &self, + class_hash: &starknet_api::core::ClassHash, + ) -> BlockifierContractClass { + let params = ureq::json!({ + "jsonrpc": "2.0", + "method": "starknet_getClass", + "params": [self.block.to_value().unwrap(), class_hash.0.to_string()], + "id": 1 + }); + + let response = self.rpc_call_result(¶ms).unwrap(); + + match response { + SNContractClass::Legacy(compressed_legacy_cc) => { + let as_str = utils::decode_reader(compressed_legacy_cc.program).unwrap(); + let program = Program::from_bytes(as_str.as_bytes(), None).unwrap(); + let entry_points_by_type = utils::map_entry_points_by_type_legacy( + compressed_legacy_cc.entry_points_by_type, + ); + let inner = Arc::new(ContractClassV0Inner { + program, + entry_points_by_type, + }); + BlockifierContractClass::V0(ContractClassV0(inner)) + } + SNContractClass::Sierra(flattened_sierra_cc) => { + let middle_sierra: utils::MiddleSierraContractClass = { + let v = serde_json::to_value(flattened_sierra_cc).unwrap(); + serde_json::from_value(v).unwrap() + }; + let sierra_cc = SierraContractClass { + sierra_program: middle_sierra.sierra_program, + contract_class_version: middle_sierra.contract_class_version, + entry_points_by_type: middle_sierra.entry_points_by_type, + sierra_program_debug_info: None, + abi: None, + }; + let casm_cc = CasmContractClass::from_contract_class(sierra_cc, false).unwrap(); + BlockifierContractClass::V1(casm_cc.try_into().unwrap()) + } + } + } + + pub fn get_class_hash_at(&self, contract_address: &ContractAddress) -> ClassHash { + let params = ureq::json!({ + "jsonrpc": "2.0", + "method": "starknet_getClassHashAt", + "params": [self.block.to_value().unwrap(), contract_address.0.key().clone().to_string()], + "id": 1 + }); + + let hash = self.rpc_call_result(¶ms).unwrap(); + + ClassHash(hash) + } + + pub fn get_nonce_at(&self, contract_address: &ContractAddress) -> StarkFelt { + let params = ureq::json!({ + "jsonrpc": "2.0", + "method": "starknet_getNonce", + "params": [self.block.to_value().unwrap(), contract_address.0.key().clone().to_string()], + "id": 1 + }); + + self.rpc_call_result(¶ms).unwrap() + } + + fn get_storage_at(&self, contract_address: &ContractAddress, key: &StorageKey) -> StarkFelt { + let contract_address = contract_address.0.key(); + let key = key.0.key(); + let params = ureq::json!({ + "jsonrpc": "2.0", + "method": "starknet_getStorageAt", + "params": [contract_address.to_string(), + key.to_string(), self.block.to_value().unwrap()], + "id": 1 + }); + + self.rpc_call_result(¶ms).unwrap() + } + + /// Requests the given transaction to the Feeder Gateway API. + pub fn get_transaction_receipt(&self, hash: &TransactionHash) -> RpcTransactionReceipt { + let params = ureq::json!({ + "jsonrpc": "2.0", + "method": "starknet_getTransactionReceipt", + "params": [hash.to_string()], + "id": 1 + }); + self.rpc_call_result(¶ms).unwrap() + } +} + +mod utils { + use std::io::{self, Read}; + + use cairo_lang_utils::bigint::BigUintAsHex; + use starknet::core::types::{LegacyContractEntryPoint, LegacyEntryPointsByType}; + use starknet_api::deprecated_contract_class::{EntryPoint, EntryPointType}; + + use super::*; + + #[derive(Debug, Deserialize)] + pub struct MiddleSierraContractClass { + pub sierra_program: Vec, + pub contract_class_version: String, + pub entry_points_by_type: ContractEntryPoints, + } + + pub(crate) fn map_entry_points_by_type_legacy( + entry_points_by_type: LegacyEntryPointsByType, + ) -> HashMap> { + let entry_types_to_points = HashMap::from([ + ( + EntryPointType::Constructor, + entry_points_by_type.constructor, + ), + (EntryPointType::External, entry_points_by_type.external), + (EntryPointType::L1Handler, entry_points_by_type.l1_handler), + ]); + + let to_contract_entry_point = |entrypoint: &LegacyContractEntryPoint| -> EntryPoint { + let felt: StarkFelt = StarkHash::new(entrypoint.selector.to_bytes_be()).unwrap(); + EntryPoint { + offset: EntryPointOffset(entrypoint.offset as usize), + selector: EntryPointSelector(felt), + } + }; + + let mut entry_points_by_type_map = HashMap::new(); + for (entry_point_type, entry_points) in entry_types_to_points.into_iter() { + let values = entry_points + .iter() + .map(to_contract_entry_point) + .collect::>(); + entry_points_by_type_map.insert(entry_point_type, values); + } + + entry_points_by_type_map + } + + // Uncompresses a Gz Encoded vector of bytes and returns a string or error + // Here &[u8] implements BufRead + pub(crate) fn decode_reader(bytes: Vec) -> io::Result { + use flate2::bufread; + let mut gz = bufread::GzDecoder::new(&bytes[..]); + let mut s = String::new(); + gz.read_to_string(&mut s)?; + Ok(s) + } +} + +#[cfg(test)] +mod tests { + use starknet_api::{ + core::{ClassHash, PatriciaKey}, + hash::StarkFelt, + stark_felt, + }; + + use super::*; + + /// A utility macro to create a [`PatriciaKey`] from a hex string / unsigned integer representation. + /// Imported from starknet_api + macro_rules! patricia_key { + ($s:expr) => { + PatriciaKey::try_from(StarkHash::try_from($s).unwrap()).unwrap() + }; + } + + /// A utility macro to create a [`ClassHash`] from a hex string / unsigned integer representation. + /// Imported from starknet_api + macro_rules! class_hash { + ($s:expr) => { + ClassHash(StarkHash::try_from($s).unwrap()) + }; + } + + /// A utility macro to create a [`ContractAddress`] from a hex string / unsigned integer + /// representation. + /// Imported from starknet_api + macro_rules! contract_address { + ($s:expr) => { + ContractAddress(patricia_key!($s)) + }; + } + + #[test] + fn test_get_contract_class_cairo1() { + let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + + let class_hash = + class_hash!("0298e56befa6d1446b86ed5b900a9ba51fd2faa683cd6f50e8f833c0fb847216"); + // This belongs to + // https://starkscan.co/class/0x0298e56befa6d1446b86ed5b900a9ba51fd2faa683cd6f50e8f833c0fb847216 + // which is cairo1.0 + + rpc_state.get_contract_class(&class_hash); + } + + #[test] + fn test_get_contract_class_cairo0() { + let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + + let class_hash = + class_hash!("025ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918"); + rpc_state.get_contract_class(&class_hash); + } + + #[test] + fn test_get_class_hash_at() { + let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + let address = + contract_address!("00b081f7ba1efc6fe98770b09a827ae373ef2baa6116b3d2a0bf5154136573a9"); + + assert_eq!( + rpc_state.get_class_hash_at(&address), + class_hash!("025ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918") + ); + } + + #[test] + fn test_get_nonce_at() { + let rpc_state = RpcState::new(RpcChain::TestNet, BlockTag::Latest.into()); + // Contract deployed by xqft which will not be used again, so nonce changes will not break + // this test. + let address = + contract_address!("07185f2a350edcc7ea072888edb4507247de23e710cbd56084c356d265626bea"); + assert_eq!(rpc_state.get_nonce_at(&address), stark_felt!("0x0")); + } + + #[test] + fn test_get_storage_at() { + let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + let address = + contract_address!("00b081f7ba1efc6fe98770b09a827ae373ef2baa6116b3d2a0bf5154136573a9"); + let key = StorageKey(patricia_key!(0u128)); + + assert_eq!(rpc_state.get_storage_at(&address, &key), stark_felt!("0x0")); + } + + #[test] + fn test_get_transaction() { + let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + let tx_hash = TransactionHash(stark_felt!( + "06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955" + )); + + rpc_state.get_transaction(&tx_hash); + } + + #[test] + fn test_get_block_info() { + let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + + rpc_state.get_block_info(); + } + + // Tested with the following query to the Feeder Gateway API: + // https://alpha4-2.starknet.io/feeder_gateway/get_transaction_trace?transactionHash=0x019feb888a2d53ffddb7a1750264640afab8e9c23119e648b5259f1b5e7d51bc + #[test] + fn test_get_transaction_trace() { + let rpc_state = RpcState::new(RpcChain::TestNet2, BlockTag::Latest.into()); + + let tx_hash = TransactionHash(stark_felt!( + "19feb888a2d53ffddb7a1750264640afab8e9c23119e648b5259f1b5e7d51bc" + )); + + let tx_trace = rpc_state.get_transaction_trace(&tx_hash); + + assert_eq!( + tx_trace.signature, + vec![ + stark_felt!("ffab1c47d8d5e5b76bdcc4af79e98205716c36b440f20244c69599a91ace58"), + stark_felt!("6aa48a0906c9c1f7381c1a040c043b649eeac1eea08f24a9d07813f6b1d05fe"), + ] + ); + + assert_eq!( + tx_trace.validate_invocation.calldata, + Some(vec![ + stark_felt!("1"), + stark_felt!("690c876e61beda61e994543af68038edac4e1cb1990ab06e52a2d27e56a1232"), + stark_felt!("1f24f689ced5802b706d7a2e28743fe45c7bfa37431c97b1c766e9622b65573"), + stark_felt!("0"), + stark_felt!("9"), + stark_felt!("9"), + stark_felt!("4"), + stark_felt!("4254432d55534443"), + stark_felt!("f02e7324ecbd65ce267"), + stark_felt!("5754492d55534443"), + stark_felt!("8e13050d06d8f514c"), + stark_felt!("4554482d55534443"), + stark_felt!("f0e4a142c3551c149d"), + stark_felt!("4a50592d55534443"), + stark_felt!("38bd34c31a0a5c"), + ]) + ); + assert_eq!(tx_trace.validate_invocation.retdata, Some(vec![])); + assert_eq!( + tx_trace.validate_invocation.execution_resources, + VmExecutionResources { + n_steps: 790, + n_memory_holes: 51, + builtin_instance_counter: HashMap::from([ + ("range_check_builtin".to_string(), 20), + ("ecdsa_builtin".to_string(), 1), + ("pedersen_builtin".to_string(), 2), + ]), + } + ); + assert_eq!(tx_trace.validate_invocation.internal_calls.len(), 1); + + assert_eq!( + tx_trace.function_invocation.calldata, + Some(vec![ + stark_felt!("1"), + stark_felt!("690c876e61beda61e994543af68038edac4e1cb1990ab06e52a2d27e56a1232"), + stark_felt!("1f24f689ced5802b706d7a2e28743fe45c7bfa37431c97b1c766e9622b65573"), + stark_felt!("0"), + stark_felt!("9"), + stark_felt!("9"), + stark_felt!("4"), + stark_felt!("4254432d55534443"), + stark_felt!("f02e7324ecbd65ce267"), + stark_felt!("5754492d55534443"), + stark_felt!("8e13050d06d8f514c"), + stark_felt!("4554482d55534443"), + stark_felt!("f0e4a142c3551c149d"), + stark_felt!("4a50592d55534443"), + stark_felt!("38bd34c31a0a5c"), + ]) + ); + assert_eq!( + tx_trace.function_invocation.retdata, + Some(vec![0u128.into()]) + ); + assert_eq!( + tx_trace.function_invocation.execution_resources, + VmExecutionResources { + n_steps: 2808, + n_memory_holes: 136, + builtin_instance_counter: HashMap::from([ + ("range_check_builtin".to_string(), 49), + ("pedersen_builtin".to_string(), 14), + ]), + } + ); + assert_eq!(tx_trace.function_invocation.internal_calls.len(), 1); + assert_eq!( + tx_trace.function_invocation.internal_calls[0] + .internal_calls + .len(), + 1 + ); + assert_eq!( + tx_trace.function_invocation.internal_calls[0].internal_calls[0] + .internal_calls + .len(), + 7 + ); + + assert_eq!( + tx_trace.fee_transfer_invocation.calldata, + Some(vec![ + stark_felt!("1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8"), + stark_felt!("2b0322a23ba4"), + stark_felt!("0"), + ]) + ); + assert_eq!( + tx_trace.fee_transfer_invocation.retdata, + Some(vec![1u128.into()]) + ); + assert_eq!( + tx_trace.fee_transfer_invocation.execution_resources, + VmExecutionResources { + n_steps: 586, + n_memory_holes: 42, + builtin_instance_counter: HashMap::from([ + ("range_check_builtin".to_string(), 21), + ("pedersen_builtin".to_string(), 4), + ]), + } + ); + assert_eq!(tx_trace.fee_transfer_invocation.internal_calls.len(), 1); + } + + #[test] + fn test_get_transaction_receipt() { + let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + let tx_hash = TransactionHash(stark_felt!( + "06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955" + )); + + rpc_state.get_transaction_receipt(&tx_hash); + } +} + +mod blockifier_transaction_tests { + use blockifier::{ + block_context::BlockContext, + execution::contract_class::ContractClass, + state::{ + cached_state::{CachedState, GlobalContractCache}, + state_api::{StateReader, StateResult}, + }, + transaction::{ + account_transaction::AccountTransaction, + objects::TransactionExecutionInfo, + transactions::{ExecutableTransaction, InvokeTransaction}, + }, + }; + use starknet_api::{ + contract_address, + core::{CompiledClassHash, Nonce, PatriciaKey}, + patricia_key, stark_felt, + transaction::TransactionHash, + }; + + use super::*; + + pub struct RpcStateReader(RpcState); + + impl StateReader for RpcStateReader { + fn get_storage_at( + &mut self, + contract_address: ContractAddress, + key: StorageKey, + ) -> StateResult { + Ok(self.0.get_storage_at(&contract_address, &key)) + } + + fn get_nonce_at(&mut self, contract_address: ContractAddress) -> StateResult { + Ok(Nonce(self.0.get_nonce_at(&contract_address))) + } + + fn get_class_hash_at( + &mut self, + contract_address: ContractAddress, + ) -> StateResult { + Ok(self.0.get_class_hash_at(&contract_address)) + } + + /// Returns the contract class of the given class hash. + fn get_compiled_contract_class( + &mut self, + class_hash: &ClassHash, + ) -> StateResult { + Ok(self.0.get_contract_class(class_hash)) + } + + /// Returns the compiled class hash of the given class hash. + fn get_compiled_class_hash( + &mut self, + class_hash: ClassHash, + ) -> StateResult { + Ok(CompiledClassHash( + self.0 + .get_class_hash_at(&ContractAddress(class_hash.0.try_into().unwrap())) + .0, + )) + } + } + + #[allow(unused)] + pub fn execute_tx( + tx_hash: &str, + network: RpcChain, + block_number: BlockNumber, + gas_price: u128, + ) -> ( + TransactionExecutionInfo, + TransactionTrace, + RpcTransactionReceipt, + ) { + let tx_hash = tx_hash.strip_prefix("0x").unwrap(); + + // Instantiate the RPC StateReader and the CachedState + let rpc_reader = RpcStateReader(RpcState::new(network, block_number.into())); + + // Get values for block context before giving ownership of the reader + let chain_id = rpc_reader.0.get_chain_name(); + let RpcBlockInfo { + block_number, + block_timestamp, + sequencer_address, + } = rpc_reader.0.get_block_info(); + + // Get transaction before giving ownership of the reader + let tx_hash = TransactionHash(stark_felt!(tx_hash)); + let sn_api_tx = rpc_reader.0.get_transaction(&tx_hash); + + let trace = rpc_reader.0.get_transaction_trace(&tx_hash); + let receipt = rpc_reader.0.get_transaction_receipt(&tx_hash); + + // Create state from RPC reader + let global_cache = GlobalContractCache::default(); + let mut state = CachedState::new(rpc_reader, global_cache); + + let fee_token_address = + contract_address!("049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"); + + const N_STEPS_FEE_WEIGHT: f64 = 0.01; + let vm_resource_fee_cost = Arc::new(HashMap::from([ + ("n_steps".to_string(), N_STEPS_FEE_WEIGHT), + ("output_builtin".to_string(), 0.0), + ("pedersen_builtin".to_string(), N_STEPS_FEE_WEIGHT * 32.0), + ("range_check_builtin".to_string(), N_STEPS_FEE_WEIGHT * 16.0), + ("ecdsa_builtin".to_string(), N_STEPS_FEE_WEIGHT * 2048.0), + ("bitwise_builtin".to_string(), N_STEPS_FEE_WEIGHT * 64.0), + ("ec_op_builtin".to_string(), N_STEPS_FEE_WEIGHT * 1024.0), + ("poseidon_builtin".to_string(), N_STEPS_FEE_WEIGHT * 32.0), + ( + "segment_arena_builtin".to_string(), + N_STEPS_FEE_WEIGHT * 10.0, + ), + ("keccak_builtin".to_string(), N_STEPS_FEE_WEIGHT * 2048.0), // 2**11 + ])); + + let block_context = BlockContext { + chain_id, + block_number, + block_timestamp, + sequencer_address, + fee_token_address, + vm_resource_fee_cost, + gas_price, + invoke_tx_max_n_steps: 1_000_000, + validate_max_n_steps: 1_000_000, + max_recursion_depth: 500, + }; + + // Map starknet_api transaction to blockifier's + let blockifier_tx = match sn_api_tx { + Transaction::Invoke(tx) => { + let invoke = InvokeTransaction { tx, tx_hash }; + AccountTransaction::Invoke(invoke) + } + _ => unimplemented!(), + }; + + ( + blockifier_tx + .execute(&mut state, &block_context, true, true) + .unwrap(), + trace, + receipt, + ) + } + + #[cfg(test)] + mod test { + use blockifier::execution::entry_point::CallInfo; + + use super::*; + + #[test] + #[ignore = "working on fixes"] + fn test_recent_tx() { + let (tx_info, trace, receipt) = execute_tx( + "0x05d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91", + RpcChain::MainNet, + BlockNumber(169928), + 17110275391107, + ); + + let TransactionExecutionInfo { + execute_call_info, + actual_fee, + .. + } = tx_info; + + let CallInfo { + vm_resources, + inner_calls, + .. + } = execute_call_info.unwrap(); + + assert_eq!(vm_resources, trace.function_invocation.execution_resources); + assert_eq!( + inner_calls.len(), + trace.function_invocation.internal_calls.len() + ); + + assert_eq!(actual_fee.0, receipt.actual_fee); + } + } +} From b740b92368ba067af8748746a262d71e20419247 Mon Sep 17 00:00:00 2001 From: Edgar Date: Wed, 30 Aug 2023 15:25:49 +0200 Subject: [PATCH 06/44] Deserialize transactions too on the block info for the Rpc Reader SN (#961) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * initial commit * add get_class_hash_at * Added get_nonce_at * Added get_storage_at * Remove comments * Added get block info * Fixed get_contract_class() * WIP fixing desearlization * WIP Fix * Finished fixing get_contract_class() * Uncommented tests, new get_contract_class * Remove file * WIP Fixing tests * Finish fixing simple tests * Fixed transaction trace and block info * Fix import * Refactor, fixes, added test * Fixed warnings, removed tests * deserialize all transactions in the block info too * docs * refactor into standalone fn * get gas from block via RPC SN (#963) * get gas automatically from block * cleanup * fix wrong gas * unintended change --------- Co-authored-by: juanbono Co-authored-by: Estéfano Bargas --- Cargo.toml | 2 +- rpc_state_reader_sn_api/src/lib.rs | 68 ++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e3110c53b..c4ef535b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ serde_json = { version = "1.0", features = [ ] } sha3 = "0.10.1" # TODO: Replace with sha3. We should look how to integrate it correctly to calculate sn_keccak -keccak = "0.1.3" +keccak = "0.1.3" starknet_api = { workspace = true } starknet-crypto = "0.5.1" thiserror = { workspace = true } diff --git a/rpc_state_reader_sn_api/src/lib.rs b/rpc_state_reader_sn_api/src/lib.rs index b05492451..ef1c81d4a 100644 --- a/rpc_state_reader_sn_api/src/lib.rs +++ b/rpc_state_reader_sn_api/src/lib.rs @@ -128,6 +128,8 @@ pub struct RpcBlockInfo { pub block_timestamp: BlockTimestamp, /// The sequencer address of this block. pub sequencer_address: ContractAddress, + /// The transactions of this block. + pub transactions: Vec, } #[derive(Deserialize)] @@ -299,6 +301,29 @@ impl<'de> Deserialize<'de> for TransactionTrace { } } +/// Freestanding deserialize method to avoid a new type. +fn deserialize_transaction_json(transaction: serde_json::Value) -> serde_json::Result { + let tx_type: String = serde_json::from_value(transaction["type"].clone())?; + let tx_version: String = serde_json::from_value(transaction["version"].clone())?; + + match tx_type.as_str() { + "INVOKE" => match tx_version.as_str() { + "0x0" => Ok(Transaction::Invoke(InvokeTransaction::V0( + serde_json::from_value(transaction)?, + ))), + "0x1" => Ok(Transaction::Invoke(InvokeTransaction::V1( + serde_json::from_value(transaction)?, + ))), + x => Err(serde::de::Error::custom(format!( + "unimplemented invoke version: {x}" + ))), + }, + x => Err(serde::de::Error::custom(format!( + "unimplemented transaction type deserialization: {x}" + ))), + } +} + impl RpcState { /// Requests the transaction trace to the Feeder Gateway API. /// It's useful for testing the transaction outputs like: @@ -343,6 +368,25 @@ impl RpcState { } } + /// Gets the gas price of a given block. + pub fn get_gas_price(&self, block_number: u64) -> serde_json::Result { + let chain_name = self.get_chain_name(); + + let response = ureq::get(&format!( + "https://{}.starknet.io/feeder_gateway/get_block", + chain_name + )) + .query("blockNumber", &block_number.to_string()) + .call() + .unwrap(); + + let res: serde_json::Value = response.into_json().expect("should be json"); + + let gas_price_hex = res["gas_price"].as_str().unwrap(); + let gas_price = u128::from_str_radix(gas_price_hex.trim_start_matches("0x"), 16).unwrap(); + Ok(gas_price) + } + pub fn get_chain_name(&self) -> ChainId { ChainId(match self.chain { RpcChain::MainNet => "alpha-mainnet".to_string(), @@ -354,7 +398,7 @@ impl RpcState { pub fn get_block_info(&self) -> RpcBlockInfo { let get_block_info_params = ureq::json!({ "jsonrpc": "2.0", - "method": "starknet_getBlockWithTxHashes", + "method": "starknet_getBlockWithTxs", "params": [self.block.to_value().unwrap()], "id": 1 }); @@ -363,6 +407,13 @@ impl RpcState { let sequencer_address: StarkFelt = serde_json::from_value(block_info["result"]["sequencer_address"].clone()).unwrap(); + let transactions: Vec<_> = block_info["result"]["transactions"] + .as_array() + .unwrap() + .iter() + .filter_map(|result| deserialize_transaction_json(result.clone()).ok()) + .collect(); + RpcBlockInfo { block_number: BlockNumber( block_info["result"]["block_number"] @@ -377,6 +428,7 @@ impl RpcState { .unwrap(), ), sequencer_address: ContractAddress(sequencer_address.try_into().unwrap()), + transactions, } } @@ -851,7 +903,6 @@ mod blockifier_transaction_tests { tx_hash: &str, network: RpcChain, block_number: BlockNumber, - gas_price: u128, ) -> ( TransactionExecutionInfo, TransactionTrace, @@ -861,6 +912,7 @@ mod blockifier_transaction_tests { // Instantiate the RPC StateReader and the CachedState let rpc_reader = RpcStateReader(RpcState::new(network, block_number.into())); + let gas_price = rpc_reader.0.get_gas_price(block_number.0).unwrap(); // Get values for block context before giving ownership of the reader let chain_id = rpc_reader.0.get_chain_name(); @@ -868,6 +920,7 @@ mod blockifier_transaction_tests { block_number, block_timestamp, sequencer_address, + .. } = rpc_reader.0.get_block_info(); // Get transaction before giving ownership of the reader @@ -939,13 +992,20 @@ mod blockifier_transaction_tests { use super::*; #[test] - #[ignore = "working on fixes"] + fn test_get_gas_price() { + let block = BlockValue::Number(BlockNumber(169928)); + let rpc_state = RpcState::new(RpcChain::MainNet, block); + + let price = rpc_state.get_gas_price(169928).unwrap(); + assert_eq!(price, 22804578690); + } + + #[test] fn test_recent_tx() { let (tx_info, trace, receipt) = execute_tx( "0x05d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91", RpcChain::MainNet, BlockNumber(169928), - 17110275391107, ); let TransactionExecutionInfo { From d6c7d915c92b56e1269c4d88300246418872f577 Mon Sep 17 00:00:00 2001 From: MrAzteca Date: Wed, 30 Aug 2023 16:58:46 +0200 Subject: [PATCH 07/44] Unify deprecated and casm contract caches. (#937) * Unify deprecated and casm contract caches. * Fix formatting and clippy. * Remove unused code. * Unify contract classes in the state traits too. * Restore type alias. --------- Co-authored-by: Esteve Soler Arderiu --- bench/internals.rs | 29 +- cli/src/main.rs | 12 +- fuzzer/src/main.rs | 13 +- rpc_state_reader/src/lib.rs | 4 +- src/bin/fibonacci.rs | 20 +- src/bin/invoke.rs | 20 +- src/bin/invoke_with_cachedstate.rs | 14 +- src/execution/execution_entry_point.rs | 7 +- src/lib.rs | 83 +++-- src/state/cached_state.rs | 193 +++--------- src/state/in_memory_state_reader.rs | 45 ++- src/state/mod.rs | 17 +- src/state/state_api.rs | 13 +- src/syscalls/deprecated_syscall_handler.rs | 33 +- src/syscalls/deprecated_syscall_response.rs | 4 +- src/testing/erc20.rs | 23 +- src/testing/mod.rs | 14 +- src/testing/state.rs | 32 +- src/transaction/declare.rs | 55 +++- src/transaction/declare_v2.rs | 17 +- src/transaction/deploy.rs | 31 +- src/transaction/deploy_account.rs | 28 +- src/transaction/fee.rs | 4 +- src/transaction/invoke_function.rs | 78 +++-- src/transaction/l1_handler.rs | 11 +- tests/cairo_1_syscalls.rs | 285 ++++++++++-------- tests/complex_contracts/amm_contracts/amm.rs | 54 +--- .../amm_contracts/amm_proxy.rs | 30 +- tests/complex_contracts/nft/erc721.rs | 84 +----- tests/complex_contracts/utils.rs | 14 +- tests/delegate_call.rs | 13 +- tests/delegate_l1_handler.rs | 13 +- tests/deploy_account.rs | 24 +- tests/fibonacci.rs | 12 +- tests/increase_balance.rs | 8 +- tests/internal_calls.rs | 8 +- tests/internals.rs | 138 ++++----- tests/multi_syscall_test.rs | 9 +- tests/storage.rs | 8 +- tests/syscalls.rs | 104 ++++--- tests/syscalls_errors.rs | 32 +- 41 files changed, 808 insertions(+), 828 deletions(-) diff --git a/bench/internals.rs b/bench/internals.rs index 075f216a2..430dc5446 100644 --- a/bench/internals.rs +++ b/bench/internals.rs @@ -11,13 +11,15 @@ use starknet_in_rust::{ constants::{TRANSACTION_VERSION, VALIDATE_ENTRY_POINT_SELECTOR}, }, hash_utils::calculate_contract_address, - services::api::contract_classes::deprecated_contract_class::ContractClass, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, state::in_memory_state_reader::InMemoryStateReader, state::{cached_state::CachedState, state_api::State}, transaction::{declare::Declare, Deploy, DeployAccount, InvokeFunction}, utils::Address, }; -use std::{hint::black_box, sync::Arc}; +use std::{collections::HashMap, hint::black_box, sync::Arc}; lazy_static! { // include_str! doesn't seem to work in CI @@ -61,10 +63,13 @@ fn deploy_account() { const RUNS: usize = 500; let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, Some(Default::default()), None); + let mut state = CachedState::new(state_reader, HashMap::new()); state - .set_contract_class(&CLASS_HASH_BYTES, &CONTRACT_CLASS) + .set_contract_class( + &CLASS_HASH_BYTES, + &CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), + ) .unwrap(); let block_context = &Default::default(); @@ -97,7 +102,7 @@ fn declare() { const RUNS: usize = 5; let state_reader = Arc::new(InMemoryStateReader::default()); - let state = CachedState::new(state_reader, Some(Default::default()), None); + let state = CachedState::new(state_reader, HashMap::new()); let block_context = &Default::default(); @@ -129,10 +134,13 @@ fn deploy() { const RUNS: usize = 8; let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, Some(Default::default()), None); + let mut state = CachedState::new(state_reader, HashMap::new()); state - .set_contract_class(&CLASS_HASH_BYTES, &CONTRACT_CLASS) + .set_contract_class( + &CLASS_HASH_BYTES, + &CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), + ) .unwrap(); let block_context = &Default::default(); @@ -164,10 +172,13 @@ fn invoke() { const RUNS: usize = 100; let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, Some(Default::default()), None); + let mut state = CachedState::new(state_reader, HashMap::new()); state - .set_contract_class(&CLASS_HASH_BYTES, &CONTRACT_CLASS) + .set_contract_class( + &CLASS_HASH_BYTES, + &CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), + ) .unwrap(); let block_context = &Default::default(); diff --git a/cli/src/main.rs b/cli/src/main.rs index f37bdf544..1248123dd 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -23,7 +23,9 @@ use starknet_in_rust::{ hash_utils::calculate_contract_address, parser_errors::ParserError, serde_structs::read_abi, - services::api::contract_classes::deprecated_contract_class::ContractClass, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, state::{cached_state::CachedState, state_api::State}, state::{in_memory_state_reader::InMemoryStateReader, ExecutionResourcesManager}, transaction::{error::TransactionError, InvokeFunction}, @@ -110,7 +112,10 @@ fn declare_parser( let contract_class = ContractClass::from_path(&args.contract).map_err(ContractAddressError::Program)?; let class_hash = compute_deprecated_class_hash(&contract_class)?; - cached_state.set_contract_class(&felt_to_hash(&class_hash), &contract_class)?; + cached_state.set_contract_class( + &felt_to_hash(&class_hash), + &CompiledClass::Deprecated(Arc::new(contract_class.clone())), + )?; let tx_hash = calculate_declare_transaction_hash( &contract_class, @@ -313,8 +318,7 @@ pub async fn start_devnet(port: u16) -> Result<(), std::io::Error> { let cached_state = web::Data::new(AppState { cached_state: Mutex::new(CachedState::::new( Arc::new(InMemoryStateReader::default()), - Some(HashMap::new()), - None, + HashMap::new(), )), }); diff --git a/fuzzer/src/main.rs b/fuzzer/src/main.rs index edbfb1cf5..2b14e11b4 100644 --- a/fuzzer/src/main.rs +++ b/fuzzer/src/main.rs @@ -25,6 +25,7 @@ use std::{ path::PathBuf, }; +use starknet_in_rust::services::api::contract_classes::compiled_class::CompiledClass; use std::fs; use std::process::Command; use std::thread; @@ -44,11 +45,11 @@ fn main() { let file_content1 = " %lang starknet from starkware.cairo.common.cairo_builtins import HashBuiltin - + @storage_var func _counter() -> (res: felt) { } - + @external func write_and_read{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (res:felt) { _counter.write('"; @@ -116,7 +117,10 @@ fn main() { let address = Address(1111.into()); let class_hash = [1; 32]; - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -126,8 +130,7 @@ fn main() { //* Create state with previous data //* --------------------------------------- - let mut state = - CachedState::new(Arc::new(state_reader), Some(contract_class_cache), None); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); //* ------------------------------------ //* Create execution entry point diff --git a/rpc_state_reader/src/lib.rs b/rpc_state_reader/src/lib.rs index 280f14aa0..254b26b00 100644 --- a/rpc_state_reader/src/lib.rs +++ b/rpc_state_reader/src/lib.rs @@ -741,7 +741,7 @@ mod transaction_tests { felt::felt_str, state::cached_state::CachedState, }; - use std::sync::Arc; + use std::{collections::HashMap, sync::Arc}; fn test_tx( tx_hash: &str, @@ -754,7 +754,7 @@ mod transaction_tests { // Instantiate the RPC StateReader and the CachedState let block = BlockValue::Number(serde_json::to_value(block_number).unwrap()); let rpc_state = Arc::new(RpcState::new(network, block)); - let mut state = CachedState::new(rpc_state.clone(), None, None); + let mut state = CachedState::new(rpc_state.clone(), HashMap::new()); let fee_token_address = Address(felt_str!( "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", diff --git a/src/bin/fibonacci.rs b/src/bin/fibonacci.rs index b14be188a..df61410cf 100644 --- a/src/bin/fibonacci.rs +++ b/src/bin/fibonacci.rs @@ -5,9 +5,13 @@ use num_traits::Zero; use lazy_static::lazy_static; use starknet_in_rust::{ - services::api::contract_classes::deprecated_contract_class::ContractClass, - state::cached_state::CachedState, state::in_memory_state_reader::InMemoryStateReader, - testing::state::StarknetState, utils::Address, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, + state::cached_state::CachedState, + state::in_memory_state_reader::InMemoryStateReader, + testing::state::StarknetState, + utils::Address, }; #[cfg(feature = "with_mimalloc")] @@ -78,17 +82,17 @@ fn create_initial_state() -> CachedState { state_reader .address_to_nonce_mut() .insert(CONTRACT_ADDRESS.clone(), Felt252::zero()); - state_reader - .class_hash_to_contract_class_mut() - .insert(*CONTRACT_CLASS_HASH, CONTRACT_CLASS.clone()); + state_reader.class_hash_to_compiled_class_mut().insert( + *CONTRACT_CLASS_HASH, + CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), + ); state_reader .address_to_storage_mut() .insert((CONTRACT_ADDRESS.clone(), [0; 32]), Felt252::zero()); Arc::new(state_reader) }, - Some(HashMap::new()), - None, + HashMap::new(), ); cached_state diff --git a/src/bin/invoke.rs b/src/bin/invoke.rs index afec929fa..f29a78ad0 100644 --- a/src/bin/invoke.rs +++ b/src/bin/invoke.rs @@ -4,9 +4,13 @@ use cairo_vm::felt::{felt_str, Felt252}; use num_traits::Zero; use starknet_in_rust::{ - services::api::contract_classes::deprecated_contract_class::ContractClass, - state::cached_state::CachedState, state::in_memory_state_reader::InMemoryStateReader, - testing::state::StarknetState, utils::Address, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, + state::cached_state::CachedState, + state::in_memory_state_reader::InMemoryStateReader, + testing::state::StarknetState, + utils::Address, }; use lazy_static::lazy_static; @@ -92,17 +96,17 @@ fn create_initial_state() -> CachedState { state_reader .address_to_nonce_mut() .insert(CONTRACT_ADDRESS.clone(), Felt252::zero()); - state_reader - .class_hash_to_contract_class_mut() - .insert(*CONTRACT_CLASS_HASH, CONTRACT_CLASS.clone()); + state_reader.class_hash_to_compiled_class_mut().insert( + *CONTRACT_CLASS_HASH, + CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), + ); state_reader .address_to_storage_mut() .insert((CONTRACT_ADDRESS.clone(), [0; 32]), Felt252::zero()); Arc::new(state_reader) }, - Some(HashMap::new()), - None, + HashMap::new(), ); cached_state diff --git a/src/bin/invoke_with_cachedstate.rs b/src/bin/invoke_with_cachedstate.rs index e5c7cac2f..4868a0ab4 100644 --- a/src/bin/invoke_with_cachedstate.rs +++ b/src/bin/invoke_with_cachedstate.rs @@ -8,7 +8,9 @@ use starknet_in_rust::{ block_context::{BlockContext, StarknetChainId, StarknetOsConfig}, constants::TRANSACTION_VERSION, }, - services::api::contract_classes::deprecated_contract_class::ContractClass, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, state::in_memory_state_reader::InMemoryStateReader, state::{cached_state::CachedState, BlockInfo}, transaction::InvokeFunction, @@ -99,17 +101,17 @@ fn create_initial_state() -> CachedState { state_reader .address_to_nonce_mut() .insert(CONTRACT_ADDRESS.clone(), Felt252::zero()); - state_reader - .class_hash_to_contract_class_mut() - .insert(*CONTRACT_CLASS_HASH, CONTRACT_CLASS.clone()); + state_reader.class_hash_to_compiled_class_mut().insert( + *CONTRACT_CLASS_HASH, + CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), + ); state_reader .address_to_storage_mut() .insert((CONTRACT_ADDRESS.clone(), [0; 32]), Felt252::zero()); Arc::new(state_reader) }, - Some(HashMap::new()), - None, + HashMap::new(), ); cached_state diff --git a/src/execution/execution_entry_point.rs b/src/execution/execution_entry_point.rs index 554463471..b16b500a9 100644 --- a/src/execution/execution_entry_point.rs +++ b/src/execution/execution_entry_point.rs @@ -128,11 +128,8 @@ impl ExecutionEntryPoint { }) } CompiledClass::Casm(contract_class) => { - let mut tmp_state = CachedState::new( - state.state_reader.clone(), - state.contract_classes.clone(), - state.casm_contract_classes.clone(), - ); + let mut tmp_state = + CachedState::new(state.state_reader.clone(), state.contract_classes.clone()); tmp_state.cache = state.cache.clone(); match self._execute( diff --git a/src/lib.rs b/src/lib.rs index 6dc8c24fa..1b9a441e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,7 +61,7 @@ pub fn simulate_transaction( ignore_max_fee: bool, skip_nonce_check: bool, ) -> Result, TransactionError> { - let mut cache_state = CachedState::new(Arc::new(state), None, Some(HashMap::new())); + let mut cache_state = CachedState::new(Arc::new(state), HashMap::new()); let mut result = Vec::with_capacity(transactions.len()); for transaction in transactions { let tx_for_simulation = transaction.create_for_simulation( @@ -89,7 +89,7 @@ where T: StateReader, { // This is used as a copy of the original state, we can update this cached state freely. - let mut cached_state = CachedState::::new(Arc::new(state), None, None); + let mut cached_state = CachedState::::new(Arc::new(state), HashMap::new()); let mut result = Vec::with_capacity(transactions.len()); for transaction in transactions { @@ -177,7 +177,7 @@ where T: StateReader, { // This is used as a copy of the original state, we can update this cached state freely. - let mut cached_state = CachedState::::new(Arc::new(state), None, None); + let mut cached_state = CachedState::::new(Arc::new(state), HashMap::new()); // Check if the contract is deployed. cached_state.get_class_hash_at(l1_handler.contract_address())?; @@ -251,6 +251,7 @@ mod test { utils::{Address, ClassHash}, }; + use crate::services::api::contract_classes::compiled_class::CompiledClass; use lazy_static::lazy_static; lazy_static! { @@ -317,7 +318,7 @@ mod test { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -326,7 +327,7 @@ mod test { .address_to_nonce_mut() .insert(address.clone(), nonce); - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); let calldata = [1.into(), 1.into(), 10.into()].to_vec(); let retdata = call_contract( @@ -378,10 +379,13 @@ mod test { .address_to_nonce .insert(contract_address, nonce); - let mut state = CachedState::new(Arc::new(state_reader), None, None); + let mut state = CachedState::new(Arc::new(state_reader), HashMap::new()); // Initialize state.contract_classes - let contract_classes = HashMap::from([(class_hash, contract_class)]); + let contract_classes = HashMap::from([( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + )]); state.set_contract_classes(contract_classes).unwrap(); let mut block_context = BlockContext::default(); @@ -407,7 +411,8 @@ mod test { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); + let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -416,7 +421,7 @@ mod test { .address_to_nonce_mut() .insert(address.clone(), nonce); - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); let calldata = [1.into(), 1.into(), 10.into()].to_vec(); let invoke = InvokeFunction::new( @@ -483,9 +488,10 @@ mod test { .insert(address.clone(), nonce); // simulate deploy - state_reader - .class_hash_to_contract_class_mut() - .insert(acc_class_hash, contract_class); + state_reader.class_hash_to_compiled_class_mut().insert( + acc_class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); let hash = felt_str!( "134328839377938040543570691566621575472567895629741043448357033688476792132" @@ -494,9 +500,10 @@ mod test { state_reader .class_hash_to_compiled_class_hash_mut() .insert(fib_address, class_hash); - state_reader - .casm_contract_classes - .insert(fib_address, casm_contract_class); + state_reader.class_hash_to_compiled_class.insert( + fib_address, + CompiledClass::Casm(Arc::new(casm_contract_class)), + ); let calldata = [ address.0.clone(), @@ -610,9 +617,10 @@ mod test { .insert(address.clone(), nonce); // simulate deploy - state_reader - .class_hash_to_contract_class_mut() - .insert(acc_class_hash, contract_class); + state_reader.class_hash_to_compiled_class_mut().insert( + acc_class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); let hash = felt_str!( "134328839377938040543570691566621575472567895629741043448357033688476792132" @@ -621,9 +629,10 @@ mod test { state_reader .class_hash_to_compiled_class_hash_mut() .insert(fib_address, class_hash); - state_reader - .casm_contract_classes - .insert(fib_address, casm_contract_class); + state_reader.class_hash_to_compiled_class.insert( + fib_address, + CompiledClass::Casm(Arc::new(casm_contract_class)), + ); let calldata = [ address.0.clone(), @@ -672,10 +681,13 @@ mod test { #[test] fn test_simulate_deploy() { let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, Some(Default::default()), None); + let mut state = CachedState::new(state_reader, HashMap::new()); state - .set_contract_class(&CLASS_HASH_BYTES, &CONTRACT_CLASS) + .set_contract_class( + &CLASS_HASH_BYTES, + &CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), + ) .unwrap(); let block_context = &Default::default(); @@ -711,7 +723,7 @@ mod test { #[test] fn test_simulate_declare() { let state_reader = Arc::new(InMemoryStateReader::default()); - let state = CachedState::new(state_reader, Some(Default::default()), None); + let state = CachedState::new(state_reader, HashMap::new()); let block_context = &Default::default(); @@ -748,10 +760,13 @@ mod test { #[test] fn test_simulate_invoke() { let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, Some(Default::default()), None); + let mut state = CachedState::new(state_reader, HashMap::new()); state - .set_contract_class(&CLASS_HASH_BYTES, &CONTRACT_CLASS) + .set_contract_class( + &CLASS_HASH_BYTES, + &CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), + ) .unwrap(); let block_context = Default::default(); @@ -809,10 +824,13 @@ mod test { #[test] fn test_simulate_deploy_account() { let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, Some(Default::default()), None); + let mut state = CachedState::new(state_reader, HashMap::new()); state - .set_contract_class(&CLASS_HASH_BYTES, &CONTRACT_CLASS) + .set_contract_class( + &CLASS_HASH_BYTES, + &CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), + ) .unwrap(); let block_context = &Default::default(); @@ -930,13 +948,16 @@ mod test { .address_to_nonce .insert(contract_address, nonce); - let mut state = CachedState::new(Arc::new(state_reader), None, None); + let mut state = CachedState::new(Arc::new(state_reader), HashMap::new()); // Initialize state.contract_classes state.set_contract_classes(HashMap::new()).unwrap(); state - .set_contract_class(&class_hash, &contract_class) + .set_contract_class( + &class_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) .unwrap(); let mut block_context = BlockContext::default(); @@ -959,7 +980,7 @@ mod test { #[test] fn test_deploy_and_invoke_simulation() { let state_reader = Arc::new(InMemoryStateReader::default()); - let state = CachedState::new(state_reader, Some(Default::default()), None); + let state = CachedState::new(state_reader, HashMap::new()); let block_context = &Default::default(); diff --git a/src/state/cached_state.rs b/src/state/cached_state.rs index 8b2298de8..f451d5e97 100644 --- a/src/state/cached_state.rs +++ b/src/state/cached_state.rs @@ -4,13 +4,10 @@ use super::{ }; use crate::{ core::errors::state_errors::StateError, - services::api::contract_classes::{ - compiled_class::CompiledClass, deprecated_contract_class::ContractClass, - }, + services::api::contract_classes::compiled_class::CompiledClass, state::StateDiff, utils::{subtract_mappings, to_cache_state_storage_mapping, Address, ClassHash}, }; -use cairo_lang_starknet::casm_contract_class::CasmContractClass; use cairo_vm::felt::Felt252; use getset::{Getters, MutGetters}; use num_traits::Zero; @@ -19,11 +16,9 @@ use std::{ sync::Arc, }; -// K: class_hash V: ContractClass -pub type ContractClassCache = HashMap; -pub type CasmClassCache = HashMap; +pub type ContractClassCache = HashMap; -pub const UNINITIALIZED_CLASS_HASH: &ClassHash = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; +pub const UNINITIALIZED_CLASS_HASH: &ClassHash = &[0u8; 32]; /// Represents a cached state of contract classes with optional caches. #[derive(Default, Clone, Debug, Eq, Getters, MutGetters, PartialEq)] @@ -32,38 +27,29 @@ pub struct CachedState { #[getset(get = "pub", get_mut = "pub")] pub(crate) cache: StateCache, #[get = "pub"] - pub(crate) contract_classes: Option, - #[get = "pub"] - pub(crate) casm_contract_classes: Option, + pub(crate) contract_classes: ContractClassCache, } impl CachedState { /// Constructor, creates a new cached state. - pub fn new( - state_reader: Arc, - contract_class_cache: Option, - casm_class_cache: Option, - ) -> Self { + pub fn new(state_reader: Arc, contract_classes: ContractClassCache) -> Self { Self { cache: StateCache::default(), - contract_classes: contract_class_cache, state_reader, - casm_contract_classes: casm_class_cache, + contract_classes, } } /// Creates a CachedState for testing purposes. pub fn new_for_testing( state_reader: Arc, - contract_classes: Option, cache: StateCache, - casm_contract_classes: Option, + contract_classes: ContractClassCache, ) -> Self { Self { cache, contract_classes, state_reader, - casm_contract_classes, } } @@ -72,20 +58,12 @@ impl CachedState { &mut self, contract_classes: ContractClassCache, ) -> Result<(), StateError> { - if self.contract_classes.is_some() { + if !self.contract_classes.is_empty() { return Err(StateError::AssignedContractClassCache); } - self.contract_classes = Some(contract_classes); + self.contract_classes = contract_classes; Ok(()) } - - /// Returns the casm classes. - #[allow(dead_code)] - pub(crate) fn get_casm_classes(&mut self) -> Result<&CasmClassCache, StateError> { - self.casm_contract_classes - .as_ref() - .ok_or(StateError::MissingCasmClassCache) - } } impl StateReader for CachedState { @@ -172,36 +150,21 @@ impl StateReader for CachedState { if class_hash == UNINITIALIZED_CLASS_HASH { return Err(StateError::UninitiaizedClassHash); } + // I: FETCHING FROM CACHE - // I: DEPRECATED CONTRACT CLASS - // deprecated contract classes dont have compiled class hashes, so we only have one case - if let Some(compiled_class) = self - .contract_classes - .as_ref() - .and_then(|x| x.get(class_hash)) - { - return Ok(CompiledClass::Deprecated(Arc::new(compiled_class.clone()))); - } - // I: CASM CONTRACT CLASS : COMPILED_CLASS_HASH - if let Some(compiled_class) = self - .casm_contract_classes - .as_ref() - .and_then(|x| x.get(class_hash)) - { - return Ok(CompiledClass::Casm(Arc::new(compiled_class.clone()))); + if let Some(compiled_class) = self.contract_classes.get(class_hash) { + return Ok(compiled_class.clone()); } + // I: CASM CONTRACT CLASS : CLASS_HASH if let Some(compiled_class_hash) = self.cache.class_hash_to_compiled_class_hash.get(class_hash) { - if let Some(casm_class) = &mut self - .casm_contract_classes - .as_ref() - .and_then(|m| m.get(compiled_class_hash)) - { - return Ok(CompiledClass::Casm(Arc::new(casm_class.clone()))); + if let Some(casm_class) = self.contract_classes.get(compiled_class_hash) { + return Ok(casm_class.clone()); } } + // II: FETCHING FROM STATE_READER self.state_reader.get_contract_class(class_hash) } @@ -212,17 +175,11 @@ impl State for CachedState { fn set_contract_class( &mut self, class_hash: &ClassHash, - contract_class: &ContractClass, + contract_class: &CompiledClass, ) -> Result<(), StateError> { - match self.contract_classes.as_mut() { - Some(x) => { - x.insert(*class_hash, contract_class.clone()); - } - None => { - self.contract_classes = Some(HashMap::new()); - self.set_contract_class(class_hash, contract_class)?; - } - } + self.contract_classes + .insert(*class_hash, contract_class.clone()); + Ok(()) } @@ -285,20 +242,6 @@ impl State for CachedState { Ok(()) } - fn set_compiled_class( - &mut self, - compiled_class_hash: &Felt252, - casm_class: CasmContractClass, - ) -> Result<(), StateError> { - let compiled_class_hash = compiled_class_hash.to_be_bytes(); - - self.casm_contract_classes - .as_mut() - .ok_or(StateError::MissingCasmClassCache)? - .insert(compiled_class_hash, casm_class); - Ok(()) - } - fn set_compiled_class_hash( &mut self, class_hash: &Felt252, @@ -437,48 +380,35 @@ impl State for CachedState { if class_hash == UNINITIALIZED_CLASS_HASH { return Err(StateError::UninitiaizedClassHash); } + // I: FETCHING FROM CACHE - // I: DEPRECATED CONTRACT CLASS // deprecated contract classes dont have compiled class hashes, so we only have one case - if let Some(compiled_class) = self - .contract_classes - .as_ref() - .and_then(|x| x.get(class_hash)) - { - return Ok(CompiledClass::Deprecated(Arc::new(compiled_class.clone()))); - } - // I: CASM CONTRACT CLASS : COMPILED_CLASS_HASH - if let Some(compiled_class) = self - .casm_contract_classes - .as_ref() - .and_then(|x| x.get(class_hash)) - { - return Ok(CompiledClass::Casm(Arc::new(compiled_class.clone()))); + if let Some(compiled_class) = self.contract_classes.get(class_hash) { + return Ok(compiled_class.clone()); } + // I: CASM CONTRACT CLASS : CLASS_HASH if let Some(compiled_class_hash) = self.cache.class_hash_to_compiled_class_hash.get(class_hash) { - if let Some(casm_class) = &mut self - .casm_contract_classes - .as_ref() - .and_then(|m| m.get(compiled_class_hash)) - { - return Ok(CompiledClass::Casm(Arc::new(casm_class.clone()))); + if let Some(casm_class) = self.contract_classes.get(compiled_class_hash) { + return Ok(casm_class.clone()); } } + // II: FETCHING FROM STATE_READER let contract = self.state_reader.get_contract_class(class_hash)?; match contract { - CompiledClass::Casm(ref class) => { + CompiledClass::Casm(ref casm_class) => { // We call this method instead of state_reader's in order to update the cache's class_hash_initial_values map let compiled_class_hash = self.get_compiled_class_hash(class_hash)?; - self.casm_contract_classes - .as_mut() - .and_then(|m| m.insert(compiled_class_hash, class.as_ref().clone())); + self.set_contract_class( + &compiled_class_hash, + &CompiledClass::Casm(casm_class.clone()), + )?; } CompiledClass::Deprecated(ref contract) => { - self.set_contract_class(class_hash, &contract.clone())? + self.set_contract_class(class_hash, &CompiledClass::Deprecated(contract.clone()))? } } Ok(contract) @@ -489,7 +419,10 @@ impl State for CachedState { mod tests { use super::*; - use crate::state::in_memory_state_reader::InMemoryStateReader; + use crate::{ + services::api::contract_classes::deprecated_contract_class::ContractClass, + state::in_memory_state_reader::InMemoryStateReader, + }; use num_traits::One; @@ -503,7 +436,6 @@ mod tests { HashMap::new(), HashMap::new(), HashMap::new(), - HashMap::new(), ); let contract_address = Address(4242.into()); @@ -522,7 +454,7 @@ mod tests { .address_to_storage_mut() .insert(storage_entry, storage_value); - let mut cached_state = CachedState::new(Arc::new(state_reader), None, None); + let mut cached_state = CachedState::new(Arc::new(state_reader), HashMap::new()); assert_eq!( cached_state.get_class_hash_at(&contract_address).unwrap(), @@ -545,20 +477,18 @@ mod tests { HashMap::new(), HashMap::new(), HashMap::new(), - HashMap::new(), ); let contract_class = ContractClass::from_path("starknet_programs/raw_contract_classes/class_with_abi.json") .unwrap(); state_reader - .class_hash_to_contract_class - .insert([1; 32], contract_class); + .class_hash_to_compiled_class + .insert([1; 32], CompiledClass::Deprecated(Arc::new(contract_class))); - let mut cached_state = CachedState::new(Arc::new(state_reader), None, None); + let mut cached_state = CachedState::new(Arc::new(state_reader), HashMap::new()); cached_state.set_contract_classes(HashMap::new()).unwrap(); - assert!(cached_state.contract_classes.is_some()); assert_eq!( cached_state.get_contract_class(&[1; 32]).unwrap(), @@ -573,7 +503,7 @@ mod tests { #[test] fn cached_state_storage_test() { let mut cached_state = - CachedState::new(Arc::new(InMemoryStateReader::default()), None, None); + CachedState::new(Arc::new(InMemoryStateReader::default()), HashMap::new()); let storage_entry: StorageEntry = (Address(31.into()), [0; 32]); let value = Felt252::new(10); @@ -595,7 +525,7 @@ mod tests { let contract_address = Address(32123.into()); - let mut cached_state = CachedState::new(state_reader, None, None); + let mut cached_state = CachedState::new(state_reader, HashMap::new()); assert!(cached_state .deploy_contract(contract_address, [10; 32]) @@ -611,7 +541,7 @@ mod tests { let storage_key = [18; 32]; let value = Felt252::new(912); - let mut cached_state = CachedState::new(state_reader, None, None); + let mut cached_state = CachedState::new(state_reader, HashMap::new()); // set storage_key cached_state.set_storage_at(&(contract_address.clone(), storage_key), value.clone()); @@ -629,27 +559,6 @@ mod tests { assert_eq!(new_result.unwrap(), new_value); } - /// This test ensures that an error is thrown when trying to set contract classes twice. - #[test] - fn set_contract_classes_twice_error_test() { - let state_reader = InMemoryStateReader::new( - HashMap::new(), - HashMap::new(), - HashMap::new(), - HashMap::new(), - HashMap::new(), - HashMap::new(), - ); - let mut cached_state = CachedState::new(Arc::new(state_reader), None, None); - - cached_state.set_contract_classes(HashMap::new()).unwrap(); - let result = cached_state - .set_contract_classes(HashMap::new()) - .unwrap_err(); - - assert_matches!(result, StateError::AssignedContractClassCache); - } - /// This test ensures that an error is thrown if a contract address is out of range. #[test] fn deploy_contract_address_out_of_range_error_test() { @@ -659,12 +568,11 @@ mod tests { HashMap::new(), HashMap::new(), HashMap::new(), - HashMap::new(), ); let contract_address = Address(0.into()); - let mut cached_state = CachedState::new(Arc::new(state_reader), None, None); + let mut cached_state = CachedState::new(Arc::new(state_reader), HashMap::new()); let result = cached_state .deploy_contract(contract_address.clone(), [10; 32]) @@ -685,12 +593,11 @@ mod tests { HashMap::new(), HashMap::new(), HashMap::new(), - HashMap::new(), ); let contract_address = Address(42.into()); - let mut cached_state = CachedState::new(Arc::new(state_reader), None, None); + let mut cached_state = CachedState::new(Arc::new(state_reader), HashMap::new()); cached_state .deploy_contract(contract_address.clone(), [10; 32]) @@ -714,12 +621,11 @@ mod tests { HashMap::new(), HashMap::new(), HashMap::new(), - HashMap::new(), ); let contract_address = Address(32123.into()); - let mut cached_state = CachedState::new(Arc::new(state_reader), None, None); + let mut cached_state = CachedState::new(Arc::new(state_reader), HashMap::new()); cached_state .deploy_contract(contract_address.clone(), [10; 32]) @@ -744,12 +650,11 @@ mod tests { HashMap::new(), HashMap::new(), HashMap::new(), - HashMap::new(), ); let address_one = Address(Felt252::one()); - let mut cached_state = CachedState::new(Arc::new(state_reader), None, None); + let mut cached_state = CachedState::new(Arc::new(state_reader), HashMap::new()); let state_diff = StateDiff { address_to_class_hash: HashMap::from([( @@ -784,7 +689,7 @@ mod tests { #[test] fn count_actual_storage_changes_test() { let state_reader = InMemoryStateReader::default(); - let mut cached_state = CachedState::new(Arc::new(state_reader), None, None); + let mut cached_state = CachedState::new(Arc::new(state_reader), HashMap::new()); let address_one = Address(1.into()); let address_two = Address(2.into()); diff --git a/src/state/in_memory_state_reader.rs b/src/state/in_memory_state_reader.rs index de9b3e827..7a7f1c372 100644 --- a/src/state/in_memory_state_reader.rs +++ b/src/state/in_memory_state_reader.rs @@ -1,19 +1,15 @@ use crate::{ core::errors::state_errors::StateError, - services::api::contract_classes::{ - compiled_class::CompiledClass, deprecated_contract_class::ContractClass, - }, + services::api::contract_classes::compiled_class::CompiledClass, state::{ - cached_state::{CasmClassCache, UNINITIALIZED_CLASS_HASH}, - state_api::StateReader, - state_cache::StorageEntry, + cached_state::UNINITIALIZED_CLASS_HASH, state_api::StateReader, state_cache::StorageEntry, }, utils::{Address, ClassHash, CompiledClassHash}, }; use cairo_vm::felt::Felt252; use getset::{Getters, MutGetters}; use num_traits::Zero; -use std::{collections::HashMap, sync::Arc}; +use std::collections::HashMap; /// A [StateReader] that holds all the data in memory. /// @@ -28,9 +24,7 @@ pub struct InMemoryStateReader { #[getset(get_mut = "pub")] pub address_to_storage: HashMap, #[getset(get_mut = "pub")] - pub class_hash_to_contract_class: HashMap, - #[getset(get_mut = "pub")] - pub(crate) casm_contract_classes: CasmClassCache, + pub class_hash_to_compiled_class: HashMap, #[getset(get_mut = "pub")] pub(crate) class_hash_to_compiled_class_hash: HashMap, } @@ -49,16 +43,14 @@ impl InMemoryStateReader { address_to_class_hash: HashMap, address_to_nonce: HashMap, address_to_storage: HashMap, - class_hash_to_contract_class: HashMap, - casm_contract_classes: CasmClassCache, + class_hash_to_compiled_class: HashMap, class_hash_to_compiled_class_hash: HashMap, ) -> Self { Self { address_to_class_hash, address_to_nonce, address_to_storage, - class_hash_to_contract_class, - casm_contract_classes, + class_hash_to_compiled_class, class_hash_to_compiled_class_hash, } } @@ -79,13 +71,10 @@ impl InMemoryStateReader { &self, compiled_class_hash: &CompiledClassHash, ) -> Result { - if let Some(compiled_class) = self.casm_contract_classes.get(compiled_class_hash) { - return Ok(CompiledClass::Casm(Arc::new(compiled_class.clone()))); + match self.class_hash_to_compiled_class.get(compiled_class_hash) { + Some(compiled_class) => Ok(compiled_class.clone()), + None => Err(StateError::NoneCompiledClass(*compiled_class_hash)), } - if let Some(compiled_class) = self.class_hash_to_contract_class.get(compiled_class_hash) { - return Ok(CompiledClass::Deprecated(Arc::new(compiled_class.clone()))); - } - Err(StateError::NoneCompiledClass(*compiled_class_hash)) } } @@ -127,9 +116,10 @@ impl StateReader for InMemoryStateReader { fn get_contract_class(&self, class_hash: &ClassHash) -> Result { // Deprecated contract classes dont have a compiled_class_hash, we dont need to fetch it - if let Some(compiled_class) = self.class_hash_to_contract_class.get(class_hash) { - return Ok(CompiledClass::Deprecated(Arc::new(compiled_class.clone()))); + if let Some(compiled_class) = self.class_hash_to_compiled_class.get(class_hash) { + return Ok(compiled_class.clone()); } + let compiled_class_hash = self.get_compiled_class_hash(class_hash)?; if compiled_class_hash != *UNINITIALIZED_CLASS_HASH { let compiled_class = self.get_compiled_class(&compiled_class_hash)?; @@ -143,6 +133,8 @@ impl StateReader for InMemoryStateReader { #[cfg(test)] mod tests { use super::*; + use crate::services::api::contract_classes::deprecated_contract_class::ContractClass; + use std::sync::Arc; #[test] fn get_contract_state_test() { @@ -152,7 +144,6 @@ mod tests { HashMap::new(), HashMap::new(), HashMap::new(), - HashMap::new(), ); let contract_address = Address(37810.into()); @@ -190,7 +181,6 @@ mod tests { HashMap::new(), HashMap::new(), HashMap::new(), - HashMap::new(), ); let contract_class_key = [0; 32]; @@ -198,9 +188,10 @@ mod tests { ContractClass::from_path("starknet_programs/raw_contract_classes/class_with_abi.json") .unwrap(); - state_reader - .class_hash_to_contract_class - .insert([0; 32], contract_class.clone()); + state_reader.class_hash_to_compiled_class.insert( + [0; 32], + CompiledClass::Deprecated(Arc::new(contract_class.clone())), + ); assert_eq!( state_reader .get_contract_class(&contract_class_key) diff --git a/src/state/mod.rs b/src/state/mod.rs index 8b6ace0cc..3920165a8 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -166,7 +166,7 @@ impl StateDiff { where T: StateReader + Clone, { - let mut cache_state = CachedState::new(state_reader, None, None); + let mut cache_state = CachedState::new(state_reader, HashMap::new()); let cache_storage_mapping = to_cache_state_storage_mapping(&self.storage_updates); cache_state.cache_mut().set_initial_values( @@ -240,7 +240,7 @@ mod test { use crate::{ state::in_memory_state_reader::InMemoryStateReader, state::{ - cached_state::{CachedState, ContractClassCache}, + cached_state::CachedState, state_api::StateReader, state_cache::{StateCache, StorageEntry}, }, @@ -263,7 +263,7 @@ mod test { .address_to_nonce .insert(contract_address, nonce); - let cached_state = CachedState::new(Arc::new(state_reader), None, None); + let cached_state = CachedState::new(Arc::new(state_reader), HashMap::new()); let diff = StateDiff::from_cached_state(cached_state).unwrap(); @@ -323,7 +323,8 @@ mod test { .address_to_nonce .insert(contract_address.clone(), nonce); - let cached_state_original = CachedState::new(Arc::new(state_reader.clone()), None, None); + let cached_state_original = + CachedState::new(Arc::new(state_reader.clone()), HashMap::new()); let diff = StateDiff::from_cached_state(cached_state_original.clone()).unwrap(); @@ -370,12 +371,8 @@ mod test { storage_writes, HashMap::new(), ); - let cached_state = CachedState::new_for_testing( - Arc::new(state_reader), - Some(ContractClassCache::new()), - cache, - None, - ); + let cached_state = + CachedState::new_for_testing(Arc::new(state_reader), cache, HashMap::new()); let mut diff = StateDiff::from_cached_state(cached_state).unwrap(); diff --git a/src/state/state_api.rs b/src/state/state_api.rs index 27ffa8599..885eee4be 100644 --- a/src/state/state_api.rs +++ b/src/state/state_api.rs @@ -1,13 +1,10 @@ use super::state_cache::StorageEntry; use crate::{ core::errors::state_errors::StateError, - services::api::contract_classes::{ - compiled_class::CompiledClass, deprecated_contract_class::ContractClass, - }, + services::api::contract_classes::compiled_class::CompiledClass, state::StateDiff, utils::{Address, ClassHash, CompiledClassHash}, }; -use cairo_lang_starknet::casm_contract_class::CasmContractClass; use cairo_vm::felt::Felt252; pub trait StateReader { @@ -30,7 +27,7 @@ pub trait State { fn set_contract_class( &mut self, class_hash: &ClassHash, - contract_class: &ContractClass, + contract_class: &CompiledClass, ) -> Result<(), StateError>; fn deploy_contract( @@ -49,12 +46,6 @@ pub trait State { class_hash: ClassHash, ) -> Result<(), StateError>; - fn set_compiled_class( - &mut self, - compiled_class_hash: &Felt252, - casm_class: CasmContractClass, - ) -> Result<(), StateError>; - fn set_compiled_class_hash( &mut self, class_hash: &Felt252, diff --git a/src/syscalls/deprecated_syscall_handler.rs b/src/syscalls/deprecated_syscall_handler.rs index d131d5ff1..7ee047b76 100644 --- a/src/syscalls/deprecated_syscall_handler.rs +++ b/src/syscalls/deprecated_syscall_handler.rs @@ -227,6 +227,7 @@ mod tests { use std::sync::Arc; use super::*; + use crate::services::api::contract_classes::compiled_class::CompiledClass; use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; use crate::{ add_segments, allocate_selector, any_box, @@ -730,7 +731,7 @@ mod tests { ] ); - let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), None, None); + let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), HashMap::new()); let mut hint_processor = SyscallHintProcessor::new( DeprecatedBLSyscallHandler::default_with(&mut state), RunResources::default(), @@ -766,7 +767,7 @@ mod tests { let hint_data = HintProcessorData::new_default(GET_CONTRACT_ADDRESS.to_string(), ids_data); // invoke syscall - let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), None, None); + let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), HashMap::new()); let mut hint_processor = SyscallHintProcessor::new( DeprecatedBLSyscallHandler::default_with(&mut state), RunResources::default(), @@ -808,7 +809,7 @@ mod tests { let hint_data = HintProcessorData::new_default(GET_TX_SIGNATURE.to_string(), ids_data); // invoke syscall - let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), None, None); + let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), HashMap::new()); let mut syscall_handler_hint_processor = SyscallHintProcessor::new( DeprecatedBLSyscallHandler::default_with(&mut state), RunResources::default(), @@ -847,7 +848,7 @@ mod tests { ); } - /// Tests the correct behavior of a storage read operation within a blockchain. + /// Tests the correct behavior of a storage read operation within a blockchain. #[test] fn test_bl_storage_read_hint_ok() { let mut vm = vm!(); @@ -876,7 +877,7 @@ mod tests { let hint_data = HintProcessorData::new_default(STORAGE_READ.to_string(), ids_data); - let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), None, None); + let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), HashMap::new()); let mut syscall_handler_hint_processor = SyscallHintProcessor::new( DeprecatedBLSyscallHandler::default_with(&mut state), RunResources::default(), @@ -911,7 +912,7 @@ mod tests { assert_matches!(get_big_int(&vm, relocatable!(2, 2)), Ok(response) if response == storage_value ); } - /// Tests the correct behavior of a storage write operation within a blockchain. + /// Tests the correct behavior of a storage write operation within a blockchain. #[test] fn test_bl_storage_write_hint_ok() { let mut vm = vm!(); @@ -941,7 +942,7 @@ mod tests { let hint_data = HintProcessorData::new_default(STORAGE_WRITE.to_string(), ids_data); - let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), None, None); + let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), HashMap::new()); let mut syscall_handler_hint_processor = SyscallHintProcessor::new( DeprecatedBLSyscallHandler::default_with(&mut state), RunResources::default(), @@ -980,7 +981,7 @@ mod tests { assert_eq!(write, Felt252::new(45)); } - /// Tests the correct behavior of a deploy operation within a blockchain. + /// Tests the correct behavior of a deploy operation within a blockchain. #[test] fn test_bl_deploy_ok() { let mut vm = vm!(); @@ -1015,7 +1016,7 @@ mod tests { let hint_data = HintProcessorData::new_default(DEPLOY.to_string(), ids_data); // Create SyscallHintProcessor - let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), None, None); + let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), HashMap::new()); let mut syscall_handler_hint_processor = SyscallHintProcessor::new( DeprecatedBLSyscallHandler::default_with(&mut state), RunResources::default(), @@ -1034,7 +1035,10 @@ mod tests { .syscall_handler .starknet_storage_state .state - .set_contract_class(&class_hash, &contract_class) + .set_contract_class( + &class_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) .unwrap(); // Execute Deploy hint @@ -1071,7 +1075,7 @@ mod tests { ); } - /// Tests the correct behavior of a storage deploy and invoke operations within a blockchain. + /// Tests the correct behavior of a storage deploy and invoke operations within a blockchain. #[test] fn test_deploy_and_invoke() { /* @@ -1113,7 +1117,7 @@ mod tests { ); // Create SyscallHintProcessor - let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), None, None); + let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), HashMap::new()); let mut syscall_handler_hint_processor = SyscallHintProcessor::new( DeprecatedBLSyscallHandler::default_with(&mut state), RunResources::default(), @@ -1133,7 +1137,10 @@ mod tests { .syscall_handler .starknet_storage_state .state - .set_contract_class(&class_hash, &contract_class) + .set_contract_class( + &class_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) .unwrap(); // Execute Deploy hint diff --git a/src/syscalls/deprecated_syscall_response.rs b/src/syscalls/deprecated_syscall_response.rs index 85e3e9cc1..bc7d3523f 100644 --- a/src/syscalls/deprecated_syscall_response.rs +++ b/src/syscalls/deprecated_syscall_response.rs @@ -309,7 +309,7 @@ impl DeprecatedWriteSyscallResponse for DeprecatedStorageReadResponse { #[cfg(test)] mod tests { - use std::sync::Arc; + use std::{collections::HashMap, sync::Arc}; use super::*; use crate::{ @@ -330,7 +330,7 @@ mod tests { #[test] fn write_get_caller_address_response() { // Initialize a VM and syscall handler - let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), None, None); + let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), HashMap::new()); let syscall = DeprecatedBLSyscallHandler::default_with(&mut state); let mut vm = vm!(); diff --git a/src/testing/erc20.rs b/src/testing/erc20.rs index eab540352..97dbf7cb8 100644 --- a/src/testing/erc20.rs +++ b/src/testing/erc20.rs @@ -10,7 +10,9 @@ use crate::{ execution::{ execution_entry_point::ExecutionEntryPoint, CallType, TransactionExecutionContext, }, - services::api::contract_classes::deprecated_contract_class::ContractClass, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, state::{ cached_state::CachedState, in_memory_state_reader::InMemoryStateReader, @@ -58,8 +60,11 @@ fn test_erc20_cairo2() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); - contract_class_cache.insert(erc20_class_hash, test_contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); + contract_class_cache.insert( + erc20_class_hash, + CompiledClass::Casm(Arc::new(test_contract_class)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader @@ -70,7 +75,7 @@ fn test_erc20_cairo2() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); let name_ = Felt252::from_bytes_be(b"some-token"); let symbol_ = Felt252::from_bytes_be(b"my-super-awesome-token"); @@ -137,7 +142,10 @@ fn test_erc20_cairo2() { serde_json::from_slice(program_data_account).unwrap(); state - .set_compiled_class(&felt_str!("1"), contract_class_account) + .set_contract_class( + &felt_str!("1").to_be_bytes(), + &CompiledClass::Casm(Arc::new(contract_class_account)), + ) .unwrap(); let contract_address_salt = @@ -176,7 +184,10 @@ fn test_erc20_cairo2() { serde_json::from_slice(program_data_account).unwrap(); state - .set_compiled_class(&felt_str!("1"), contract_class_account) + .set_contract_class( + &felt_str!("1").to_be_bytes(), + &CompiledClass::Casm(Arc::new(contract_class_account)), + ) .unwrap(); let contract_address_salt = felt_str!("123123123123123"); diff --git a/src/testing/mod.rs b/src/testing/mod.rs index 7772aae10..018082643 100644 --- a/src/testing/mod.rs +++ b/src/testing/mod.rs @@ -14,7 +14,9 @@ use crate::{ block_context::{BlockContext, StarknetChainId, StarknetOsConfig}, constants::DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS, }, - services::api::contract_classes::deprecated_contract_class::ContractClass, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, state::{ cached_state::CachedState, in_memory_state_reader::InMemoryStateReader, state_cache::StorageEntry, BlockInfo, @@ -149,14 +151,14 @@ pub fn create_account_tx_test_state( state_reader.address_to_storage_mut().extend(stored); } for (class_hash, contract_class) in class_hash_to_class { - state_reader - .class_hash_to_contract_class_mut() - .insert(class_hash, contract_class); + state_reader.class_hash_to_compiled_class_mut().insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); } Arc::new(state_reader) }, - Some(HashMap::new()), - Some(HashMap::new()), + HashMap::new(), ); Ok((block_context, cached_state)) diff --git a/src/testing/state.rs b/src/testing/state.rs index 28c1ef84a..8158786ce 100644 --- a/src/testing/state.rs +++ b/src/testing/state.rs @@ -1,5 +1,6 @@ use super::{state_error::StarknetStateError, type_utils::ExecutionInfo}; use crate::execution::execution_entry_point::ExecutionResult; +use crate::services::api::contract_classes::compiled_class::CompiledClass; use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; use crate::{ definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, @@ -40,7 +41,7 @@ impl StarknetState { let block_context = context.unwrap_or_default(); let state_reader = Arc::new(InMemoryStateReader::default()); - let state = CachedState::new(state_reader, Some(HashMap::new()), Some(HashMap::new())); + let state = CachedState::new(state_reader, HashMap::new()); let l2_to_l1_messages = HashMap::new(); let l2_to_l1_messages_log = Vec::new(); @@ -201,8 +202,10 @@ impl StarknetState { let contract_hash = deploy.contract_hash; let mut tx = Transaction::Deploy(deploy); - self.state - .set_contract_class(&contract_hash, &contract_class)?; + self.state.set_contract_class( + &contract_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + )?; let tx_execution_info = self.execute_tx(&mut tx, remaining_gas)?; Ok((contract_address, tx_execution_info)) @@ -330,6 +333,7 @@ mod tests { }, execution::{CallType, OrderedL2ToL1Message}, hash_utils::calculate_contract_address, + services::api::contract_classes::compiled_class::CompiledClass, state::state_cache::StorageEntry, utils::{calculate_sn_keccak, felt_to_hash}, }; @@ -399,11 +403,10 @@ mod tests { starknet_state .state .contract_classes - .unwrap() .get(&class_hash) .unwrap() .to_owned(), - contract_class + CompiledClass::Deprecated(Arc::new(contract_class)) ); } @@ -419,7 +422,10 @@ mod tests { // hack store account contract let hash = compute_deprecated_class_hash(&contract_class).unwrap(); let class_hash = felt_to_hash(&hash); - contract_class_cache.insert(class_hash, contract_class.clone()); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class.clone())), + ); // store sender_address let sender_address = Address(1.into()); @@ -440,11 +446,12 @@ mod tests { state_reader .address_to_storage_mut() .insert(storage_entry.clone(), storage.clone()); - state_reader - .class_hash_to_contract_class_mut() - .insert(class_hash, contract_class.clone()); + state_reader.class_hash_to_compiled_class_mut().insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class.clone())), + ); - let state = CachedState::new(Arc::new(state_reader), Some(contract_class_cache), None); + let state = CachedState::new(Arc::new(state_reader), contract_class_cache); //* -------------------------------------------- //* Create starknet state with previous data @@ -468,7 +475,10 @@ mod tests { starknet_state .state - .set_contract_class(&class_hash, &contract_class) + .set_contract_class( + &class_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) .unwrap(); // -------------------------------------------- diff --git a/src/transaction/declare.rs b/src/transaction/declare.rs index abb20c0b7..ce93bc4b1 100644 --- a/src/transaction/declare.rs +++ b/src/transaction/declare.rs @@ -29,6 +29,8 @@ use num_traits::Zero; use super::fee::charge_fee; use super::{verify_version, Transaction}; +use crate::services::api::contract_classes::compiled_class::CompiledClass; +use std::sync::Arc; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /// Represents an internal transaction in the StarkNet network that is a declaration of a Cairo @@ -281,7 +283,10 @@ impl Declare { self.skip_fee_transfer, )?; - state.set_contract_class(&self.class_hash, &self.contract_class)?; + state.set_contract_class( + &self.class_hash, + &CompiledClass::Deprecated(Arc::new(self.contract_class.clone())), + )?; tx_exec_info.set_fee_info(actual_fee, fee_transfer_info); @@ -332,7 +337,9 @@ mod tests { transaction_type::TransactionType, }, execution::CallType, - services::api::contract_classes::deprecated_contract_class::ContractClass, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, state::cached_state::CachedState, state::in_memory_state_reader::InMemoryStateReader, utils::{felt_to_hash, Address}, @@ -353,7 +360,10 @@ mod tests { let hash = compute_deprecated_class_hash(&contract_class).unwrap(); let class_hash = hash.to_be_bytes(); - contract_class_cache.insert(class_hash, contract_class.clone()); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class.clone())), + ); // store sender_address let sender_address = Address(1.into()); @@ -369,7 +379,7 @@ mod tests { .address_to_nonce_mut() .insert(sender_address, Felt252::new(1)); - let mut state = CachedState::new(Arc::new(state_reader), Some(contract_class_cache), None); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); //* --------------------------------------- //* Test declare with previous data @@ -510,7 +520,10 @@ mod tests { let hash = compute_deprecated_class_hash(&contract_class).unwrap(); let class_hash = felt_to_hash(&hash); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); // store sender_address let sender_address = Address(1.into()); @@ -526,7 +539,7 @@ mod tests { .address_to_nonce_mut() .insert(sender_address, Felt252::new(1)); - let _state = CachedState::new(Arc::new(state_reader), Some(contract_class_cache), None); + let _state = CachedState::new(Arc::new(state_reader), contract_class_cache); //* --------------------------------------- //* Test declare with previous data @@ -573,7 +586,10 @@ mod tests { let hash = compute_deprecated_class_hash(&contract_class).unwrap(); let class_hash = felt_to_hash(&hash); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); // store sender_address let sender_address = Address(1.into()); @@ -589,7 +605,7 @@ mod tests { .address_to_nonce_mut() .insert(sender_address, Felt252::new(1)); - let _state = CachedState::new(Arc::new(state_reader), Some(contract_class_cache), None); + let _state = CachedState::new(Arc::new(state_reader), contract_class_cache); //* --------------------------------------- //* Test declare with previous data @@ -635,7 +651,10 @@ mod tests { let hash = compute_deprecated_class_hash(&contract_class).unwrap(); let class_hash = felt_to_hash(&hash); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); // store sender_address let sender_address = Address(1.into()); @@ -651,7 +670,7 @@ mod tests { .address_to_nonce_mut() .insert(sender_address, Felt252::zero()); - let mut state = CachedState::new(Arc::new(state_reader), Some(contract_class_cache), None); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); //* --------------------------------------- //* Test declare with previous data @@ -711,7 +730,10 @@ mod tests { let hash = compute_deprecated_class_hash(&contract_class).unwrap(); let class_hash = felt_to_hash(&hash); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); // store sender_address let sender_address = Address(1.into()); @@ -727,7 +749,7 @@ mod tests { .address_to_nonce_mut() .insert(sender_address, Felt252::zero()); - let mut state = CachedState::new(Arc::new(state_reader), Some(contract_class_cache), None); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); //* --------------------------------------- //* Test declare with previous data @@ -774,7 +796,7 @@ mod tests { let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, Some(contract_class_cache), None); + let mut state = CachedState::new(state_reader, contract_class_cache); // There are no account contracts in the state, so the transaction should fail let fib_contract_class = @@ -815,7 +837,10 @@ mod tests { let hash = compute_deprecated_class_hash(&contract_class).unwrap(); let class_hash = felt_to_hash(&hash); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); // store sender_address let sender_address = Address(1.into()); @@ -831,7 +856,7 @@ mod tests { .address_to_nonce_mut() .insert(sender_address, Felt252::zero()); - let mut state = CachedState::new(Arc::new(state_reader), Some(contract_class_cache), None); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); //* --------------------------------------- //* Test declare with previous data diff --git a/src/transaction/declare_v2.rs b/src/transaction/declare_v2.rs index 0b80174c5..577c0738b 100644 --- a/src/transaction/declare_v2.rs +++ b/src/transaction/declare_v2.rs @@ -5,6 +5,7 @@ use crate::definitions::constants::QUERY_VERSION_BASE; use crate::execution::execution_entry_point::ExecutionResult; use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; +use crate::services::api::contract_classes::compiled_class::CompiledClass; use crate::state::cached_state::CachedState; use crate::{ core::transaction_hash::calculate_declare_v2_transaction_hash, @@ -26,6 +27,7 @@ use cairo_lang_starknet::casm_contract_class::CasmContractClass; use cairo_lang_starknet::contract_class::ContractClass as SierraContractClass; use cairo_vm::felt::Felt252; use num_traits::Zero; +use std::sync::Arc; /// Represents a declare transaction in the starknet network. /// Declare creates a blueprint of a contract class that is used to deploy instances of the contract @@ -372,7 +374,10 @@ impl DeclareV2 { )); } state.set_compiled_class_hash(&self.sierra_class_hash, &self.compiled_class_hash)?; - state.set_compiled_class(&self.compiled_class_hash, casm_class)?; + state.set_contract_class( + &self.compiled_class_hash.to_be_bytes(), + &CompiledClass::Casm(Arc::new(casm_class)), + )?; Ok(()) } @@ -510,7 +515,7 @@ mod tests { // crate state to store casm contract class let casm_contract_class_cache = HashMap::new(); let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, None, Some(casm_contract_class_cache)); + let mut state = CachedState::new(state_reader, casm_contract_class_cache); // call compile and store assert!(internal_declare @@ -579,7 +584,7 @@ mod tests { // crate state to store casm contract class let casm_contract_class_cache = HashMap::new(); let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, None, Some(casm_contract_class_cache)); + let mut state = CachedState::new(state_reader, casm_contract_class_cache); // call compile and store assert!(internal_declare @@ -650,7 +655,7 @@ mod tests { // crate state to store casm contract class let casm_contract_class_cache = HashMap::new(); let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, None, Some(casm_contract_class_cache)); + let mut state = CachedState::new(state_reader, casm_contract_class_cache); // call compile and store assert!(internal_declare @@ -719,7 +724,7 @@ mod tests { // crate state to store casm contract class let casm_contract_class_cache = HashMap::new(); let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, None, Some(casm_contract_class_cache)); + let mut state = CachedState::new(state_reader, casm_contract_class_cache); // call compile and store assert!(internal_declare @@ -789,7 +794,7 @@ mod tests { // crate state to store casm contract class let casm_contract_class_cache = HashMap::new(); let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, None, Some(casm_contract_class_cache)); + let mut state = CachedState::new(state_reader, casm_contract_class_cache); let expected_err = format!( "Invalid compiled class, expected class hash: {}, but received: {}", diff --git a/src/transaction/deploy.rs b/src/transaction/deploy.rs index 23606ca65..b65e8559e 100644 --- a/src/transaction/deploy.rs +++ b/src/transaction/deploy.rs @@ -151,18 +151,7 @@ impl Deploy { state: &mut CachedState, block_context: &BlockContext, ) -> Result { - match self.contract_class.clone() { - CompiledClass::Casm(contract_class) => { - state.set_compiled_class( - &Felt252::from_bytes_be(&self.contract_hash), - contract_class.as_ref().clone(), - )?; - } - CompiledClass::Deprecated(contract_class) => { - state.set_contract_class(&self.contract_hash, &contract_class)?; - } - } - + state.set_contract_class(&self.contract_hash, &self.contract_class)?; state.deploy_contract(self.contract_address.clone(), self.contract_hash)?; if self.constructor_entry_points_empty(self.contract_class.clone())? { @@ -172,10 +161,10 @@ impl Deploy { self.invoke_constructor(state, block_context) } } + /// Executes the contract without constructor /// ## Parameters /// - state: A state that implements the [`State`] and [`StateReader`] traits. - pub fn handle_empty_constructor( &self, state: &mut S, @@ -328,7 +317,7 @@ mod tests { fn invoke_constructor_test() { // Instantiate CachedState let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, Some(Default::default()), None); + let mut state = CachedState::new(state_reader, HashMap::new()); // Set contract_class let contract_class = @@ -376,7 +365,7 @@ mod tests { fn invoke_constructor_no_calldata_should_fail() { // Instantiate CachedState let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, Some(Default::default()), None); + let mut state = CachedState::new(state_reader, HashMap::new()); let contract_class = ContractClass::from_path("starknet_programs/constructor.json").unwrap(); @@ -386,7 +375,10 @@ mod tests { let class_hash_bytes = class_hash.to_be_bytes(); state - .set_contract_class(&class_hash_bytes, &contract_class) + .set_contract_class( + &class_hash_bytes, + &CompiledClass::Deprecated(Arc::new(contract_class.clone())), + ) .unwrap(); let internal_deploy = @@ -402,7 +394,7 @@ mod tests { fn deploy_contract_without_constructor_should_fail() { // Instantiate CachedState let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, Some(Default::default()), None); + let mut state = CachedState::new(state_reader, HashMap::new()); let contract_path = "starknet_programs/amm.json"; let contract_class = ContractClass::from_path(contract_path).unwrap(); @@ -413,7 +405,10 @@ mod tests { class_hash_bytes.copy_from_slice(&class_hash.to_bytes_be()); state - .set_contract_class(&class_hash_bytes, &contract_class) + .set_contract_class( + &class_hash_bytes, + &CompiledClass::Deprecated(Arc::new(contract_class.clone())), + ) .unwrap(); let internal_deploy = Deploy::new( diff --git a/src/transaction/deploy_account.rs b/src/transaction/deploy_account.rs index 2833004e1..eccb34117 100644 --- a/src/transaction/deploy_account.rs +++ b/src/transaction/deploy_account.rs @@ -385,7 +385,7 @@ impl DeployAccount { #[cfg(test)] mod tests { - use std::{path::PathBuf, sync::Arc}; + use std::{collections::HashMap, path::PathBuf, sync::Arc}; use super::*; use crate::{ @@ -406,11 +406,7 @@ mod tests { let class_hash = felt_to_hash(&hash); let block_context = BlockContext::default(); - let mut _state = CachedState::new( - Arc::new(InMemoryStateReader::default()), - Some(Default::default()), - None, - ); + let mut _state = CachedState::new(Arc::new(InMemoryStateReader::default()), HashMap::new()); let internal_deploy = DeployAccount::new( class_hash, @@ -442,11 +438,7 @@ mod tests { let class_hash = felt_to_hash(&hash); let block_context = BlockContext::default(); - let mut state = CachedState::new( - Arc::new(InMemoryStateReader::default()), - Some(Default::default()), - None, - ); + let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), HashMap::new()); let internal_deploy = DeployAccount::new( class_hash, @@ -473,7 +465,9 @@ mod tests { .unwrap(); let class_hash = internal_deploy.class_hash(); - state.set_contract_class(class_hash, &contract).unwrap(); + state + .set_contract_class(class_hash, &CompiledClass::Deprecated(Arc::new(contract))) + .unwrap(); internal_deploy.execute(&mut state, &block_context).unwrap(); assert_matches!( internal_deploy_error @@ -494,11 +488,7 @@ mod tests { let class_hash = felt_to_hash(&hash); let block_context = BlockContext::default(); - let mut state = CachedState::new( - Arc::new(InMemoryStateReader::default()), - Some(Default::default()), - None, - ); + let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), HashMap::new()); let internal_deploy = DeployAccount::new( class_hash, @@ -513,7 +503,9 @@ mod tests { .unwrap(); let class_hash = internal_deploy.class_hash(); - state.set_contract_class(class_hash, &contract).unwrap(); + state + .set_contract_class(class_hash, &CompiledClass::Deprecated(Arc::new(contract))) + .unwrap(); internal_deploy.execute(&mut state, &block_context).unwrap(); } } diff --git a/src/transaction/fee.rs b/src/transaction/fee.rs index 12d9ec686..818c62a54 100644 --- a/src/transaction/fee.rs +++ b/src/transaction/fee.rs @@ -196,7 +196,7 @@ mod tests { #[test] fn test_charge_fee_v0_actual_fee_exceeds_max_fee_should_return_error() { - let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), None, None); + let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), HashMap::new()); let mut tx_execution_context = TransactionExecutionContext::default(); let mut block_context = BlockContext::default(); block_context.starknet_os_config.gas_price = 1; @@ -222,7 +222,7 @@ mod tests { #[test] fn test_charge_fee_v1_actual_fee_exceeds_max_fee_should_return_error() { - let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), None, None); + let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), HashMap::new()); let mut tx_execution_context = TransactionExecutionContext { version: 1.into(), ..Default::default() diff --git a/src/transaction/invoke_function.rs b/src/transaction/invoke_function.rs index f4ec8a579..ef707f510 100644 --- a/src/transaction/invoke_function.rs +++ b/src/transaction/invoke_function.rs @@ -401,8 +401,11 @@ pub(crate) fn preprocess_invoke_function_fields( mod tests { use super::*; use crate::{ - services::api::contract_classes::deprecated_contract_class::ContractClass, - state::cached_state::CachedState, state::in_memory_state_reader::InMemoryStateReader, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, + state::cached_state::CachedState, + state::in_memory_state_reader::InMemoryStateReader, utils::calculate_sn_keccak, }; use cairo_lang_starknet::casm_contract_class::CasmContractClass; @@ -449,13 +452,16 @@ mod tests { .address_to_nonce .insert(contract_address, nonce); - let mut state = CachedState::new(Arc::new(state_reader), None, None); + let mut state = CachedState::new(Arc::new(state_reader), HashMap::new()); // Initialize state.contract_classes state.set_contract_classes(HashMap::new()).unwrap(); state - .set_contract_class(&class_hash, &contract_class) + .set_contract_class( + &class_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) .unwrap(); let result = internal_invoke_function @@ -518,13 +524,16 @@ mod tests { .address_to_nonce .insert(contract_address, nonce); - let mut state = CachedState::new(Arc::new(state_reader), None, None); + let mut state = CachedState::new(Arc::new(state_reader), HashMap::new()); // Initialize state.contract_classes state.set_contract_classes(HashMap::new()).unwrap(); state - .set_contract_class(&class_hash, &contract_class) + .set_contract_class( + &class_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) .unwrap(); let result = internal_invoke_function @@ -583,13 +592,16 @@ mod tests { .address_to_nonce .insert(contract_address, nonce); - let mut state = CachedState::new(Arc::new(state_reader), None, None); + let mut state = CachedState::new(Arc::new(state_reader), HashMap::new()); // Initialize state.contract_classes state.set_contract_classes(HashMap::new()).unwrap(); state - .set_contract_class(&class_hash, &contract_class) + .set_contract_class( + &class_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) .unwrap(); let expected_error = @@ -642,13 +654,16 @@ mod tests { .address_to_nonce .insert(contract_address, nonce); - let mut state = CachedState::new(Arc::new(state_reader), None, None); + let mut state = CachedState::new(Arc::new(state_reader), HashMap::new()); // Initialize state.contract_classes state.set_contract_classes(HashMap::new()).unwrap(); state - .set_contract_class(&class_hash, &contract_class) + .set_contract_class( + &class_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) .unwrap(); let result = internal_invoke_function @@ -707,13 +722,16 @@ mod tests { .address_to_nonce .insert(contract_address, nonce); - let mut state = CachedState::new(Arc::new(state_reader), None, None); + let mut state = CachedState::new(Arc::new(state_reader), HashMap::new()); // Initialize state.contract_classes state.set_contract_classes(HashMap::new()).unwrap(); state - .set_contract_class(&class_hash, &contract_class) + .set_contract_class( + &class_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) .unwrap(); let expected_error = @@ -766,13 +784,16 @@ mod tests { skip_nonce_check: false, }; - let mut state = CachedState::new(Arc::new(state_reader), None, None); + let mut state = CachedState::new(Arc::new(state_reader), HashMap::new()); // Initialize state.contract_classes state.set_contract_classes(HashMap::new()).unwrap(); state - .set_contract_class(&class_hash, &contract_class) + .set_contract_class( + &class_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) .unwrap(); let block_context = BlockContext::default(); @@ -823,13 +844,16 @@ mod tests { .address_to_nonce .insert(contract_address, nonce); - let mut state = CachedState::new(Arc::new(state_reader), None, None); + let mut state = CachedState::new(Arc::new(state_reader), HashMap::new()); // Initialize state.contract_classes state.set_contract_classes(HashMap::new()).unwrap(); state - .set_contract_class(&class_hash, &contract_class) + .set_contract_class( + &class_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) .unwrap(); let mut block_context = BlockContext::default(); @@ -881,13 +905,16 @@ mod tests { .address_to_nonce .insert(contract_address, nonce); - let mut state = CachedState::new(Arc::new(state_reader), None, None); + let mut state = CachedState::new(Arc::new(state_reader), HashMap::new()); // Initialize state.contract_classes state.set_contract_classes(HashMap::new()).unwrap(); state - .set_contract_class(&class_hash, &contract_class) + .set_contract_class( + &class_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) .unwrap(); internal_invoke_function @@ -944,13 +971,16 @@ mod tests { .address_to_nonce .insert(contract_address, nonce); - let mut state = CachedState::new(Arc::new(state_reader), None, None); + let mut state = CachedState::new(Arc::new(state_reader), HashMap::new()); // Initialize state.contract_classes state.set_contract_classes(HashMap::new()).unwrap(); state - .set_contract_class(&class_hash, &contract_class) + .set_contract_class( + &class_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) .unwrap(); let expected_error = @@ -1087,13 +1117,9 @@ mod tests { let mut casm_contract_class_cache = HashMap::new(); - casm_contract_class_cache.insert(class_hash, contract_class); + casm_contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); - let mut state = CachedState::new( - Arc::new(state_reader), - None, - Some(casm_contract_class_cache), - ); + let mut state = CachedState::new(Arc::new(state_reader), casm_contract_class_cache); let state_before_execution = state.clone(); diff --git a/src/transaction/l1_handler.rs b/src/transaction/l1_handler.rs index 9b479a340..4f84c910d 100644 --- a/src/transaction/l1_handler.rs +++ b/src/transaction/l1_handler.rs @@ -211,7 +211,9 @@ mod test { sync::Arc, }; - use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; + use crate::services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::EntryPointType, + }; use cairo_vm::{ felt::{felt_str, Felt252}, vm::runners::cairo_runner::ExecutionResources, @@ -266,13 +268,16 @@ mod test { .address_to_nonce .insert(contract_address, nonce); - let mut state = CachedState::new(Arc::new(state_reader), None, None); + let mut state = CachedState::new(Arc::new(state_reader), HashMap::new()); // Initialize state.contract_classes state.set_contract_classes(HashMap::new()).unwrap(); state - .set_contract_class(&class_hash, &contract_class) + .set_contract_class( + &class_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) .unwrap(); let mut block_context = BlockContext::default(); diff --git a/tests/cairo_1_syscalls.rs b/tests/cairo_1_syscalls.rs index 1f32b20e6..9e7cc02a3 100644 --- a/tests/cairo_1_syscalls.rs +++ b/tests/cairo_1_syscalls.rs @@ -65,7 +65,7 @@ fn storage_write_read() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -75,7 +75,7 @@ fn storage_write_read() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); let block_context = BlockContext::default(); let mut tx_execution_context = TransactionExecutionContext::new( @@ -204,7 +204,7 @@ fn library_call() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -226,7 +226,10 @@ fn library_call() { let lib_class_hash: ClassHash = [2; 32]; let lib_nonce = Felt252::zero(); - contract_class_cache.insert(lib_class_hash, lib_contract_class); + contract_class_cache.insert( + lib_class_hash, + CompiledClass::Casm(Arc::new(lib_contract_class)), + ); state_reader .address_to_class_hash_mut() .insert(lib_address.clone(), lib_class_hash); @@ -235,7 +238,7 @@ fn library_call() { .insert(lib_address, lib_nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // Create an execution entry point let calldata = [25.into(), Felt252::from_bytes_be(&lib_class_hash)].to_vec(); @@ -361,7 +364,7 @@ fn call_contract_storage_write_read() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -392,7 +395,10 @@ fn call_contract_storage_write_read() { let simple_wallet_class_hash: ClassHash = [2; 32]; let simple_wallet_nonce = Felt252::zero(); - contract_class_cache.insert(simple_wallet_class_hash, simple_wallet_contract_class); + contract_class_cache.insert( + simple_wallet_class_hash, + CompiledClass::Casm(Arc::new(simple_wallet_contract_class)), + ); state_reader .address_to_class_hash_mut() .insert(simple_wallet_address.clone(), simple_wallet_class_hash); @@ -401,7 +407,7 @@ fn call_contract_storage_write_read() { .insert(simple_wallet_address.clone(), simple_wallet_nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); let block_context = BlockContext::default(); let mut tx_execution_context = TransactionExecutionContext::new( @@ -547,7 +553,7 @@ fn emit_event() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -557,7 +563,7 @@ fn emit_event() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // Create an execution entry point let calldata = [].to_vec(); @@ -659,8 +665,11 @@ fn deploy_cairo1_from_cairo1() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); - contract_class_cache.insert(test_class_hash, test_contract_class.clone()); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); + contract_class_cache.insert( + test_class_hash, + CompiledClass::Casm(Arc::new(test_contract_class.clone())), + ); let mut state_reader = InMemoryStateReader::default(); state_reader @@ -671,7 +680,7 @@ fn deploy_cairo1_from_cairo1() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // arguments of deploy contract let calldata: Vec<_> = [test_felt_hash, salt].to_vec(); @@ -750,15 +759,17 @@ fn deploy_cairo0_from_cairo1_without_constructor() { let entrypoint_selector = &entrypoints.external.get(0).unwrap().selector; // Create state reader with class hash data - let mut casm_contract_class_cache = HashMap::new(); let mut contract_class_cache = HashMap::new(); let address = Address(1111.into()); let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - casm_contract_class_cache.insert(class_hash, contract_class); - contract_class_cache.insert(test_class_hash, test_contract_class.clone()); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); + contract_class_cache.insert( + test_class_hash, + CompiledClass::Deprecated(Arc::new(test_contract_class.clone())), + ); let mut state_reader = InMemoryStateReader::default(); state_reader @@ -769,11 +780,7 @@ fn deploy_cairo0_from_cairo1_without_constructor() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new( - Arc::new(state_reader), - Some(contract_class_cache), - Some(casm_contract_class_cache), - ); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // arguments of deploy contract let calldata: Vec<_> = [test_felt_hash, salt].to_vec(); @@ -850,7 +857,6 @@ fn deploy_cairo0_from_cairo1_with_constructor() { let entrypoint_selector = &entrypoints.external.get(0).unwrap().selector; // Create state reader with class hash data - let mut casm_contract_class_cache = HashMap::new(); let mut contract_class_cache = HashMap::new(); let address = Address(1111.into()); @@ -858,8 +864,11 @@ fn deploy_cairo0_from_cairo1_with_constructor() { let nonce = Felt252::zero(); // simulate contract declare - casm_contract_class_cache.insert(class_hash, contract_class); - contract_class_cache.insert(test_class_hash, test_contract_class.clone()); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); + contract_class_cache.insert( + test_class_hash, + CompiledClass::Deprecated(Arc::new(test_contract_class.clone())), + ); let mut state_reader = InMemoryStateReader::default(); state_reader @@ -870,11 +879,7 @@ fn deploy_cairo0_from_cairo1_with_constructor() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new( - Arc::new(state_reader), - Some(contract_class_cache), - Some(casm_contract_class_cache), - ); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // arguments of deploy contract let calldata: Vec<_> = [test_felt_hash, salt, address.0.clone(), Felt252::zero()].to_vec(); @@ -953,15 +958,17 @@ fn deploy_cairo0_and_invoke() { let entrypoint_selector = &entrypoints.external.get(0).unwrap().selector; // Create state reader with class hash data - let mut casm_contract_class_cache = HashMap::new(); let mut contract_class_cache = HashMap::new(); let address = Address(1111.into()); let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - casm_contract_class_cache.insert(class_hash, contract_class); - contract_class_cache.insert(test_class_hash, test_contract_class.clone()); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); + contract_class_cache.insert( + test_class_hash, + CompiledClass::Deprecated(Arc::new(test_contract_class.clone())), + ); let mut state_reader = InMemoryStateReader::default(); state_reader @@ -972,11 +979,7 @@ fn deploy_cairo0_and_invoke() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state: CachedState<_> = CachedState::new( - Arc::new(state_reader), - Some(contract_class_cache), - Some(casm_contract_class_cache), - ); + let mut state: CachedState<_> = CachedState::new(Arc::new(state_reader), contract_class_cache); // arguments of deploy contract let calldata: Vec<_> = [test_felt_hash, salt].to_vec(); @@ -1085,7 +1088,7 @@ fn test_send_message_to_l1_syscall() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader @@ -1096,7 +1099,7 @@ fn test_send_message_to_l1_syscall() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // RUN SEND_MSG // Create an execution entry point @@ -1179,7 +1182,7 @@ fn test_get_execution_info() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -1189,7 +1192,7 @@ fn test_get_execution_info() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); let block_context = BlockContext::default(); let mut tx_execution_context = TransactionExecutionContext::new( @@ -1274,7 +1277,10 @@ fn replace_class_internal() { let class_hash_a: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash_a, contract_class_a); + contract_class_cache.insert( + class_hash_a, + CompiledClass::Casm(Arc::new(contract_class_a)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -1292,10 +1298,13 @@ fn replace_class_internal() { let class_hash_b: ClassHash = [2; 32]; - contract_class_cache.insert(class_hash_b, contract_class_b.clone()); + contract_class_cache.insert( + class_hash_b, + CompiledClass::Casm(Arc::new(contract_class_b.clone())), + ); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // Run upgrade entrypoint and check that the storage was updated with the new contract class // Create an execution entry point @@ -1370,7 +1379,10 @@ fn replace_class_contract_call() { let class_hash_a: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash_a, contract_class_a); + contract_class_cache.insert( + class_hash_a, + CompiledClass::Casm(Arc::new(contract_class_a)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -1391,7 +1403,10 @@ fn replace_class_contract_call() { let class_hash_b: ClassHash = [2; 32]; - contract_class_cache.insert(class_hash_b, contract_class_b); + contract_class_cache.insert( + class_hash_b, + CompiledClass::Casm(Arc::new(contract_class_b)), + ); // SET GET_NUMBER_WRAPPER @@ -1408,7 +1423,10 @@ fn replace_class_contract_call() { let wrapper_address = Address(Felt252::from(2)); let wrapper_class_hash: ClassHash = [3; 32]; - contract_class_cache.insert(wrapper_class_hash, wrapper_contract_class); + contract_class_cache.insert( + wrapper_class_hash, + CompiledClass::Casm(Arc::new(wrapper_contract_class)), + ); state_reader .address_to_class_hash_mut() .insert(wrapper_address.clone(), wrapper_class_hash); @@ -1417,7 +1435,7 @@ fn replace_class_contract_call() { .insert(wrapper_address, nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // INITIALIZE STARKNET CONFIG let block_context = BlockContext::default(); @@ -1537,7 +1555,10 @@ fn replace_class_contract_call_same_transaction() { let class_hash_a: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash_a, contract_class_a); + contract_class_cache.insert( + class_hash_a, + CompiledClass::Casm(Arc::new(contract_class_a)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -1558,7 +1579,10 @@ fn replace_class_contract_call_same_transaction() { let class_hash_b: ClassHash = [2; 32]; - contract_class_cache.insert(class_hash_b, contract_class_b); + contract_class_cache.insert( + class_hash_b, + CompiledClass::Casm(Arc::new(contract_class_b)), + ); // SET GET_NUMBER_WRAPPER @@ -1574,7 +1598,10 @@ fn replace_class_contract_call_same_transaction() { let wrapper_address = Address(Felt252::from(2)); let wrapper_class_hash: ClassHash = [3; 32]; - contract_class_cache.insert(wrapper_class_hash, wrapper_contract_class); + contract_class_cache.insert( + wrapper_class_hash, + CompiledClass::Casm(Arc::new(wrapper_contract_class)), + ); state_reader .address_to_class_hash_mut() .insert(wrapper_address.clone(), wrapper_class_hash); @@ -1583,7 +1610,7 @@ fn replace_class_contract_call_same_transaction() { .insert(wrapper_address, nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // INITIALIZE STARKNET CONFIG let block_context = BlockContext::default(); @@ -1645,14 +1672,16 @@ fn call_contract_upgrade_cairo_0_to_cairo_1_same_transaction() { let contract_class_c = ContractClass::from_path("starknet_programs/get_number_c.json").unwrap(); // Create state reader with class hash data - let mut casm_contract_class_cache = HashMap::new(); - let mut deprecated_contract_class_cache = HashMap::new(); + let mut contract_class_cache = HashMap::new(); let address = Address(Felt252::one()); let class_hash_c: ClassHash = Felt252::one().to_be_bytes(); let nonce = Felt252::zero(); - deprecated_contract_class_cache.insert(class_hash_c, contract_class_c); + contract_class_cache.insert( + class_hash_c, + CompiledClass::Deprecated(Arc::new(contract_class_c)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -1673,7 +1702,10 @@ fn call_contract_upgrade_cairo_0_to_cairo_1_same_transaction() { let class_hash_b: ClassHash = Felt252::from(2).to_be_bytes(); - casm_contract_class_cache.insert(class_hash_b, contract_class_b); + contract_class_cache.insert( + class_hash_b, + CompiledClass::Casm(Arc::new(contract_class_b)), + ); // SET GET_NUMBER_WRAPPER @@ -1689,7 +1721,10 @@ fn call_contract_upgrade_cairo_0_to_cairo_1_same_transaction() { let wrapper_address = Address(Felt252::from(2)); let wrapper_class_hash: ClassHash = [3; 32]; - casm_contract_class_cache.insert(wrapper_class_hash, wrapper_contract_class); + contract_class_cache.insert( + wrapper_class_hash, + CompiledClass::Casm(Arc::new(wrapper_contract_class)), + ); state_reader .address_to_class_hash_mut() .insert(wrapper_address.clone(), wrapper_class_hash); @@ -1698,11 +1733,7 @@ fn call_contract_upgrade_cairo_0_to_cairo_1_same_transaction() { .insert(wrapper_address, nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new( - Arc::new(state_reader), - Some(deprecated_contract_class_cache), - Some(casm_contract_class_cache), - ); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // INITIALIZE STARKNET CONFIG let block_context = BlockContext::default(); @@ -1762,14 +1793,16 @@ fn call_contract_downgrade_cairo_1_to_cairo_0_same_transaction() { let contract_class_c = ContractClass::from_path("starknet_programs/get_number_c.json").unwrap(); // Create state reader with class hash data - let mut casm_contract_class_cache = HashMap::new(); - let mut deprecated_contract_class_cache = HashMap::new(); + let mut contract_class_cache = HashMap::new(); let address = Address(Felt252::one()); let class_hash_c: ClassHash = Felt252::one().to_be_bytes(); let nonce = Felt252::zero(); - deprecated_contract_class_cache.insert(class_hash_c, contract_class_c); + contract_class_cache.insert( + class_hash_c, + CompiledClass::Deprecated(Arc::new(contract_class_c)), + ); // SET GET_NUMBER_B @@ -1783,7 +1816,10 @@ fn call_contract_downgrade_cairo_1_to_cairo_0_same_transaction() { let class_hash_b: ClassHash = Felt252::from(2).to_be_bytes(); - casm_contract_class_cache.insert(class_hash_b, contract_class_b); + contract_class_cache.insert( + class_hash_b, + CompiledClass::Casm(Arc::new(contract_class_b)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -1806,7 +1842,10 @@ fn call_contract_downgrade_cairo_1_to_cairo_0_same_transaction() { let wrapper_address = Address(Felt252::from(2)); let wrapper_class_hash: ClassHash = [3; 32]; - casm_contract_class_cache.insert(wrapper_class_hash, wrapper_contract_class); + contract_class_cache.insert( + wrapper_class_hash, + CompiledClass::Casm(Arc::new(wrapper_contract_class)), + ); state_reader .address_to_class_hash_mut() .insert(wrapper_address.clone(), wrapper_class_hash); @@ -1815,11 +1854,7 @@ fn call_contract_downgrade_cairo_1_to_cairo_0_same_transaction() { .insert(wrapper_address, nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new( - Arc::new(state_reader), - Some(deprecated_contract_class_cache), - Some(casm_contract_class_cache), - ); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // INITIALIZE STARKNET CONFIG let block_context = BlockContext::default(); @@ -1879,14 +1914,16 @@ fn call_contract_replace_class_cairo_0() { let contract_class_c = ContractClass::from_path("starknet_programs/get_number_c.json").unwrap(); // Create state reader with class hash data - let mut casm_contract_class_cache = HashMap::new(); - let mut deprecated_contract_class_cache = HashMap::new(); + let mut contract_class_cache = HashMap::new(); let address = Address(Felt252::one()); let class_hash_c: ClassHash = Felt252::one().to_be_bytes(); let nonce = Felt252::zero(); - deprecated_contract_class_cache.insert(class_hash_c, contract_class_c); + contract_class_cache.insert( + class_hash_c, + CompiledClass::Deprecated(Arc::new(contract_class_c)), + ); // SET GET_NUMBER_B @@ -1896,7 +1933,10 @@ fn call_contract_replace_class_cairo_0() { let class_hash_d: ClassHash = Felt252::from(2).to_be_bytes(); - deprecated_contract_class_cache.insert(class_hash_d, contract_class_d); + contract_class_cache.insert( + class_hash_d, + CompiledClass::Deprecated(Arc::new(contract_class_d)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -1919,7 +1959,10 @@ fn call_contract_replace_class_cairo_0() { let wrapper_address = Address(Felt252::from(2)); let wrapper_class_hash: ClassHash = [3; 32]; - casm_contract_class_cache.insert(wrapper_class_hash, wrapper_contract_class); + contract_class_cache.insert( + wrapper_class_hash, + CompiledClass::Casm(Arc::new(wrapper_contract_class)), + ); state_reader .address_to_class_hash_mut() .insert(wrapper_address.clone(), wrapper_class_hash); @@ -1928,11 +1971,7 @@ fn call_contract_replace_class_cairo_0() { .insert(wrapper_address, nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new( - Arc::new(state_reader), - Some(deprecated_contract_class_cache), - Some(casm_contract_class_cache), - ); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // INITIALIZE STARKNET CONFIG let block_context = BlockContext::default(); @@ -1998,7 +2037,7 @@ fn test_out_of_gas_failure() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -2008,7 +2047,7 @@ fn test_out_of_gas_failure() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // Create an execution entry point let calldata = [].to_vec(); @@ -2075,7 +2114,7 @@ fn deploy_syscall_failure_uninitialized_class_hash() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -2085,7 +2124,7 @@ fn deploy_syscall_failure_uninitialized_class_hash() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // Create an execution entry point let calldata = [Felt252::zero()].to_vec(); @@ -2151,7 +2190,7 @@ fn deploy_syscall_failure_in_constructor() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -2167,10 +2206,13 @@ fn deploy_syscall_failure_in_constructor() { let f_c_program_data = include_bytes!("../starknet_programs/cairo1/failing_constructor.casm"); let f_c_contract_class: CasmContractClass = serde_json::from_slice(f_c_program_data).unwrap(); let f_c_class_hash = Felt252::one(); - contract_class_cache.insert(f_c_class_hash.to_be_bytes(), f_c_contract_class); + contract_class_cache.insert( + f_c_class_hash.to_be_bytes(), + CompiledClass::Casm(Arc::new(f_c_contract_class)), + ); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // Create an execution entry point let calldata = [f_c_class_hash].to_vec(); @@ -2238,7 +2280,7 @@ fn storage_read_no_value() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -2248,7 +2290,7 @@ fn storage_read_no_value() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); let block_context = BlockContext::default(); let mut tx_execution_context = TransactionExecutionContext::new( @@ -2309,7 +2351,7 @@ fn storage_read_unavailable_address_domain() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -2319,7 +2361,7 @@ fn storage_read_unavailable_address_domain() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); let block_context = BlockContext::default(); let mut tx_execution_context = TransactionExecutionContext::new( @@ -2383,7 +2425,7 @@ fn storage_write_unavailable_address_domain() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -2393,7 +2435,7 @@ fn storage_write_unavailable_address_domain() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); let block_context = BlockContext::default(); let mut tx_execution_context = TransactionExecutionContext::new( @@ -2455,7 +2497,7 @@ fn library_call_failure() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -2476,7 +2518,10 @@ fn library_call_failure() { let lib_class_hash: ClassHash = [2; 32]; let lib_nonce = Felt252::zero(); - contract_class_cache.insert(lib_class_hash, lib_contract_class); + contract_class_cache.insert( + lib_class_hash, + CompiledClass::Casm(Arc::new(lib_contract_class)), + ); state_reader .address_to_class_hash_mut() .insert(lib_address.clone(), lib_class_hash); @@ -2485,7 +2530,7 @@ fn library_call_failure() { .insert(lib_address, lib_nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // Create an execution entry point let calldata = [25.into(), Felt252::from_bytes_be(&lib_class_hash)].to_vec(); @@ -2564,7 +2609,7 @@ fn send_messages_to_l1_different_contract_calls() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -2585,7 +2630,10 @@ fn send_messages_to_l1_different_contract_calls() { let send_msg_class_hash: ClassHash = [2; 32]; let send_msg_nonce = Felt252::zero(); - contract_class_cache.insert(send_msg_class_hash, send_msg_contract_class); + contract_class_cache.insert( + send_msg_class_hash, + CompiledClass::Casm(Arc::new(send_msg_contract_class)), + ); state_reader .address_to_class_hash_mut() .insert(send_msg_address.clone(), send_msg_class_hash); @@ -2594,7 +2642,7 @@ fn send_messages_to_l1_different_contract_calls() { .insert(send_msg_address, send_msg_nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // Create an execution entry point let calldata = [25.into(), 50.into(), 75.into()].to_vec(); @@ -2679,13 +2727,12 @@ fn send_messages_to_l1_different_contract_calls_cairo1_to_cairo0() { // Create state reader with class hash data let mut contract_class_cache = HashMap::new(); - let mut deprecated_contract_class_cache = HashMap::new(); let address = Address(1111.into()); let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -2703,7 +2750,10 @@ fn send_messages_to_l1_different_contract_calls_cairo1_to_cairo0() { let send_msg_class_hash: ClassHash = [2; 32]; let send_msg_nonce = Felt252::zero(); - deprecated_contract_class_cache.insert(send_msg_class_hash, send_msg_contract_class); + contract_class_cache.insert( + send_msg_class_hash, + CompiledClass::Deprecated(Arc::new(send_msg_contract_class)), + ); state_reader .address_to_class_hash_mut() .insert(send_msg_address.clone(), send_msg_class_hash); @@ -2712,11 +2762,7 @@ fn send_messages_to_l1_different_contract_calls_cairo1_to_cairo0() { .insert(send_msg_address, send_msg_nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new( - Arc::new(state_reader), - Some(deprecated_contract_class_cache), - Some(contract_class_cache), - ); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // Create an execution entry point let calldata = [25.into(), 50.into(), 75.into()].to_vec(); @@ -2796,13 +2842,15 @@ fn send_messages_to_l1_different_contract_calls_cairo0_to_cairo1() { // Create state reader with class hash data let mut contract_class_cache = HashMap::new(); - let mut deprecated_contract_class_cache = HashMap::new(); let address = Address(1111.into()); let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - deprecated_contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -2823,7 +2871,10 @@ fn send_messages_to_l1_different_contract_calls_cairo0_to_cairo1() { let send_msg_class_hash: ClassHash = [2; 32]; let send_msg_nonce = Felt252::zero(); - contract_class_cache.insert(send_msg_class_hash, send_msg_contract_class); + contract_class_cache.insert( + send_msg_class_hash, + CompiledClass::Casm(Arc::new(send_msg_contract_class)), + ); state_reader .address_to_class_hash_mut() .insert(send_msg_address.clone(), send_msg_class_hash); @@ -2832,11 +2883,7 @@ fn send_messages_to_l1_different_contract_calls_cairo0_to_cairo1() { .insert(send_msg_address, send_msg_nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new( - Arc::new(state_reader), - Some(deprecated_contract_class_cache), - Some(contract_class_cache), - ); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // Create an execution entry point let calldata = [25.into(), 50.into(), 75.into()].to_vec(); @@ -2920,7 +2967,7 @@ fn keccak_syscall() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -2930,7 +2977,7 @@ fn keccak_syscall() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); let block_context = BlockContext::default(); let mut tx_execution_context = TransactionExecutionContext::new( diff --git a/tests/complex_contracts/amm_contracts/amm.rs b/tests/complex_contracts/amm_contracts/amm.rs index bbab48eb9..6f987ed64 100644 --- a/tests/complex_contracts/amm_contracts/amm.rs +++ b/tests/complex_contracts/amm_contracts/amm.rs @@ -54,11 +54,7 @@ fn swap(calldata: &[Felt252], call_config: &mut CallConfig) -> Result { pub state: &'a mut CachedState, @@ -156,7 +161,10 @@ pub fn deploy( )?, }; let class_hash = internal_deploy.class_hash(); - state.set_contract_class(&class_hash, &contract_class)?; + state.set_contract_class( + &class_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + )?; let tx_execution_info = internal_deploy.apply(state, block_context)?; diff --git a/tests/delegate_call.rs b/tests/delegate_call.rs index f3705c533..f9d2c7b57 100644 --- a/tests/delegate_call.rs +++ b/tests/delegate_call.rs @@ -2,6 +2,7 @@ use cairo_vm::felt::Felt252; use num_traits::{One, Zero}; +use starknet_in_rust::services::api::contract_classes::compiled_class::CompiledClass; use starknet_in_rust::EntryPointType; use starknet_in_rust::{ definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, @@ -33,7 +34,10 @@ fn delegate_call() { let address = Address(Felt252::one()); // const CONTRACT_ADDRESS = 1; let class_hash = [2; 32]; - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -64,7 +68,10 @@ fn delegate_call() { let address = Address(1111.into()); let class_hash = [1; 32]; - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); state_reader .address_to_class_hash_mut() .insert(address.clone(), class_hash); @@ -76,7 +83,7 @@ fn delegate_call() { //* Create state with previous data //* --------------------------------------- - let mut state = CachedState::new(Arc::new(state_reader), Some(contract_class_cache), None); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); //* ------------------------------------ //* Create execution entry point diff --git a/tests/delegate_l1_handler.rs b/tests/delegate_l1_handler.rs index a62b46181..fdc91ee81 100644 --- a/tests/delegate_l1_handler.rs +++ b/tests/delegate_l1_handler.rs @@ -2,6 +2,7 @@ use cairo_vm::felt::{felt_str, Felt252}; use num_traits::{One, Zero}; +use starknet_in_rust::services::api::contract_classes::compiled_class::CompiledClass; use starknet_in_rust::EntryPointType; use starknet_in_rust::{ definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, @@ -34,7 +35,10 @@ fn delegate_l1_handler() { let address = Address(Felt252::one()); // const CONTRACT_ADDRESS = 1; let class_hash = [2; 32]; - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -59,7 +63,10 @@ fn delegate_l1_handler() { let address = Address(1111.into()); let class_hash = [1; 32]; - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); state_reader .address_to_class_hash_mut() .insert(address.clone(), class_hash); @@ -71,7 +78,7 @@ fn delegate_l1_handler() { //* Create state with previous data //* --------------------------------------- - let mut state = CachedState::new(Arc::new(state_reader), Some(contract_class_cache), None); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); //* ------------------------------------ //* Create execution entry point diff --git a/tests/deploy_account.rs b/tests/deploy_account.rs index f0d5636a8..6da3256af 100644 --- a/tests/deploy_account.rs +++ b/tests/deploy_account.rs @@ -4,7 +4,6 @@ use cairo_vm::{ }; use lazy_static::lazy_static; use num_traits::Zero; -use starknet_in_rust::EntryPointType; use starknet_in_rust::{ core::contract_address::compute_deprecated_class_hash, definitions::{ @@ -20,7 +19,13 @@ use starknet_in_rust::{ utils::Address, CasmContractClass, }; -use std::{collections::HashSet, sync::Arc}; +use starknet_in_rust::{ + services::api::contract_classes::compiled_class::CompiledClass, EntryPointType, +}; +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, +}; lazy_static! { static ref TEST_ACCOUNT_COMPILED_CONTRACT_CLASS_HASH: Felt252 = felt_str!("1"); @@ -29,7 +34,7 @@ lazy_static! { #[test] fn internal_deploy_account() { let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, None, None); + let mut state = CachedState::new(state_reader, HashMap::new()); state.set_contract_classes(Default::default()).unwrap(); @@ -40,7 +45,10 @@ fn internal_deploy_account() { let class_hash_bytes = class_hash.to_be_bytes(); state - .set_contract_class(&class_hash_bytes, &contract_class) + .set_contract_class( + &class_hash_bytes, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) .unwrap(); let contract_address_salt = @@ -109,7 +117,7 @@ fn internal_deploy_account() { #[test] fn internal_deploy_account_cairo1() { let state_reader = Arc::new(InMemoryStateReader::default()); - let mut state = CachedState::new(state_reader, None, Some(Default::default())); + let mut state = CachedState::new(state_reader, HashMap::default()); state.set_contract_classes(Default::default()).unwrap(); @@ -120,9 +128,9 @@ fn internal_deploy_account_cairo1() { let contract_class: CasmContractClass = serde_json::from_slice(program_data).unwrap(); state - .set_compiled_class( - &TEST_ACCOUNT_COMPILED_CONTRACT_CLASS_HASH.clone(), - contract_class, + .set_contract_class( + &TEST_ACCOUNT_COMPILED_CONTRACT_CLASS_HASH.to_be_bytes(), + &CompiledClass::Casm(Arc::new(contract_class)), ) .unwrap(); diff --git a/tests/fibonacci.rs b/tests/fibonacci.rs index 17f44906c..827c7935d 100644 --- a/tests/fibonacci.rs +++ b/tests/fibonacci.rs @@ -6,6 +6,7 @@ use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use cairo_vm::{felt::Felt252, vm::runners::builtin_runner::RANGE_CHECK_BUILTIN_NAME}; use num_traits::Zero; use starknet_in_rust::definitions::block_context::BlockContext; +use starknet_in_rust::services::api::contract_classes::compiled_class::CompiledClass; use starknet_in_rust::EntryPointType; use starknet_in_rust::{ definitions::constants::TRANSACTION_VERSION, @@ -50,7 +51,10 @@ fn integration_test() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -63,7 +67,7 @@ fn integration_test() { //* Create state with previous data //* --------------------------------------- - let mut state = CachedState::new(Arc::new(state_reader), Some(contract_class_cache), None); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); //* ------------------------------------ //* Create execution entry point @@ -151,7 +155,7 @@ fn integration_test_cairo1() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -161,7 +165,7 @@ fn integration_test_cairo1() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new(Arc::new(state_reader), None, Some(contract_class_cache)); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // Create an execution entry point let calldata = [0.into(), 1.into(), 12.into()].to_vec(); diff --git a/tests/increase_balance.rs b/tests/increase_balance.rs index 7aec0336b..141583e7b 100644 --- a/tests/increase_balance.rs +++ b/tests/increase_balance.rs @@ -3,6 +3,7 @@ use cairo_vm::felt::Felt252; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use num_traits::Zero; +use starknet_in_rust::services::api::contract_classes::compiled_class::CompiledClass; use starknet_in_rust::EntryPointType; use starknet_in_rust::{ definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, @@ -53,7 +54,10 @@ fn hello_starknet_increase_balance() { let storage_entry: StorageEntry = (address.clone(), [1; 32]); let storage = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -69,7 +73,7 @@ fn hello_starknet_increase_balance() { //* Create state with previous data //* --------------------------------------- - let mut state = CachedState::new(Arc::new(state_reader), Some(contract_class_cache), None); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); //* ------------------------------------ //* Create execution entry point diff --git a/tests/internal_calls.rs b/tests/internal_calls.rs index 62ed69d71..97de33e63 100644 --- a/tests/internal_calls.rs +++ b/tests/internal_calls.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use cairo_vm::felt::Felt252; use num_traits::Zero; +use starknet_in_rust::services::api::contract_classes::compiled_class::CompiledClass; use starknet_in_rust::EntryPointType; use starknet_in_rust::{ definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, @@ -15,6 +16,7 @@ use starknet_in_rust::{ state::{in_memory_state_reader::InMemoryStateReader, ExecutionResourcesManager}, utils::{calculate_sn_keccak, Address, ClassHash}, }; +use std::collections::HashMap; #[test] fn test_internal_calls() { @@ -47,8 +49,10 @@ fn test_internal_calls() { let mut state = CachedState::new( Arc::new(state_reader), - Some([([0x01; 32], contract_class)].into_iter().collect()), - None, + HashMap::from([( + [0x01; 32], + CompiledClass::Deprecated(Arc::new(contract_class)), + )]), ); let entry_point_selector = Felt252::from_bytes_be(&calculate_sn_keccak(b"a")); diff --git a/tests/internals.rs b/tests/internals.rs index 26595c01b..94f845e36 100644 --- a/tests/internals.rs +++ b/tests/internals.rs @@ -41,7 +41,7 @@ use starknet_in_rust::{ execution::{CallInfo, CallType, OrderedEvent, TransactionExecutionInfo}, state::in_memory_state_reader::InMemoryStateReader, state::{ - cached_state::{CachedState, ContractClassCache}, + cached_state::CachedState, state_api::{State, StateReader}, state_cache::StateCache, state_cache::StorageEntry, @@ -188,14 +188,14 @@ fn create_account_tx_test_state( state_reader.address_to_storage_mut().extend(stored); } for (class_hash, contract_class) in class_hash_to_class { - state_reader - .class_hash_to_contract_class_mut() - .insert(class_hash, contract_class); + state_reader.class_hash_to_compiled_class_mut().insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); } Arc::new(state_reader) }, - Some(HashMap::new()), - Some(HashMap::new()), + HashMap::new(), ); Ok((block_context, cached_state)) @@ -204,38 +204,37 @@ fn create_account_tx_test_state( fn expected_state_before_tx() -> CachedState { let in_memory_state_reader = initial_in_memory_state_reader(); - let state_cache = ContractClassCache::new(); - - CachedState::new( - Arc::new(in_memory_state_reader), - Some(state_cache), - Some(HashMap::new()), - ) + CachedState::new(Arc::new(in_memory_state_reader), HashMap::new()) } fn expected_state_after_tx(fee: u128) -> CachedState { let in_memory_state_reader = initial_in_memory_state_reader(); - let contract_classes_cache = ContractClassCache::from([ + let contract_classes_cache = HashMap::from([ ( felt_to_hash(&TEST_CLASS_HASH.clone()), - ContractClass::from_path(TEST_CONTRACT_PATH).unwrap(), + CompiledClass::Deprecated(Arc::new( + ContractClass::from_path(TEST_CONTRACT_PATH).unwrap(), + )), ), ( felt_to_hash(&TEST_ACCOUNT_CONTRACT_CLASS_HASH.clone()), - ContractClass::from_path(ACCOUNT_CONTRACT_PATH).unwrap(), + CompiledClass::Deprecated(Arc::new( + ContractClass::from_path(ACCOUNT_CONTRACT_PATH).unwrap(), + )), ), ( felt_to_hash(&TEST_ERC20_CONTRACT_CLASS_HASH.clone()), - ContractClass::from_path(ERC20_CONTRACT_PATH).unwrap(), + CompiledClass::Deprecated(Arc::new( + ContractClass::from_path(ERC20_CONTRACT_PATH).unwrap(), + )), ), ]); CachedState::new_for_testing( Arc::new(in_memory_state_reader), - Some(contract_classes_cache), state_cache_after_invoke_tx(fee), - Some(HashMap::new()), + contract_classes_cache, ) } @@ -372,19 +371,24 @@ fn initial_in_memory_state_reader() -> InMemoryStateReader { HashMap::from([ ( felt_to_hash(&TEST_ERC20_CONTRACT_CLASS_HASH), - ContractClass::from_path(ERC20_CONTRACT_PATH).unwrap(), + CompiledClass::Deprecated(Arc::new( + ContractClass::from_path(ERC20_CONTRACT_PATH).unwrap(), + )), ), ( felt_to_hash(&TEST_ACCOUNT_CONTRACT_CLASS_HASH), - ContractClass::from_path(ACCOUNT_CONTRACT_PATH).unwrap(), + CompiledClass::Deprecated(Arc::new( + ContractClass::from_path(ACCOUNT_CONTRACT_PATH).unwrap(), + )), ), ( felt_to_hash(&TEST_CLASS_HASH), - ContractClass::from_path(TEST_CONTRACT_PATH).unwrap(), + CompiledClass::Deprecated(Arc::new( + ContractClass::from_path(TEST_CONTRACT_PATH).unwrap(), + )), ), ]), HashMap::new(), - HashMap::new(), ) } @@ -524,10 +528,6 @@ fn test_create_account_tx_test_state() { &state.contract_classes(), &expected_initial_state.contract_classes() ); - assert_eq!( - &state.casm_contract_classes(), - &expected_initial_state.casm_contract_classes() - ); assert_eq!( &state.state_reader.address_to_class_hash, &expected_initial_state.state_reader.address_to_class_hash @@ -542,21 +542,21 @@ fn test_create_account_tx_test_state() { ); assert!(&state .state_reader - .class_hash_to_contract_class + .class_hash_to_compiled_class .contains_key(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16 ])); assert!(&state .state_reader - .class_hash_to_contract_class + .class_hash_to_compiled_class .contains_key(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 16 ])); assert!(&state .state_reader - .class_hash_to_contract_class + .class_hash_to_compiled_class .contains_key(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 17 @@ -874,10 +874,6 @@ fn test_declare_tx() { &state.contract_classes(), &expected_initial_state.contract_classes() ); - assert_eq!( - &state.casm_contract_classes(), - &expected_initial_state.casm_contract_classes() - ); assert_eq!( &state.state_reader.address_to_class_hash, &expected_initial_state.state_reader.address_to_class_hash @@ -892,21 +888,21 @@ fn test_declare_tx() { ); assert!(&state .state_reader - .class_hash_to_contract_class + .class_hash_to_compiled_class .contains_key(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16 ])); assert!(&state .state_reader - .class_hash_to_contract_class + .class_hash_to_compiled_class .contains_key(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 16 ])); assert!(&state .state_reader - .class_hash_to_contract_class + .class_hash_to_compiled_class .contains_key(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 17 @@ -962,10 +958,6 @@ fn test_declarev2_tx() { &state.contract_classes(), &expected_initial_state.contract_classes() ); - assert_eq!( - &state.casm_contract_classes(), - &expected_initial_state.casm_contract_classes() - ); assert_eq!( &state.state_reader.address_to_class_hash, &expected_initial_state.state_reader.address_to_class_hash @@ -980,21 +972,21 @@ fn test_declarev2_tx() { ); assert!(&state .state_reader - .class_hash_to_contract_class + .class_hash_to_compiled_class .contains_key(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16 ])); assert!(&state .state_reader - .class_hash_to_contract_class + .class_hash_to_compiled_class .contains_key(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 16 ])); assert!(&state .state_reader - .class_hash_to_contract_class + .class_hash_to_compiled_class .contains_key(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 17 @@ -1308,10 +1300,6 @@ fn test_invoke_tx_state() { &state.contract_classes(), &expected_initial_state.contract_classes() ); - assert_eq!( - &state.casm_contract_classes(), - &expected_initial_state.casm_contract_classes() - ); assert_eq!( &state.state_reader.address_to_class_hash, &expected_initial_state.state_reader.address_to_class_hash @@ -1326,21 +1314,21 @@ fn test_invoke_tx_state() { ); assert!(&state .state_reader - .class_hash_to_contract_class + .class_hash_to_compiled_class .contains_key(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16 ])); assert!(&state .state_reader - .class_hash_to_contract_class + .class_hash_to_compiled_class .contains_key(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 16 ])); assert!(&state .state_reader - .class_hash_to_contract_class + .class_hash_to_compiled_class .contains_key(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 17 @@ -1362,10 +1350,6 @@ fn test_invoke_tx_state() { let expected_final_state = expected_state_after_tx(result.actual_fee); assert_eq!(&state.cache(), &expected_final_state.cache()); - assert_eq!( - &state.casm_contract_classes(), - &expected_final_state.casm_contract_classes() - ); assert_eq!( &state.state_reader.address_to_class_hash, &expected_final_state.state_reader.address_to_class_hash @@ -1389,10 +1373,6 @@ fn test_invoke_with_declarev2_tx() { &state.contract_classes(), &expected_initial_state.contract_classes() ); - assert_eq!( - &state.casm_contract_classes(), - &expected_initial_state.casm_contract_classes() - ); assert_eq!( &state.state_reader.address_to_class_hash, &expected_initial_state.state_reader.address_to_class_hash @@ -1407,21 +1387,21 @@ fn test_invoke_with_declarev2_tx() { ); assert!(&state .state_reader - .class_hash_to_contract_class + .class_hash_to_compiled_class .contains_key(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16 ])); assert!(&state .state_reader - .class_hash_to_contract_class + .class_hash_to_compiled_class .contains_key(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 16 ])); assert!(&state .state_reader - .class_hash_to_contract_class + .class_hash_to_compiled_class .contains_key(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 17 @@ -1488,19 +1468,11 @@ fn test_deploy_account() { assert_eq!(&state.cache(), &state_before.cache()); assert_eq!(&state.contract_classes(), &state_before.contract_classes()); - assert_eq!( - &state.casm_contract_classes(), - &state_before.casm_contract_classes() - ); let tx_info = deploy_account_tx .execute(&mut state, &block_context) .unwrap(); - assert_eq!( - state.casm_contract_classes(), - state_after.casm_contract_classes() - ); assert_eq!(state.cache(), state_after.cache()); let expected_validate_call_info = expected_validate_call_info( @@ -1599,22 +1571,26 @@ fn expected_deploy_account_states() -> ( HashMap::from([ ( felt_to_hash(&0x110.into()), - ContractClass::from_path(TEST_CONTRACT_PATH).unwrap(), + CompiledClass::Deprecated(Arc::new( + ContractClass::from_path(TEST_CONTRACT_PATH).unwrap(), + )), ), ( felt_to_hash(&0x111.into()), - ContractClass::from_path(ACCOUNT_CONTRACT_PATH).unwrap(), + CompiledClass::Deprecated(Arc::new( + ContractClass::from_path(ACCOUNT_CONTRACT_PATH).unwrap(), + )), ), ( felt_to_hash(&0x1010.into()), - ContractClass::from_path(ERC20_CONTRACT_PATH).unwrap(), + CompiledClass::Deprecated(Arc::new( + ContractClass::from_path(ERC20_CONTRACT_PATH).unwrap(), + )), ), ]), HashMap::new(), - HashMap::new(), )), - Some(ContractClassCache::new()), - Some(HashMap::new()), + HashMap::new(), ); state_before.set_storage_at( &( @@ -1712,13 +1688,17 @@ fn expected_deploy_account_states() -> ( state_after .set_contract_class( &felt_to_hash(&0x1010.into()), - &ContractClass::from_path(ERC20_CONTRACT_PATH).unwrap(), + &CompiledClass::Deprecated(Arc::new( + ContractClass::from_path(ERC20_CONTRACT_PATH).unwrap(), + )), ) .unwrap(); state_after .set_contract_class( &felt_to_hash(&0x111.into()), - &ContractClass::from_path(ACCOUNT_CONTRACT_PATH).unwrap(), + &CompiledClass::Deprecated(Arc::new( + ContractClass::from_path(ACCOUNT_CONTRACT_PATH).unwrap(), + )), ) .unwrap(); @@ -2034,7 +2014,7 @@ fn test_library_call_with_declare_v2() { .insert(address.clone(), nonce); state - .set_compiled_class(&Felt252::from_bytes_be(&class_hash), contract_class) + .set_contract_class(&class_hash, &CompiledClass::Casm(Arc::new(contract_class))) .unwrap(); let create_execute_extrypoint = |selector: &BigUint, diff --git a/tests/multi_syscall_test.rs b/tests/multi_syscall_test.rs index 7aa7890d7..9f75e7925 100644 --- a/tests/multi_syscall_test.rs +++ b/tests/multi_syscall_test.rs @@ -1,6 +1,7 @@ use cairo_lang_starknet::casm_contract_class::CasmContractClass; use cairo_vm::felt::Felt252; use num_traits::{Num, Zero}; +use starknet_in_rust::services::api::contract_classes::compiled_class::CompiledClass; use starknet_in_rust::utils::calculate_sn_keccak; use starknet_in_rust::EntryPointType; use starknet_in_rust::{ @@ -28,7 +29,7 @@ fn test_multiple_syscall() { let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert(class_hash, CompiledClass::Casm(Arc::new(contract_class))); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -38,11 +39,7 @@ fn test_multiple_syscall() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new( - Arc::new(state_reader), - None, - Some(contract_class_cache.clone()), - ); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache.clone()); // Create an execution entry point let calldata = [].to_vec(); diff --git a/tests/storage.rs b/tests/storage.rs index 19d03359e..f13bc141c 100644 --- a/tests/storage.rs +++ b/tests/storage.rs @@ -1,6 +1,7 @@ use cairo_vm::felt::Felt252; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use num_traits::Zero; +use starknet_in_rust::services::api::contract_classes::compiled_class::CompiledClass; use starknet_in_rust::EntryPointType; use starknet_in_rust::{ definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, @@ -50,7 +51,10 @@ fn integration_storage_test() { let storage_entry = (address.clone(), [90; 32]); let storage_value = Felt252::new(10902); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -66,7 +70,7 @@ fn integration_storage_test() { //* Create state with previous data //* --------------------------------------- - let mut state = CachedState::new(Arc::new(state_reader), Some(contract_class_cache), None); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); //* ------------------------------------ //* Create execution entry point diff --git a/tests/syscalls.rs b/tests/syscalls.rs index 23ee0b2e0..03bfd188f 100644 --- a/tests/syscalls.rs +++ b/tests/syscalls.rs @@ -10,7 +10,6 @@ use cairo_vm::{ }, }; use num_traits::{Num, One, Zero}; -use starknet_in_rust::EntryPointType; use starknet_in_rust::{ definitions::{ block_context::{BlockContext, StarknetChainId}, @@ -20,16 +19,17 @@ use starknet_in_rust::{ execution_entry_point::ExecutionEntryPoint, CallInfo, CallType, L2toL1MessageInfo, OrderedEvent, OrderedL2ToL1Message, TransactionExecutionContext, }, - services::api::contract_classes::{ - compiled_class::CompiledClass, deprecated_contract_class::ContractClass, - }, + services::api::contract_classes::deprecated_contract_class::ContractClass, state::{ - cached_state::{CachedState, ContractClassCache}, + cached_state::CachedState, state_api::{State, StateReader}, }, state::{in_memory_state_reader::InMemoryStateReader, ExecutionResourcesManager}, utils::{calculate_sn_keccak, felt_to_hash, Address, ClassHash}, }; +use starknet_in_rust::{ + services::api::contract_classes::compiled_class::CompiledClass, EntryPointType, +}; use std::{ collections::{HashMap, HashSet}, iter::empty, @@ -85,19 +85,23 @@ fn test_contract<'a>( state_reader .address_to_nonce_mut() .insert(contract_address.clone(), nonce); - state_reader - .class_hash_to_contract_class_mut() - .insert(class_hash, contract_class); + state_reader.class_hash_to_compiled_class_mut().insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); let mut storage_entries = Vec::new(); let contract_class_cache = { - let mut contract_class_cache = ContractClassCache::new(); + let mut contract_class_cache = HashMap::new(); for (class_hash, contract_path, contract_address) in extra_contracts { let contract_class = ContractClass::from_path(contract_path) .expect("Could not load extra contract from JSON"); - contract_class_cache.insert(class_hash, contract_class.clone()); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class.clone())), + ); if let Some((contract_address, data)) = contract_address { storage_entries.extend( @@ -108,15 +112,16 @@ fn test_contract<'a>( state_reader .address_to_class_hash_mut() .insert(contract_address.clone(), class_hash); - state_reader - .class_hash_to_contract_class_mut() - .insert(class_hash, contract_class.clone()); + state_reader.class_hash_to_compiled_class_mut().insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class.clone())), + ); } } - Some(contract_class_cache) + contract_class_cache }; - let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache, None); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); storage_entries .into_iter() .for_each(|(a, b, c)| state.set_storage_at(&(a, b), c)); @@ -1079,7 +1084,6 @@ fn deploy_cairo1_from_cairo0_with_constructor() { let test_contract_class: CasmContractClass = serde_json::from_slice(program_data).unwrap(); // Create state reader with class hash data - let mut casm_contract_class_cache = HashMap::new(); let mut contract_class_cache = HashMap::new(); let address = Address(1111.into()); @@ -1087,8 +1091,14 @@ fn deploy_cairo1_from_cairo0_with_constructor() { let nonce = Felt252::zero(); // simulate contract declare - casm_contract_class_cache.insert(test_class_hash, test_contract_class.clone()); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + test_class_hash, + CompiledClass::Casm(Arc::new(test_contract_class.clone())), + ); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader @@ -1099,11 +1109,7 @@ fn deploy_cairo1_from_cairo0_with_constructor() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new( - Arc::new(state_reader), - Some(contract_class_cache), - Some(casm_contract_class_cache), - ); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // arguments of deploy contract let calldata: Vec<_> = [test_felt_hash, salt, Felt252::one()].to_vec(); @@ -1180,7 +1186,6 @@ fn deploy_cairo1_from_cairo0_without_constructor() { let test_contract_class: CasmContractClass = serde_json::from_slice(program_data).unwrap(); // Create state reader with class hash data - let mut casm_contract_class_cache = HashMap::new(); let mut contract_class_cache = HashMap::new(); let address = Address(1111.into()); @@ -1188,8 +1193,14 @@ fn deploy_cairo1_from_cairo0_without_constructor() { let nonce = Felt252::zero(); // simulate contract declare - casm_contract_class_cache.insert(test_class_hash, test_contract_class.clone()); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + test_class_hash, + CompiledClass::Casm(Arc::new(test_contract_class.clone())), + ); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader @@ -1200,11 +1211,7 @@ fn deploy_cairo1_from_cairo0_without_constructor() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new( - Arc::new(state_reader), - Some(contract_class_cache), - Some(casm_contract_class_cache), - ); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // arguments of deploy contract let calldata: Vec<_> = [test_felt_hash, salt].to_vec(); @@ -1283,7 +1290,6 @@ fn deploy_cairo1_and_invoke() { let test_contract_class: CasmContractClass = serde_json::from_slice(program_data).unwrap(); // Create state reader with class hash data - let mut casm_contract_class_cache = HashMap::new(); let mut contract_class_cache = HashMap::new(); let address = Address(1111.into()); @@ -1291,8 +1297,14 @@ fn deploy_cairo1_and_invoke() { let nonce = Felt252::zero(); // simulate contract declare - casm_contract_class_cache.insert(test_class_hash, test_contract_class.clone()); - contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + test_class_hash, + CompiledClass::Casm(Arc::new(test_contract_class.clone())), + ); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader @@ -1303,11 +1315,7 @@ fn deploy_cairo1_and_invoke() { .insert(address.clone(), nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new( - Arc::new(state_reader), - Some(contract_class_cache), - Some(casm_contract_class_cache), - ); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // arguments of deploy contract let calldata: Vec<_> = [test_felt_hash, salt].to_vec(); @@ -1408,13 +1416,16 @@ fn send_messages_to_l1_different_contract_calls() { .to_owned(); // Create state reader with class hash data - let mut deprecated_contract_class_cache = HashMap::new(); + let mut contract_class_cache = HashMap::new(); let address = Address(1111.into()); let class_hash: ClassHash = [1; 32]; let nonce = Felt252::zero(); - deprecated_contract_class_cache.insert(class_hash, contract_class); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); let mut state_reader = InMemoryStateReader::default(); state_reader .address_to_class_hash_mut() @@ -1432,7 +1443,10 @@ fn send_messages_to_l1_different_contract_calls() { let send_msg_class_hash: ClassHash = [2; 32]; let send_msg_nonce = Felt252::zero(); - deprecated_contract_class_cache.insert(send_msg_class_hash, send_msg_contract_class); + contract_class_cache.insert( + send_msg_class_hash, + CompiledClass::Deprecated(Arc::new(send_msg_contract_class)), + ); state_reader .address_to_class_hash_mut() .insert(send_msg_address.clone(), send_msg_class_hash); @@ -1441,11 +1455,7 @@ fn send_messages_to_l1_different_contract_calls() { .insert(send_msg_address, send_msg_nonce); // Create state from the state_reader and contract cache. - let mut state = CachedState::new( - Arc::new(state_reader), - Some(deprecated_contract_class_cache), - None, - ); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); // Create an execution entry point let calldata = [25.into(), 50.into(), 75.into()].to_vec(); diff --git a/tests/syscalls_errors.rs b/tests/syscalls_errors.rs index 17d85bb1f..1e9433e93 100644 --- a/tests/syscalls_errors.rs +++ b/tests/syscalls_errors.rs @@ -10,10 +10,7 @@ use starknet_in_rust::{ execution_entry_point::ExecutionEntryPoint, CallType, TransactionExecutionContext, }, services::api::contract_classes::deprecated_contract_class::ContractClass, - state::{ - cached_state::{CachedState, ContractClassCache}, - state_api::State, - }, + state::{cached_state::CachedState, state_api::State}, state::{in_memory_state_reader::InMemoryStateReader, ExecutionResourcesManager}, utils::{calculate_sn_keccak, Address, ClassHash}, }; @@ -21,6 +18,8 @@ use std::path::Path; use std::sync::Arc; use assert_matches::assert_matches; +use starknet_in_rust::services::api::contract_classes::compiled_class::CompiledClass; +use std::collections::HashMap; #[allow(clippy::too_many_arguments)] fn test_contract<'a>( @@ -63,19 +62,23 @@ fn test_contract<'a>( state_reader .address_to_nonce_mut() .insert(contract_address.clone(), nonce); - state_reader - .class_hash_to_contract_class_mut() - .insert(class_hash, contract_class); + state_reader.class_hash_to_compiled_class_mut().insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); let mut storage_entries = Vec::new(); let contract_class_cache = { - let mut contract_class_cache = ContractClassCache::new(); + let mut contract_class_cache = HashMap::new(); for (class_hash, contract_path, contract_address) in extra_contracts { let contract_class = ContractClass::from_path(contract_path) .expect("Could not load extra contract from JSON"); - contract_class_cache.insert(class_hash, contract_class.clone()); + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class.clone())), + ); if let Some((contract_address, data)) = contract_address { storage_entries.extend(data.into_iter().map(|(name, value)| { @@ -89,15 +92,16 @@ fn test_contract<'a>( state_reader .address_to_class_hash_mut() .insert(contract_address.clone(), class_hash); - state_reader - .class_hash_to_contract_class_mut() - .insert(class_hash, contract_class.clone()); + state_reader.class_hash_to_compiled_class_mut().insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class.clone())), + ); } } - Some(contract_class_cache) + contract_class_cache }; - let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache, None); + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); storage_entries .into_iter() .for_each(|(a, b, c)| state.set_storage_at(&(a, b), c)); From e7ad24d2c50348f8699dbfc9e3daa23c00691118 Mon Sep 17 00:00:00 2001 From: Juan Bono Date: Wed, 30 Aug 2023 17:54:54 -0300 Subject: [PATCH 08/44] Update README with Telegram group link and badge (#843) * Update README.md * add link to tg group --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1dd623fad..1b754db81 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ### 🦀 Starknet in Rust 🦀 -Starknet library in Rust, featuring [⚡cairo-vm⚡](https://github.com/lambdaclass/cairo-vm) +Starknet transaction execution library in Rust, featuring [⚡cairo-vm⚡](https://github.com/lambdaclass/cairo-vm) [Report Bug](https://github.com/lambdaclass/starknet_in_rust/issues/new?labels=bug&title=bug%3A+) · [Request Feature](https://github.com/lambdaclass/starknet_in_rust/issues/new?labels=enhancement&title=feat%3A+) @@ -13,8 +13,8 @@ Starknet library in Rust, featuring [⚡cairo-vm⚡](https://github.com/lambdacl [![Telegram Chat][tg-badge]][tg-url] [pr-welcome]: https://img.shields.io/static/v1?color=orange&label=PRs&style=flat&message=welcome -[tg-badge]: https://img.shields.io/static/v1?color=green&logo=telegram&label=chat&style=flat&message=join -[tg-url]: https://t.me/starknet_rs +[tg-badge]: https://img.shields.io/endpoint?url=https%3A%2F%2Ftg.sumanjay.workers.dev%2FLambdaStarkNet%2F&logo=telegram&label=chat&color=neon +[tg-url]: https://t.me/LambdaStarkNet From 05c0efe4c2b805967f0c8b03198c5358f1b615a6 Mon Sep 17 00:00:00 2001 From: mmsc2 <88055861+mmsc2@users.noreply.github.com> Date: Wed, 30 Aug 2023 20:39:17 -0300 Subject: [PATCH 09/44] From/TryFrom starknet api types (#962) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * From/TryFrom starknet api types * Add deploy account * Modify gitignore * Deploy account and invoke function * Change into_iter to iter * Update .gitignore Co-authored-by: fmoletta <99273364+fmoletta@users.noreply.github.com> * change to try_from * Move functions to its respective files * Test * Delete test * Fix format * Fix test --------- Co-authored-by: Juan Bono Co-authored-by: fmoletta <99273364+fmoletta@users.noreply.github.com> Co-authored-by: Estéfano Bargas --- .gitignore | 1 + Cargo.lock | 28 +----- Cargo.toml | 2 +- .../deprecated_contract_class.rs | 52 +++++------ src/transaction/deploy_account.rs | 45 +++++++++ src/transaction/invoke_function.rs | 93 ++++++++++++++++++- 6 files changed, 166 insertions(+), 55 deletions(-) diff --git a/.gitignore b/.gitignore index 3e25dca32..abb8b256d 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,4 @@ lcov.info .rusty-hook.toml !/starknet_programs/raw_contract_classes/*.json cairo-*.tar +starknet-pypy-env/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index fbf90ed9e..6b5dc8f09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -691,7 +691,7 @@ dependencies = [ "serde_json", "sha3", "starknet-crypto 0.5.1", - "starknet_api 0.4.1", + "starknet_api", "strum", "strum_macros", "thiserror", @@ -1889,7 +1889,7 @@ dependencies = [ "honggfuzz", "num-traits 0.2.16", "serde_json", - "starknet_api 0.3.0", + "starknet_api", "starknet_in_rust", "tempfile", ] @@ -3118,7 +3118,7 @@ dependencies = [ "serde_json", "serde_with 3.1.0", "starknet", - "starknet_api 0.3.0", + "starknet_api", "starknet_in_rust", "thiserror", "ureq", @@ -3138,7 +3138,7 @@ dependencies = [ "serde_json", "serde_with 3.1.0", "starknet", - "starknet_api 0.4.1", + "starknet_api", "thiserror", "ureq", ] @@ -3779,24 +3779,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "starknet_api" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfe4732113f66de3d6e9fc77f713b934cfd4b24d43887ca8cbfbe9462ed9119" -dependencies = [ - "cairo-lang-starknet", - "derive_more", - "hex", - "indexmap 1.9.3", - "once_cell", - "primitive-types", - "serde", - "serde_json", - "starknet-crypto 0.5.1", - "thiserror", -] - [[package]] name = "starknet_api" version = "0.4.1" @@ -3845,7 +3827,7 @@ dependencies = [ "sha3", "starknet", "starknet-crypto 0.5.1", - "starknet_api 0.3.0", + "starknet_api", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index c4ef535b6..b4552d465 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ members = ["cli", "fuzzer", "rpc_state_reader", "rpc_state_reader_sn_api"] [workspace.dependencies] cairo-vm = { version = "0.8.5", features = ["cairo-1-hints"] } -starknet_api = "0.3.0" +starknet_api = "0.4.1" num-traits = "0.2.15" starknet = "0.5.0" thiserror = "1.0.32" diff --git a/src/services/api/contract_classes/deprecated_contract_class.rs b/src/services/api/contract_classes/deprecated_contract_class.rs index 2736bbca4..a1ef5c367 100644 --- a/src/services/api/contract_classes/deprecated_contract_class.rs +++ b/src/services/api/contract_classes/deprecated_contract_class.rs @@ -265,9 +265,7 @@ mod tests { felt::{felt_str, PRIME_STR}, serde::deserialize_program::BuiltinName, }; - use starknet_api::deprecated_contract_class::{ - FunctionAbiEntry, FunctionAbiEntryType, FunctionAbiEntryWithType, TypedParameter, - }; + use starknet_api::deprecated_contract_class::{FunctionAbiEntry, TypedParameter}; #[test] fn deserialize_contract_class() { @@ -333,34 +331,28 @@ mod tests { // This specific contract compiles with --no_debug_info let res = ContractClass::from_path("starknet_programs/fibonacci.json"); let contract_class = res.expect("should be able to read file"); - - let expected_abi = Some(vec![ContractClassAbiEntry::Function( - FunctionAbiEntryWithType { - r#type: FunctionAbiEntryType::Function, - entry: FunctionAbiEntry { - name: "fib".to_string(), - inputs: vec![ - TypedParameter { - name: "first_element".to_string(), - r#type: "felt".to_string(), - }, - TypedParameter { - name: "second_element".to_string(), - r#type: "felt".to_string(), - }, - TypedParameter { - name: "n".to_string(), - r#type: "felt".to_string(), - }, - ], - outputs: vec![TypedParameter { - name: "res".to_string(), - r#type: "felt".to_string(), - }], - state_mutability: None, + let expected_abi = Some(vec![ContractClassAbiEntry::Function(FunctionAbiEntry { + name: "fib".to_string(), + inputs: vec![ + TypedParameter { + name: "first_element".to_string(), + r#type: "felt".to_string(), + }, + TypedParameter { + name: "second_element".to_string(), + r#type: "felt".to_string(), + }, + TypedParameter { + name: "n".to_string(), + r#type: "felt".to_string(), }, - }, - )]); + ], + outputs: vec![TypedParameter { + name: "res".to_string(), + r#type: "felt".to_string(), + }], + state_mutability: None, + })]); assert_eq!(contract_class.abi, expected_abi); } diff --git a/src/transaction/deploy_account.rs b/src/transaction/deploy_account.rs index eccb34117..44d03785d 100644 --- a/src/transaction/deploy_account.rs +++ b/src/transaction/deploy_account.rs @@ -383,6 +383,51 @@ impl DeployAccount { } } +// ---------------------------------- +// Try from starknet api +// ---------------------------------- + +impl TryFrom for DeployAccount { + type Error = SyscallHandlerError; + + fn try_from( + value: starknet_api::transaction::DeployAccountTransaction, + ) -> Result { + let max_fee = value.max_fee.0; + let version = Felt252::from_bytes_be(value.version.0.bytes()); + let nonce = Felt252::from_bytes_be(value.nonce.0.bytes()); + let class_hash: [u8; 32] = value.class_hash.0.bytes().try_into().unwrap(); + let contract_address_salt = Felt252::from_bytes_be(value.contract_address_salt.0.bytes()); + + let signature = value + .signature + .0 + .iter() + .map(|f| Felt252::from_bytes_be(f.bytes())) + .collect(); + let constructor_calldata = value + .constructor_calldata + .0 + .as_ref() + .iter() + .map(|f| Felt252::from_bytes_be(f.bytes())) + .collect(); + + let chain_id = Felt252::zero(); + + DeployAccount::new( + class_hash, + max_fee, + version, + nonce, + constructor_calldata, + signature, + contract_address_salt, + chain_id, + ) + } +} + #[cfg(test)] mod tests { use std::{collections::HashMap, path::PathBuf, sync::Arc}; diff --git a/src/transaction/invoke_function.rs b/src/transaction/invoke_function.rs index ef707f510..f532cd04b 100644 --- a/src/transaction/invoke_function.rs +++ b/src/transaction/invoke_function.rs @@ -20,7 +20,7 @@ use crate::{ use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; use cairo_vm::felt::Felt252; use getset::Getters; -use num_traits::Zero; +use num_traits::{One, Zero}; use super::{fee::charge_fee, Transaction}; @@ -397,6 +397,97 @@ pub(crate) fn preprocess_invoke_function_fields( } } +// ---------------------------------- +// Try from starknet api +// ---------------------------------- + +fn convert_invoke_v0( + value: starknet_api::transaction::InvokeTransactionV0, +) -> Result { + let contract_address = Address(Felt252::from_bytes_be( + value.contract_address.0.key().bytes(), + )); + let max_fee = value.max_fee.0; + let entry_point_selector = Felt252::from_bytes_be(value.entry_point_selector.0.bytes()); + let version = Felt252::zero(); + let nonce = None; + let chain_id = Felt252::zero(); + + let signature = value + .signature + .0 + .iter() + .map(|f| Felt252::from_bytes_be(f.bytes())) + .collect(); + let calldata = value + .calldata + .0 + .as_ref() + .iter() + .map(|f| Felt252::from_bytes_be(f.bytes())) + .collect(); + + InvokeFunction::new( + contract_address, + entry_point_selector, + max_fee, + version, + calldata, + signature, + chain_id, + nonce, + ) +} + +fn convert_invoke_v1( + value: starknet_api::transaction::InvokeTransactionV1, +) -> Result { + let contract_address = Address(Felt252::from_bytes_be(value.sender_address.0.key().bytes())); + let max_fee = value.max_fee.0; + let version = Felt252::one(); + let nonce = Felt252::from_bytes_be(value.nonce.0.bytes()); + let chain_id = Felt252::zero(); + let entry_point_selector = EXECUTE_ENTRY_POINT_SELECTOR.clone(); + + let signature = value + .signature + .0 + .iter() + .map(|f| Felt252::from_bytes_be(f.bytes())) + .collect(); + let calldata = value + .calldata + .0 + .as_ref() + .iter() + .map(|f| Felt252::from_bytes_be(f.bytes())) + .collect(); + + InvokeFunction::new( + contract_address, + entry_point_selector, + max_fee, + version, + calldata, + signature, + chain_id, + Some(nonce), + ) +} + +impl TryFrom for InvokeFunction { + type Error = TransactionError; + + fn try_from( + value: starknet_api::transaction::InvokeTransaction, + ) -> Result { + match value { + starknet_api::transaction::InvokeTransaction::V0(v0) => convert_invoke_v0(v0), + starknet_api::transaction::InvokeTransaction::V1(v1) => convert_invoke_v1(v1), + } + } +} + #[cfg(test)] mod tests { use super::*; From 27ffa5db6f7beca56b8c221e38adff5736270ac7 Mon Sep 17 00:00:00 2001 From: MrAzteca Date: Thu, 31 Aug 2023 18:32:17 +0200 Subject: [PATCH 10/44] Fix gas/fee price type consistency (to `u128`). (#987) --- rpc_state_reader/src/lib.rs | 4 ++-- src/definitions/constants.rs | 2 +- src/state/mod.rs | 2 +- tests/internals.rs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rpc_state_reader/src/lib.rs b/rpc_state_reader/src/lib.rs index 254b26b00..647ab5fa9 100644 --- a/rpc_state_reader/src/lib.rs +++ b/rpc_state_reader/src/lib.rs @@ -341,7 +341,7 @@ impl RpcState { .to_string() .parse::() .unwrap(), - gas_price: *starknet_os_config.gas_price() as u64, + gas_price: *starknet_os_config.gas_price(), sequencer_address: starknet_os_config.fee_token_address().clone(), } } @@ -569,7 +569,7 @@ mod tests { .to_string() .parse::() .unwrap(), - gas_price: gas_price_u128 as u64, + gas_price: gas_price_u128, sequencer_address: fee_token_address, }; diff --git a/src/definitions/constants.rs b/src/definitions/constants.rs index bcd2a257e..cbf706d01 100644 --- a/src/definitions/constants.rs +++ b/src/definitions/constants.rs @@ -82,7 +82,7 @@ pub static ref DECLARE_VERSION: Felt252 = 2.into(); pub static ref TRANSACTION_VERSION: Felt252 = 1.into(); } -pub const DEFAULT_GAS_PRICE: u64 = 100_000_000_000; // 100 * 10**9 +pub const DEFAULT_GAS_PRICE: u128 = 100_000_000_000; // 100 * 10**9 pub const DEFAULT_CONTRACT_STORAGE_COMMITMENT_TREE_HEIGHT: u64 = 251; pub const DEFAULT_GLOBAL_STATE_COMMITMENT_TREE_HEIGHT: u64 = 251; pub const DEFAULT_INVOKE_TX_MAX_N_STEPS: u64 = 1000000; diff --git a/src/state/mod.rs b/src/state/mod.rs index 3920165a8..05b40f91f 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -29,7 +29,7 @@ pub struct BlockInfo { /// Timestamp of the beginning of the last block creation attempt. pub block_timestamp: u64, /// L1 gas price (in Wei) measured at the beginning of the last block creation attempt. - pub gas_price: u64, + pub gas_price: u128, /// The sequencer address of this block. pub sequencer_address: Address, } diff --git a/tests/internals.rs b/tests/internals.rs index 94f845e36..2611784d9 100644 --- a/tests/internals.rs +++ b/tests/internals.rs @@ -418,7 +418,7 @@ fn expected_validate_call_info( fn expected_fee_transfer_call_info( block_context: &BlockContext, account_address: &Address, - actual_fee: u64, + actual_fee: u128, ) -> CallInfo { CallInfo { entry_point_type: EntryPointType::External.into(), @@ -1502,7 +1502,7 @@ fn test_deploy_account() { let expected_fee_transfer_call_info = expected_fee_transfer_call_info( &block_context, deploy_account_tx.contract_address(), - expected_fee as u64, + expected_fee, ); let resources = HashMap::from([ From 8cfd3b594279f0dffd32e53cd40af3e67fb8edf3 Mon Sep 17 00:00:00 2001 From: fmoletta <99273364+fmoletta@users.noreply.github.com> Date: Fri, 1 Sep 2023 17:08:21 +0300 Subject: [PATCH 11/44] Fix `ExecutionResources::increment_syscall_counter` (#971) * Fix increment_syscall_counter * Add test + fix test * Fix test * Fix tests * fmt --- src/lib.rs | 2 +- src/state/mod.rs | 25 ++++++++++++++++++------- src/transaction/l1_handler.rs | 2 +- tests/deploy_account.rs | 4 ++-- tests/internals.rs | 10 +++++----- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1b9a441e6..b8773231d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -392,7 +392,7 @@ mod test { block_context.starknet_os_config.gas_price = 1; let estimated_fee = estimate_message_fee(&l1_handler, state, &block_context).unwrap(); - assert_eq!(estimated_fee, (19708, 19695)); + assert_eq!(estimated_fee, (19709, 19695)); } #[test] diff --git a/src/state/mod.rs b/src/state/mod.rs index 05b40f91f..a8eb3acbe 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -89,10 +89,11 @@ impl ExecutionResourcesManager { } } - pub fn increment_syscall_counter(&mut self, syscall_name: &str, amount: u64) -> Option<()> { - self.syscall_counter - .get_mut(syscall_name) - .map(|val| *val += amount) + pub fn increment_syscall_counter(&mut self, syscall_name: &str, amount: u64) { + *self + .syscall_counter + .entry(syscall_name.to_string()) + .or_default() += amount } pub fn get_syscall_counter(&self, syscall_name: &str) -> Option { @@ -294,9 +295,7 @@ mod test { Default::default(), ); - execution_resources_manager - .increment_syscall_counter("syscall1", 1) - .unwrap(); + execution_resources_manager.increment_syscall_counter("syscall1", 1); assert_eq!( execution_resources_manager.get_syscall_counter("syscall1"), @@ -308,6 +307,18 @@ mod test { ); } + #[test] + fn execution_resources_manager_should_add_syscall_if_not_present() { + let mut execution_resources_manager = super::ExecutionResourcesManager::default(); + + execution_resources_manager.increment_syscall_counter("syscall1", 1); + + assert_eq!( + execution_resources_manager.get_syscall_counter("syscall1"), + Some(1) + ); + } + #[test] fn state_diff_to_cached_state_should_return_correct_cached_state() { let mut state_reader = InMemoryStateReader::default(); diff --git a/src/transaction/l1_handler.rs b/src/transaction/l1_handler.rs index 4f84c910d..4f051651e 100644 --- a/src/transaction/l1_handler.rs +++ b/src/transaction/l1_handler.rs @@ -336,7 +336,7 @@ mod test { fee_transfer_info: None, actual_fee: 0, actual_resources: HashMap::from([ - ("n_steps".to_string(), 1229), + ("n_steps".to_string(), 1319), ("pedersen_builtin".to_string(), 13), ("range_check_builtin".to_string(), 23), ("l1_gas_usage".to_string(), 19695), diff --git a/tests/deploy_account.rs b/tests/deploy_account.rs index 6da3256af..70af6ea6d 100644 --- a/tests/deploy_account.rs +++ b/tests/deploy_account.rs @@ -171,11 +171,11 @@ fn internal_deploy_account_cairo1() { let n_steps; #[cfg(not(feature = "cairo_1_tests"))] { - n_steps = 3873; + n_steps = 3948; } #[cfg(feature = "cairo_1_tests")] { - n_steps = 3877; + n_steps = 3952; } assert_eq!( diff --git a/tests/internals.rs b/tests/internals.rs index 2611784d9..3159d3c48 100644 --- a/tests/internals.rs +++ b/tests/internals.rs @@ -1224,10 +1224,10 @@ fn expected_fib_validate_call_info_2() -> CallInfo { fn expected_transaction_execution_info(block_context: &BlockContext) -> TransactionExecutionInfo { let resources = HashMap::from([ - ("n_steps".to_string(), 3445), + ("n_steps".to_string(), 4135), ("pedersen_builtin".to_string(), 16), ("l1_gas_usage".to_string(), 2448), - ("range_check_builtin".to_string(), 82), + ("range_check_builtin".to_string(), 101), ]); let fee = calculate_tx_fee(&resources, *GAS_PRICE, block_context).unwrap(); TransactionExecutionInfo::new( @@ -1247,17 +1247,17 @@ fn expected_fib_transaction_execution_info( let n_steps; #[cfg(not(feature = "cairo_1_tests"))] { - n_steps = 3541; + n_steps = 4231; } #[cfg(feature = "cairo_1_tests")] { - n_steps = 3544; + n_steps = 4234; } let resources = HashMap::from([ ("n_steps".to_string(), n_steps), ("l1_gas_usage".to_string(), 7344), ("pedersen_builtin".to_string(), 16), - ("range_check_builtin".to_string(), 85), + ("range_check_builtin".to_string(), 104), ]); let fee = calculate_tx_fee(&resources, *GAS_PRICE, block_context).unwrap(); TransactionExecutionInfo::new( From d939ece53a190491bcd5c90964dfd88fa23752b4 Mon Sep 17 00:00:00 2001 From: Edgar Date: Fri, 1 Sep 2023 16:12:06 +0200 Subject: [PATCH 12/44] minor code cleanup (#968) --- .../deprecated_contract_address.rs | 3 +-- src/definitions/block_context.rs | 4 ++-- src/execution/gas_usage.rs | 4 ++-- src/execution/mod.rs | 4 ++-- src/hash_utils.rs | 6 +++--- src/runner/mod.rs | 2 +- .../deprecated_contract_class.rs | 2 +- src/state/in_memory_state_reader.rs | 4 ++-- src/state/mod.rs | 8 ++++---- src/state/state_cache.rs | 4 ++-- src/syscalls/business_logic_syscall_handler.rs | 4 ++-- ...eprecated_business_logic_syscall_handler.rs | 4 ++-- src/syscalls/deprecated_syscall_response.rs | 18 +++++++++--------- src/syscalls/syscall_response.rs | 8 ++++---- src/transaction/deploy.rs | 4 ++-- src/transaction/invoke_function.rs | 4 +--- src/utils.rs | 2 -- 17 files changed, 40 insertions(+), 45 deletions(-) diff --git a/src/core/contract_address/deprecated_contract_address.rs b/src/core/contract_address/deprecated_contract_address.rs index 9b5b2ccfb..325902d45 100644 --- a/src/core/contract_address/deprecated_contract_address.rs +++ b/src/core/contract_address/deprecated_contract_address.rs @@ -169,7 +169,6 @@ impl serde_json::ser::Formatter for PythonDefaultFormatter { #[derive(serde::Deserialize, serde::Serialize)] #[serde(deny_unknown_fields)] - pub struct CairoContractDefinition<'a> { /// Contract ABI, which has no schema definition. pub abi: serde_json::Value, @@ -257,7 +256,7 @@ pub(crate) fn compute_hinted_class_hash( None => {} } // We don't know what this type is supposed to be, but if its missing it is null. - if let Some(serde_json::Value::Null) = vals.get_mut("flow_tracking_data") { + if vals.get("flow_tracking_data") == Some(&serde_json::Value::Null) { vals.remove("flow_tracking_data"); } diff --git a/src/definitions/block_context.rs b/src/definitions/block_context.rs index 2e8ffc9b6..2ac680271 100644 --- a/src/definitions/block_context.rs +++ b/src/definitions/block_context.rs @@ -85,7 +85,7 @@ impl StarknetOsConfig { /// * `chain_id` - [`Felt252`] of the configured chain. /// * `fee_token_address` - Address of the token used when paying fees. /// * `gas_price` - Price of gas. - pub fn new(chain_id: Felt252, fee_token_address: Address, gas_price: u128) -> Self { + pub const fn new(chain_id: Felt252, fee_token_address: Address, gas_price: u128) -> Self { StarknetOsConfig { chain_id, fee_token_address, @@ -139,7 +139,7 @@ impl BlockContext { /// Example: for block number 6351, this includes the blocks 5327, 5328, ..., 6340, 6341. /// * `enforce_l1_handler_fee` - Whether to enforce the L1 handler fee. #[allow(clippy::too_many_arguments)] - pub fn new( + pub const fn new( starknet_os_config: StarknetOsConfig, contract_storage_commitment_tree_height: u64, global_state_commitment_tree_height: u64, diff --git a/src/execution/gas_usage.rs b/src/execution/gas_usage.rs index b61419c48..f0d254dc7 100644 --- a/src/execution/gas_usage.rs +++ b/src/execution/gas_usage.rs @@ -105,7 +105,7 @@ pub fn get_message_segment_lenght( /// # Returns: /// /// The on-chain data segment length -pub fn get_onchain_data_segment_length( +pub const fn get_onchain_data_segment_length( n_modified_contracts: usize, n_storage_changes: usize, n_deployments: usize, @@ -159,7 +159,7 @@ pub fn get_log_message_to_l1_emissions_cost(l2_to_l1_messages: &[L2toL1MessageIn /// # Returns: /// /// The cost of event emissions. -pub fn get_event_emission_cost(topics: usize, l1_handler_payload_size: usize) -> usize { +pub const fn get_event_emission_cost(topics: usize, l1_handler_payload_size: usize) -> usize { GAS_PER_LOG + (topics + N_DEFAULT_TOPICS) * GAS_PER_LOG_TOPIC + l1_handler_payload_size * GAS_PER_LOG_DATA_WORD diff --git a/src/execution/mod.rs b/src/execution/mod.rs index 8a6fd6837..4acaf3fbe 100644 --- a/src/execution/mod.rs +++ b/src/execution/mod.rs @@ -494,7 +494,7 @@ pub struct TransactionExecutionInfo { } impl TransactionExecutionInfo { - pub fn new( + pub const fn new( validate_info: Option, call_info: Option, revert_error: Option, @@ -553,7 +553,7 @@ impl TransactionExecutionInfo { } } - pub fn new_without_fee_info( + pub const fn new_without_fee_info( validate_info: Option, call_info: Option, revert_error: Option, diff --git a/src/hash_utils.rs b/src/hash_utils.rs index 70da1526c..596ff1de6 100644 --- a/src/hash_utils.rs +++ b/src/hash_utils.rs @@ -125,9 +125,9 @@ pub fn compute_hash_on_elements(vec: &[Felt252]) -> Result { let felt_result = felt_vec .into_iter() .reduce(|x, y| pedersen_hash(&x, &y)) - .ok_or(HashError::FailedToComputeHash( - "Failed to compute Pedersen hash.".to_string(), - ))?; + .ok_or_else(|| { + HashError::FailedToComputeHash("Failed to compute Pedersen hash.".to_string()) + })?; let result = Felt252::from_bytes_be(&felt_result.to_bytes_be()); Ok(result) diff --git a/src/runner/mod.rs b/src/runner/mod.rs index 4788a49f5..c5e86702c 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -69,7 +69,7 @@ impl StarknetRunner where H: HintProcessor + HintProcessorPostRun, { - pub fn new(cairo_runner: CairoRunner, vm: VirtualMachine, hint_processor: H) -> Self { + pub const fn new(cairo_runner: CairoRunner, vm: VirtualMachine, hint_processor: H) -> Self { StarknetRunner { cairo_runner, vm, diff --git a/src/services/api/contract_classes/deprecated_contract_class.rs b/src/services/api/contract_classes/deprecated_contract_class.rs index a1ef5c367..f2ede7801 100644 --- a/src/services/api/contract_classes/deprecated_contract_class.rs +++ b/src/services/api/contract_classes/deprecated_contract_class.rs @@ -36,7 +36,7 @@ pub struct ContractEntryPoint { } impl ContractEntryPoint { - pub fn new(selector: Felt252, offset: usize) -> ContractEntryPoint { + pub const fn new(selector: Felt252, offset: usize) -> ContractEntryPoint { ContractEntryPoint { selector, offset } } } diff --git a/src/state/in_memory_state_reader.rs b/src/state/in_memory_state_reader.rs index 7a7f1c372..2d6a001f7 100644 --- a/src/state/in_memory_state_reader.rs +++ b/src/state/in_memory_state_reader.rs @@ -15,7 +15,7 @@ use std::collections::HashMap; /// /// This implementation is used for testing and debugging. /// It uses HashMaps to store the data. -#[derive(Debug, MutGetters, Getters, PartialEq, Clone, Default)] +#[derive(Debug, MutGetters, Getters, PartialEq, Eq, Clone, Default)] pub struct InMemoryStateReader { #[getset(get_mut = "pub")] pub address_to_class_hash: HashMap, @@ -39,7 +39,7 @@ impl InMemoryStateReader { /// - `class_hash_to_contract_class` - A HashMap from class hashes to their contract classes. /// - `casm_contract_classes` - A [CasmClassCache]. /// - `class_hash_to_compiled_class_hash` - A HashMap from class hashes to their compiled class hashes. - pub fn new( + pub const fn new( address_to_class_hash: HashMap, address_to_nonce: HashMap, address_to_storage: HashMap, diff --git a/src/state/mod.rs b/src/state/mod.rs index a8eb3acbe..33f8ab5db 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -35,7 +35,7 @@ pub struct BlockInfo { } impl BlockInfo { - pub fn empty(sequencer_address: Address) -> Self { + pub const fn empty(sequencer_address: Address) -> Self { BlockInfo { block_number: 0, // To do: In cairo-lang, this value is set to -1 block_timestamp: 0, @@ -44,7 +44,7 @@ impl BlockInfo { } } - pub fn validate_legal_progress( + pub const fn validate_legal_progress( &self, next_block_info: &BlockInfo, ) -> Result<(), TransactionError> { @@ -103,7 +103,7 @@ impl ExecutionResourcesManager { } } -#[derive(Default, Clone, PartialEq, Debug, Getters)] +#[derive(Default, Clone, PartialEq, Eq, Debug, Getters)] #[getset(get = "pub")] pub struct StateDiff { pub(crate) address_to_class_hash: HashMap, @@ -113,7 +113,7 @@ pub struct StateDiff { } impl StateDiff { - pub fn new( + pub const fn new( address_to_class_hash: HashMap, address_to_nonce: HashMap, class_hash_to_compiled_class: HashMap, diff --git a/src/state/state_cache.rs b/src/state/state_cache.rs index 03efa1774..2b5876015 100644 --- a/src/state/state_cache.rs +++ b/src/state/state_cache.rs @@ -41,7 +41,7 @@ impl StateCache { #[allow(clippy::too_many_arguments)] /// Create a new StateCache with given initial and written values for testing - pub fn new( + pub const fn new( class_hash_initial_values: HashMap, compiled_class_hash_initial_values: HashMap, nonce_initial_values: HashMap, @@ -82,7 +82,7 @@ impl StateCache { /// Creates a new instance of `StateCache` for testing purposes with the provided initial values and writes. #[allow(clippy::too_many_arguments)] - pub fn new_for_testing( + pub const fn new_for_testing( class_hash_initial_values: HashMap, compiled_class_hash_initial_values: HashMap, nonce_initial_values: HashMap, diff --git a/src/syscalls/business_logic_syscall_handler.rs b/src/syscalls/business_logic_syscall_handler.rs index 61baaf6aa..095d2ad21 100644 --- a/src/syscalls/business_logic_syscall_handler.rs +++ b/src/syscalls/business_logic_syscall_handler.rs @@ -258,7 +258,7 @@ impl<'a, S: StateReader> BusinessLogicSyscallHandler<'a, S> { .map_err(|err| SyscallHandlerError::ExecutionError(err.to_string()))?; let call_info = call_info.ok_or(SyscallHandlerError::ExecutionError( - revert_error.unwrap_or("Execution error".to_string()), + revert_error.unwrap_or_else(|| "Execution error".to_string()), ))?; let retdata_maybe_reloc = call_info @@ -376,7 +376,7 @@ impl<'a, S: StateReader> BusinessLogicSyscallHandler<'a, S> { .map_err(|_| StateError::ExecutionEntryPoint())?; let call_info = call_info.ok_or(StateError::CustomError( - revert_error.unwrap_or("Execution error".to_string()), + revert_error.unwrap_or_else(|| "Execution error".to_string()), ))?; self.internal_calls.push(call_info.clone()); diff --git a/src/syscalls/deprecated_business_logic_syscall_handler.rs b/src/syscalls/deprecated_business_logic_syscall_handler.rs index 3187b1e02..1de042db5 100644 --- a/src/syscalls/deprecated_business_logic_syscall_handler.rs +++ b/src/syscalls/deprecated_business_logic_syscall_handler.rs @@ -483,7 +483,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { .map_err(|e| SyscallHandlerError::ExecutionError(e.to_string()))?; let call_info = call_info.ok_or(SyscallHandlerError::ExecutionError( - revert_error.unwrap_or("Execution error".to_string()), + revert_error.unwrap_or_else(|| "Execution error".to_string()), ))?; let retdata = call_info.retdata.clone(); @@ -493,7 +493,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { } /// Returns the block information associated with the current context. - pub(crate) fn get_block_info(&self) -> &BlockInfo { + pub(crate) const fn get_block_info(&self) -> &BlockInfo { &self.block_context.block_info } diff --git a/src/syscalls/deprecated_syscall_response.rs b/src/syscalls/deprecated_syscall_response.rs index bc7d3523f..79fbe4be2 100644 --- a/src/syscalls/deprecated_syscall_response.rs +++ b/src/syscalls/deprecated_syscall_response.rs @@ -60,7 +60,7 @@ pub(crate) struct DeprecatedGetBlockNumberResponse { } impl DeprecatedCallContractResponse { - pub(crate) fn new(retdata_size: usize, retdata: Relocatable) -> Self { + pub(crate) const fn new(retdata_size: usize, retdata: Relocatable) -> Self { Self { retdata_size, retdata, @@ -86,19 +86,19 @@ pub(crate) struct DeprecatedDeployResponse { } impl DeprecatedGetTxInfoResponse { - pub fn new(tx_info: Relocatable) -> Self { + pub const fn new(tx_info: Relocatable) -> Self { DeprecatedGetTxInfoResponse { tx_info } } } impl DeprecatedGetBlockTimestampResponse { - pub(crate) fn new(block_timestamp: u64) -> Self { + pub(crate) const fn new(block_timestamp: u64) -> Self { DeprecatedGetBlockTimestampResponse { block_timestamp } } } impl DeprecatedGetSequencerAddressResponse { - pub(crate) fn new(sequencer_address: Address) -> Self { + pub(crate) const fn new(sequencer_address: Address) -> Self { Self { sequencer_address } } } @@ -111,7 +111,7 @@ impl DeprecatedGetCallerAddressResponse { } impl DeprecatedGetTxSignatureResponse { - pub fn new(signature: Relocatable, signature_len: usize) -> Self { + pub const fn new(signature: Relocatable, signature_len: usize) -> Self { DeprecatedGetTxSignatureResponse { signature, signature_len, @@ -119,24 +119,24 @@ impl DeprecatedGetTxSignatureResponse { } } impl DeprecatedGetContractAddressResponse { - pub fn new(contract_address: Address) -> Self { + pub const fn new(contract_address: Address) -> Self { DeprecatedGetContractAddressResponse { contract_address } } } impl DeprecatedStorageReadResponse { - pub fn new(value: Felt252) -> Self { + pub const fn new(value: Felt252) -> Self { DeprecatedStorageReadResponse { value } } } impl DeprecatedGetBlockNumberResponse { - pub(crate) fn new(block_number: u64) -> Self { + pub(crate) const fn new(block_number: u64) -> Self { Self { block_number } } } impl DeprecatedDeployResponse { - pub(crate) fn new( + pub(crate) const fn new( contract_address: Felt252, constructor_retdata_size: Felt252, constructor_retdata: Relocatable, diff --git a/src/syscalls/syscall_response.rs b/src/syscalls/syscall_response.rs index d8e39ae2c..da61935d8 100644 --- a/src/syscalls/syscall_response.rs +++ b/src/syscalls/syscall_response.rs @@ -76,7 +76,7 @@ impl SyscallResponse { // ---------------------- /// Represents the response of get_block_timestamp syscall. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct GetBlockTimestampResponse { /// The block timestamp. pub timestamp: Felt252, @@ -104,7 +104,7 @@ pub struct FailureReason { } /// Represents the response of call_contract syscall -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct CallContractResponse { /// The retdata segment start. pub retdata_start: Relocatable, @@ -113,14 +113,14 @@ pub struct CallContractResponse { } /// Represents the response of get_block_hash syscall -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct GetBlockHashResponse { /// The returned hash. pub block_hash: Felt252, } /// Represents the response of the `keccak` syscall -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct KeccakResponse { /// The returned hash. pub hash_low: Felt252, diff --git a/src/transaction/deploy.rs b/src/transaction/deploy.rs index b65e8559e..0c14512c7 100644 --- a/src/transaction/deploy.rs +++ b/src/transaction/deploy.rs @@ -125,7 +125,7 @@ impl Deploy { } /// Returns the class hash of the deployed contract - pub fn class_hash(&self) -> ClassHash { + pub const fn class_hash(&self) -> ClassHash { self.contract_hash } @@ -351,7 +351,7 @@ mod tests { class_hash_bytes ); - let storage_key = calculate_sn_keccak("owner".as_bytes()); + let storage_key = calculate_sn_keccak(b"owner"); assert_eq!( state diff --git a/src/transaction/invoke_function.rs b/src/transaction/invoke_function.rs index f532cd04b..e430fb39d 100644 --- a/src/transaction/invoke_function.rs +++ b/src/transaction/invoke_function.rs @@ -1174,9 +1174,7 @@ mod tests { fn test_reverted_transaction_wrong_entry_point() { let internal_invoke_function = InvokeFunction { contract_address: Address(0.into()), - entry_point_selector: Felt252::from_bytes_be(&calculate_sn_keccak( - "factorial_".as_bytes(), - )), + entry_point_selector: Felt252::from_bytes_be(&calculate_sn_keccak(b"factorial_")), entry_point_type: EntryPointType::External, calldata: vec![], tx_type: TransactionType::InvokeFunction, diff --git a/src/utils.rs b/src/utils.rs index 3f3b32caa..c6d354232 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -585,7 +585,6 @@ mod test { } #[test] - fn subtract_mappings_test() { let mut a = HashMap::new(); let mut b = HashMap::new(); @@ -634,7 +633,6 @@ mod test { } #[test] - fn to_cache_state_storage_mapping_test() { let mut storage: HashMap<(Address, ClassHash), Felt252> = HashMap::new(); let address1: Address = Address(1.into()); From 74b3486bee03a1bb51601f291a2f0338cec0c705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Est=C3=A9fano=20Bargas?= Date: Fri, 1 Sep 2023 12:54:53 -0300 Subject: [PATCH 13/44] Added fee transfer storage update into `count_actual_storage_changes()` (#960) * Add utils fns * Implemented fix * Fix some tests * Fix clippy * Fix tests * Fix test --------- Co-authored-by: Juan Bono --- src/lib.rs | 4 +-- src/state/cached_state.rs | 30 +++++++++++++++--- src/state/state_api.rs | 5 ++- src/testing/state.rs | 2 +- src/transaction/declare.rs | 7 +++-- src/transaction/declare_v2.rs | 5 ++- src/transaction/deploy.rs | 4 +-- src/transaction/deploy_account.rs | 5 ++- src/transaction/invoke_function.rs | 5 ++- src/transaction/l1_handler.rs | 2 +- src/utils.rs | 50 +++++++++++++++++++++++++++++- tests/deploy_account.rs | 4 +-- tests/internals.rs | 12 +++---- 13 files changed, 109 insertions(+), 26 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b8773231d..951dc2377 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -298,7 +298,7 @@ mod test { let transaction = Transaction::InvokeFunction(invoke_function); let estimated_fee = estimate_fee(&[transaction], state, &block_context).unwrap(); - assert_eq!(estimated_fee[0], (2483, 2448)); + assert_eq!(estimated_fee[0], (3707, 3672)); } #[test] @@ -1035,7 +1035,7 @@ mod test { assert_eq!( estimate_fee(&[deploy, invoke_tx], state, block_context,).unwrap(), - [(0, 3672), (0, 2448)] + [(0, 3672), (0, 3672)] ); } diff --git a/src/state/cached_state.rs b/src/state/cached_state.rs index f451d5e97..70b0e8899 100644 --- a/src/state/cached_state.rs +++ b/src/state/cached_state.rs @@ -6,7 +6,10 @@ use crate::{ core::errors::state_errors::StateError, services::api::contract_classes::compiled_class::CompiledClass, state::StateDiff, - utils::{subtract_mappings, to_cache_state_storage_mapping, Address, ClassHash}, + utils::{ + get_erc20_balance_var_addresses, subtract_mappings, to_cache_state_storage_mapping, + Address, ClassHash, + }, }; use cairo_vm::felt::Felt252; use getset::{Getters, MutGetters}; @@ -268,8 +271,11 @@ impl State for CachedState { Ok(()) } - fn count_actual_storage_changes(&mut self) -> (usize, usize) { - let storage_updates = subtract_mappings( + fn count_actual_storage_changes( + &mut self, + fee_token_and_sender_address: Option<(&Address, &Address)>, + ) -> (usize, usize) { + let mut storage_updates = subtract_mappings( self.cache.storage_writes.clone(), self.cache.storage_initial_values.clone(), ); @@ -301,6 +307,16 @@ impl State for CachedState { modified_contracts.len() }; + // Add fee transfer storage update before actually charging it, as it needs to be included in the + // calculation of the final fee. + if let Some((fee_token_address, sender_address)) = fee_token_and_sender_address { + let (sender_low_key, _) = get_erc20_balance_var_addresses(sender_address).unwrap(); + storage_updates.insert( + (fee_token_address.clone(), sender_low_key), + Felt252::default(), + ); + } + (n_modified_contracts, storage_updates.len()) } @@ -705,13 +721,17 @@ mod tests { ((address_two, storage_key_two), Felt252::from(1)), ]); + let fee_token_address = Address(123.into()); + let sender_address = Address(321.into()); + let expected_changes = { - let n_storage_updates = 3; + let n_storage_updates = 3 + 1; // + 1 fee transfer balance update let n_modified_contracts = 2; (n_modified_contracts, n_storage_updates) }; - let changes = cached_state.count_actual_storage_changes(); + let changes = + cached_state.count_actual_storage_changes(Some((&fee_token_address, &sender_address))); assert_eq!(changes, expected_changes); } diff --git a/src/state/state_api.rs b/src/state/state_api.rs index 885eee4be..0a9ee9fb7 100644 --- a/src/state/state_api.rs +++ b/src/state/state_api.rs @@ -54,7 +54,10 @@ pub trait State { fn apply_state_update(&mut self, sate_updates: &StateDiff) -> Result<(), StateError>; /// Counts the amount of modified contracts and the updates to the storage - fn count_actual_storage_changes(&mut self) -> (usize, usize); + fn count_actual_storage_changes( + &mut self, + fee_token_and_sender_address: Option<(&Address, &Address)>, + ) -> (usize, usize); fn get_class_hash_at(&mut self, contract_address: &Address) -> Result; diff --git a/src/testing/state.rs b/src/testing/state.rs index 8158786ce..58aba5d6f 100644 --- a/src/testing/state.rs +++ b/src/testing/state.rs @@ -584,7 +584,7 @@ mod tests { .unwrap(); let actual_resources = HashMap::from([ ("n_steps".to_string(), 3457), - ("l1_gas_usage".to_string(), 2448), + ("l1_gas_usage".to_string(), 3672), ("range_check_builtin".to_string(), 80), ("pedersen_builtin".to_string(), 16), ]); diff --git a/src/transaction/declare.rs b/src/transaction/declare.rs index ce93bc4b1..91dfa5a70 100644 --- a/src/transaction/declare.rs +++ b/src/transaction/declare.rs @@ -168,7 +168,10 @@ impl Declare { } else { self.run_validate_entrypoint(state, &mut resources_manager, block_context)? }; - let changes = state.count_actual_storage_changes(); + let changes = state.count_actual_storage_changes(Some(( + &block_context.starknet_os_config.fee_token_address, + &self.sender_address, + ))); let actual_resources = calculate_tx_resources( resources_manager, &vec![validate_info.clone()], @@ -435,7 +438,7 @@ mod tests { let actual_resources = HashMap::from([ ("n_steps".to_string(), 2715), - ("l1_gas_usage".to_string(), 1224), + ("l1_gas_usage".to_string(), 2448), ("range_check_builtin".to_string(), 63), ("pedersen_builtin".to_string(), 15), ]); diff --git a/src/transaction/declare_v2.rs b/src/transaction/declare_v2.rs index 577c0738b..4c9945f9a 100644 --- a/src/transaction/declare_v2.rs +++ b/src/transaction/declare_v2.rs @@ -320,7 +320,10 @@ impl DeclareV2 { (info, gas) }; - let storage_changes = state.count_actual_storage_changes(); + let storage_changes = state.count_actual_storage_changes(Some(( + &block_context.starknet_os_config.fee_token_address, + &self.sender_address, + ))); let actual_resources = calculate_tx_resources( resources_manager, &[execution_result.call_info.clone()], diff --git a/src/transaction/deploy.rs b/src/transaction/deploy.rs index 0c14512c7..50666ec5a 100644 --- a/src/transaction/deploy.rs +++ b/src/transaction/deploy.rs @@ -182,7 +182,7 @@ impl Deploy { let resources_manager = ExecutionResourcesManager::default(); - let changes = state.count_actual_storage_changes(); + let changes = state.count_actual_storage_changes(None); let actual_resources = calculate_tx_resources( resources_manager, &[Some(call_info.clone())], @@ -245,7 +245,7 @@ impl Deploy { block_context.validate_max_n_steps, )?; - let changes = state.count_actual_storage_changes(); + let changes = state.count_actual_storage_changes(None); let actual_resources = calculate_tx_resources( resources_manager, &[call_info.clone()], diff --git a/src/transaction/deploy_account.rs b/src/transaction/deploy_account.rs index 44d03785d..86ad894a0 100644 --- a/src/transaction/deploy_account.rs +++ b/src/transaction/deploy_account.rs @@ -213,7 +213,10 @@ impl DeployAccount { resources_manager, &[Some(constructor_call_info.clone()), validate_info.clone()], TransactionType::DeployAccount, - state.count_actual_storage_changes(), + state.count_actual_storage_changes(Some(( + &block_context.starknet_os_config.fee_token_address, + &self.contract_address, + ))), None, 0, ) diff --git a/src/transaction/invoke_function.rs b/src/transaction/invoke_function.rs index e430fb39d..471a334a5 100644 --- a/src/transaction/invoke_function.rs +++ b/src/transaction/invoke_function.rs @@ -245,7 +245,10 @@ impl InvokeFunction { remaining_gas, )? }; - let changes = state.count_actual_storage_changes(); + let changes = state.count_actual_storage_changes(Some(( + &block_context.starknet_os_config.fee_token_address, + &self.contract_address, + ))); let actual_resources = calculate_tx_resources( resources_manager, &vec![call_info.clone(), validate_info.clone()], diff --git a/src/transaction/l1_handler.rs b/src/transaction/l1_handler.rs index 4f051651e..10946e0d4 100644 --- a/src/transaction/l1_handler.rs +++ b/src/transaction/l1_handler.rs @@ -128,7 +128,7 @@ impl L1Handler { )? }; - let changes = state.count_actual_storage_changes(); + let changes = state.count_actual_storage_changes(None); let actual_resources = calculate_tx_resources( resources_manager, &[call_info.clone()], diff --git a/src/utils.rs b/src/utils.rs index c6d354232..affc6a726 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -17,11 +17,14 @@ use cairo_vm::{ felt::Felt252, serde::deserialize_program::BuiltinName, vm::runners::builtin_runner, }; use cairo_vm::{types::relocatable::Relocatable, vm::vm_core::VirtualMachine}; +use num_integer::Integer; use num_traits::{Num, ToPrimitive}; use serde::{Deserialize, Serialize}; use serde_json::Value; use sha3::{Digest, Keccak256}; -use starknet_crypto::FieldElement; +use starknet::core::types::FromByteArrayError; +use starknet_api::core::L2_ADDRESS_UPPER_BOUND; +use starknet_crypto::{pedersen_hash, FieldElement}; use std::{ collections::{HashMap, HashSet}, hash::Hash, @@ -270,6 +273,51 @@ where keys1.into_iter().collect() } +/// Returns the storage address of a StarkNet storage variable given its name and arguments. +pub fn get_storage_var_address( + storage_var_name: &str, + args: &[Felt252], +) -> Result { + let felt_to_field_element = |felt: &Felt252| -> Result { + FieldElement::from_bytes_be(&felt.to_be_bytes()) + }; + + let args = args + .iter() + .map(|felt| felt_to_field_element(felt)) + .collect::, _>>()?; + + let storage_var_name_hash = + FieldElement::from_bytes_be(&calculate_sn_keccak(storage_var_name.as_bytes()))?; + let storage_key_hash = args + .iter() + .fold(storage_var_name_hash, |res, arg| pedersen_hash(&res, arg)); + + let storage_key = field_element_to_felt(&storage_key_hash).mod_floor(&Felt252::from_bytes_be( + &L2_ADDRESS_UPPER_BOUND.to_bytes_be(), + )); + + Ok(storage_key) +} + +/// Gets storage keys for a Uint256 storage variable. +pub fn get_uint256_storage_var_addresses( + storage_var_name: &str, + args: &[Felt252], +) -> Result<(Felt252, Felt252), FromByteArrayError> { + let low_key = get_storage_var_address(storage_var_name, args)?; + let high_key = &low_key + &Felt252::from(1); + Ok((low_key, high_key)) +} + +pub fn get_erc20_balance_var_addresses( + contract_address: &Address, +) -> Result<([u8; 32], [u8; 32]), FromByteArrayError> { + let (felt_low, felt_high) = + get_uint256_storage_var_addresses("ERC20_balances", &[contract_address.clone().0])?; + Ok((felt_low.to_be_bytes(), felt_high.to_be_bytes())) +} + //* ---------------------------- //* Execution entry point utils //* ---------------------------- diff --git a/tests/deploy_account.rs b/tests/deploy_account.rs index 70af6ea6d..fd30b7c89 100644 --- a/tests/deploy_account.rs +++ b/tests/deploy_account.rs @@ -104,7 +104,7 @@ fn internal_deploy_account() { ("n_steps", 3612), ("pedersen_builtin", 23), ("range_check_builtin", 83), - ("l1_gas_usage", 3672) + ("l1_gas_usage", 4896) ] .into_iter() .map(|(k, v)| (k.to_string(), v)) @@ -264,7 +264,7 @@ fn internal_deploy_account_cairo1() { ("n_steps", n_steps), ("pedersen_builtin", 23), ("range_check_builtin", 87), - ("l1_gas_usage", 4896) + ("l1_gas_usage", 6120) ] .into_iter() .map(|(k, v)| (k.to_string(), v)) diff --git a/tests/internals.rs b/tests/internals.rs index 3159d3c48..d089ac2c1 100644 --- a/tests/internals.rs +++ b/tests/internals.rs @@ -696,9 +696,9 @@ fn expected_fib_fee_transfer_info(fee: u128) -> CallInfo { ], }], storage_read_values: vec![ - INITIAL_BALANCE.clone() - Felt252::from(1252), + INITIAL_BALANCE.clone() - Felt252::from(2476), Felt252::zero(), - Felt252::from(1252), + Felt252::from(2476), Felt252::zero(), ], accessed_storage_keys: HashSet::from([ @@ -920,7 +920,7 @@ fn test_declare_tx() { ("n_steps".to_string(), 2715), ("range_check_builtin".to_string(), 63), ("pedersen_builtin".to_string(), 15), - ("l1_gas_usage".to_string(), 2448), + ("l1_gas_usage".to_string(), 3672), ]); let fee = calculate_tx_fee(&resources, *GAS_PRICE, &block_context).unwrap(); @@ -1008,7 +1008,7 @@ fn test_declarev2_tx() { ("n_steps".to_string(), 2715), ("range_check_builtin".to_string(), 63), ("pedersen_builtin".to_string(), 15), - ("l1_gas_usage".to_string(), 1224), + ("l1_gas_usage".to_string(), 2448), ]); let fee = calculate_tx_fee(&resources, *GAS_PRICE, &block_context).unwrap(); @@ -1226,7 +1226,7 @@ fn expected_transaction_execution_info(block_context: &BlockContext) -> Transact let resources = HashMap::from([ ("n_steps".to_string(), 4135), ("pedersen_builtin".to_string(), 16), - ("l1_gas_usage".to_string(), 2448), + ("l1_gas_usage".to_string(), 3672), ("range_check_builtin".to_string(), 101), ]); let fee = calculate_tx_fee(&resources, *GAS_PRICE, block_context).unwrap(); @@ -1782,7 +1782,7 @@ fn test_state_for_declare_tx() { // ]) // ); - let fee = Felt252::from(2476); + let fee = Felt252::from(3700); // Check state.cache assert_eq!( From 5c44880d68523bc900de0d130ec34c2b88b7fef2 Mon Sep 17 00:00:00 2001 From: MrAzteca Date: Mon, 4 Sep 2023 15:16:12 +0200 Subject: [PATCH 14/44] Remove missing unwrap from codebase. (#1000) --- src/state/cached_state.rs | 12 +++++++----- src/state/state_api.rs | 3 ++- src/transaction/declare.rs | 2 +- src/transaction/declare_v2.rs | 2 +- src/transaction/deploy.rs | 4 ++-- src/transaction/deploy_account.rs | 2 +- src/transaction/error.rs | 3 +++ src/transaction/invoke_function.rs | 2 +- src/transaction/l1_handler.rs | 2 +- 9 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/state/cached_state.rs b/src/state/cached_state.rs index 70b0e8899..98b37deb6 100644 --- a/src/state/cached_state.rs +++ b/src/state/cached_state.rs @@ -14,6 +14,7 @@ use crate::{ use cairo_vm::felt::Felt252; use getset::{Getters, MutGetters}; use num_traits::Zero; +use starknet::core::types::FromByteArrayError; use std::{ collections::{HashMap, HashSet}, sync::Arc, @@ -274,7 +275,7 @@ impl State for CachedState { fn count_actual_storage_changes( &mut self, fee_token_and_sender_address: Option<(&Address, &Address)>, - ) -> (usize, usize) { + ) -> Result<(usize, usize), FromByteArrayError> { let mut storage_updates = subtract_mappings( self.cache.storage_writes.clone(), self.cache.storage_initial_values.clone(), @@ -310,14 +311,14 @@ impl State for CachedState { // Add fee transfer storage update before actually charging it, as it needs to be included in the // calculation of the final fee. if let Some((fee_token_address, sender_address)) = fee_token_and_sender_address { - let (sender_low_key, _) = get_erc20_balance_var_addresses(sender_address).unwrap(); + let (sender_low_key, _) = get_erc20_balance_var_addresses(sender_address)?; storage_updates.insert( (fee_token_address.clone(), sender_low_key), Felt252::default(), ); } - (n_modified_contracts, storage_updates.len()) + Ok((n_modified_contracts, storage_updates.len())) } fn get_class_hash_at(&mut self, contract_address: &Address) -> Result { @@ -730,8 +731,9 @@ mod tests { (n_modified_contracts, n_storage_updates) }; - let changes = - cached_state.count_actual_storage_changes(Some((&fee_token_address, &sender_address))); + let changes = cached_state + .count_actual_storage_changes(Some((&fee_token_address, &sender_address))) + .unwrap(); assert_eq!(changes, expected_changes); } diff --git a/src/state/state_api.rs b/src/state/state_api.rs index 0a9ee9fb7..edeab04de 100644 --- a/src/state/state_api.rs +++ b/src/state/state_api.rs @@ -6,6 +6,7 @@ use crate::{ utils::{Address, ClassHash, CompiledClassHash}, }; use cairo_vm::felt::Felt252; +use starknet::core::types::FromByteArrayError; pub trait StateReader { /// Returns the contract class of the given class hash or compiled class hash. @@ -57,7 +58,7 @@ pub trait State { fn count_actual_storage_changes( &mut self, fee_token_and_sender_address: Option<(&Address, &Address)>, - ) -> (usize, usize); + ) -> Result<(usize, usize), FromByteArrayError>; fn get_class_hash_at(&mut self, contract_address: &Address) -> Result; diff --git a/src/transaction/declare.rs b/src/transaction/declare.rs index 91dfa5a70..034132e63 100644 --- a/src/transaction/declare.rs +++ b/src/transaction/declare.rs @@ -171,7 +171,7 @@ impl Declare { let changes = state.count_actual_storage_changes(Some(( &block_context.starknet_os_config.fee_token_address, &self.sender_address, - ))); + )))?; let actual_resources = calculate_tx_resources( resources_manager, &vec![validate_info.clone()], diff --git a/src/transaction/declare_v2.rs b/src/transaction/declare_v2.rs index 4c9945f9a..a9431326f 100644 --- a/src/transaction/declare_v2.rs +++ b/src/transaction/declare_v2.rs @@ -323,7 +323,7 @@ impl DeclareV2 { let storage_changes = state.count_actual_storage_changes(Some(( &block_context.starknet_os_config.fee_token_address, &self.sender_address, - ))); + )))?; let actual_resources = calculate_tx_resources( resources_manager, &[execution_result.call_info.clone()], diff --git a/src/transaction/deploy.rs b/src/transaction/deploy.rs index 50666ec5a..f0b9b320a 100644 --- a/src/transaction/deploy.rs +++ b/src/transaction/deploy.rs @@ -182,7 +182,7 @@ impl Deploy { let resources_manager = ExecutionResourcesManager::default(); - let changes = state.count_actual_storage_changes(None); + let changes = state.count_actual_storage_changes(None)?; let actual_resources = calculate_tx_resources( resources_manager, &[Some(call_info.clone())], @@ -245,7 +245,7 @@ impl Deploy { block_context.validate_max_n_steps, )?; - let changes = state.count_actual_storage_changes(None); + let changes = state.count_actual_storage_changes(None)?; let actual_resources = calculate_tx_resources( resources_manager, &[call_info.clone()], diff --git a/src/transaction/deploy_account.rs b/src/transaction/deploy_account.rs index 86ad894a0..bc8fe3ef8 100644 --- a/src/transaction/deploy_account.rs +++ b/src/transaction/deploy_account.rs @@ -216,7 +216,7 @@ impl DeployAccount { state.count_actual_storage_changes(Some(( &block_context.starknet_os_config.fee_token_address, &self.contract_address, - ))), + )))?, None, 0, ) diff --git a/src/transaction/error.rs b/src/transaction/error.rs index 21c4ad38d..c254dd152 100644 --- a/src/transaction/error.rs +++ b/src/transaction/error.rs @@ -18,6 +18,7 @@ use cairo_vm::{ trace_errors::TraceError, vm_errors::VirtualMachineError, }, }; +use starknet::core::types::FromByteArrayError; use thiserror::Error; #[derive(Debug, Error)] @@ -144,4 +145,6 @@ pub enum TransactionError { UnsupportedVersion(String), #[error("Invalid compiled class, expected class hash: {0}, but received: {1}")] InvalidCompiledClassHash(String, String), + #[error(transparent)] + FromByteArrayError(#[from] FromByteArrayError), } diff --git a/src/transaction/invoke_function.rs b/src/transaction/invoke_function.rs index 471a334a5..2175d9a1b 100644 --- a/src/transaction/invoke_function.rs +++ b/src/transaction/invoke_function.rs @@ -248,7 +248,7 @@ impl InvokeFunction { let changes = state.count_actual_storage_changes(Some(( &block_context.starknet_os_config.fee_token_address, &self.contract_address, - ))); + )))?; let actual_resources = calculate_tx_resources( resources_manager, &vec![call_info.clone(), validate_info.clone()], diff --git a/src/transaction/l1_handler.rs b/src/transaction/l1_handler.rs index 10946e0d4..ea4bb95a8 100644 --- a/src/transaction/l1_handler.rs +++ b/src/transaction/l1_handler.rs @@ -128,7 +128,7 @@ impl L1Handler { )? }; - let changes = state.count_actual_storage_changes(None); + let changes = state.count_actual_storage_changes(None)?; let actual_resources = calculate_tx_resources( resources_manager, &[call_info.clone()], From 11ce41b4ff6f29206d1449847f16e6b16e57e7a1 Mon Sep 17 00:00:00 2001 From: Edgar Date: Mon, 4 Sep 2023 15:18:30 +0200 Subject: [PATCH 15/44] refactor/ fix TryFrom InvokeTransaction into a standalone method on InvokeFunction (#999) * refactor and fix TryFrom InvokeTransaction into a standalone method on InvokeFunction * document * fix --- src/transaction/invoke_function.rs | 120 +++++++++++++++++++++++------ 1 file changed, 98 insertions(+), 22 deletions(-) diff --git a/src/transaction/invoke_function.rs b/src/transaction/invoke_function.rs index 2175d9a1b..1f2cc3e08 100644 --- a/src/transaction/invoke_function.rs +++ b/src/transaction/invoke_function.rs @@ -1,7 +1,7 @@ use crate::{ core::transaction_hash::{calculate_transaction_hash_common, TransactionHashPrefix}, definitions::{ - block_context::BlockContext, + block_context::{BlockContext, StarknetChainId}, constants::{ EXECUTE_ENTRY_POINT_SELECTOR, QUERY_VERSION_BASE, VALIDATE_ENTRY_POINT_SELECTOR, }, @@ -20,7 +20,7 @@ use crate::{ use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; use cairo_vm::felt::Felt252; use getset::Getters; -use num_traits::{One, Zero}; +use num_traits::Zero; use super::{fee::charge_fee, Transaction}; @@ -120,6 +120,22 @@ impl InvokeFunction { }) } + /// Creates a `InvokeFunction` from a starknet api `InvokeTransaction`. + pub fn from_invoke_transaction( + tx: starknet_api::transaction::InvokeTransaction, + chain_id: StarknetChainId, + version: Felt252, + ) -> Result { + match tx { + starknet_api::transaction::InvokeTransaction::V0(v0) => { + convert_invoke_v0(v0, chain_id, version) + } + starknet_api::transaction::InvokeTransaction::V1(v1) => { + convert_invoke_v1(v1, chain_id, version) + } + } + } + fn get_execution_context( &self, n_steps: u64, @@ -406,15 +422,15 @@ pub(crate) fn preprocess_invoke_function_fields( fn convert_invoke_v0( value: starknet_api::transaction::InvokeTransactionV0, + chain_id: StarknetChainId, + version: Felt252, ) -> Result { let contract_address = Address(Felt252::from_bytes_be( value.contract_address.0.key().bytes(), )); let max_fee = value.max_fee.0; let entry_point_selector = Felt252::from_bytes_be(value.entry_point_selector.0.bytes()); - let version = Felt252::zero(); let nonce = None; - let chain_id = Felt252::zero(); let signature = value .signature @@ -437,19 +453,19 @@ fn convert_invoke_v0( version, calldata, signature, - chain_id, + chain_id.to_felt(), nonce, ) } fn convert_invoke_v1( value: starknet_api::transaction::InvokeTransactionV1, + chain_id: StarknetChainId, + version: Felt252, ) -> Result { let contract_address = Address(Felt252::from_bytes_be(value.sender_address.0.key().bytes())); let max_fee = value.max_fee.0; - let version = Felt252::one(); let nonce = Felt252::from_bytes_be(value.nonce.0.bytes()); - let chain_id = Felt252::zero(); let entry_point_selector = EXECUTE_ENTRY_POINT_SELECTOR.clone(); let signature = value @@ -473,24 +489,11 @@ fn convert_invoke_v1( version, calldata, signature, - chain_id, + chain_id.to_felt(), Some(nonce), ) } -impl TryFrom for InvokeFunction { - type Error = TransactionError; - - fn try_from( - value: starknet_api::transaction::InvokeTransaction, - ) -> Result { - match value { - starknet_api::transaction::InvokeTransaction::V0(v0) => convert_invoke_v0(v0), - starknet_api::transaction::InvokeTransaction::V1(v1) => convert_invoke_v1(v1), - } - } -} - #[cfg(test)] mod tests { use super::*; @@ -503,9 +506,82 @@ mod tests { utils::calculate_sn_keccak, }; use cairo_lang_starknet::casm_contract_class::CasmContractClass; - use num_traits::Num; + use num_traits::{Num, One}; + use starknet_api::{ + core::{ContractAddress, Nonce, PatriciaKey}, + hash::{StarkFelt, StarkHash}, + transaction::{Fee, InvokeTransaction, InvokeTransactionV1, TransactionSignature}, + }; use std::{collections::HashMap, sync::Arc}; + #[test] + fn test_from_invoke_transaction() { + // https://starkscan.co/tx/0x05b6cf416d56e7c7c519b44e6d06a41657ff6c6a3f2629044fac395e6d200ac4 + // result 0x05b6cf416d56e7c7c519b44e6d06a41657ff6c6a3f2629044fac395e6d200ac4 + let tx = InvokeTransaction::V1(InvokeTransactionV1 { + sender_address: ContractAddress( + PatriciaKey::try_from( + StarkHash::try_from( + "0x00c4658311841a69ce121543af332622bc243cf5593fc4aaf822481c7b7f183d", + ) + .unwrap(), + ) + .unwrap(), + ), + max_fee: Fee(49000000000000), + signature: TransactionSignature(vec![ + StarkFelt::try_from( + "0x18315db8eb360a82ea11f302d6a6a35a11b9df1dc220ec1376c4d4604770dd4", + ) + .unwrap(), + StarkFelt::try_from( + "0x5e8642259ac8e99c84cdf88c17385698150eb11dccfb3036ecc2b97c0903d27", + ) + .unwrap(), + ]), + nonce: Nonce(StarkFelt::from(22u32)), + calldata: starknet_api::transaction::Calldata(Arc::new(vec![ + StarkFelt::try_from("0x1").unwrap(), + StarkFelt::try_from( + "0x0454f0bd015e730e5adbb4f080b075fdbf55654ff41ee336203aa2e1ac4d4309", + ) + .unwrap(), + StarkFelt::try_from( + "0x032a99297e1d12a9b91d4f90d5dd4b160d93c84a9e3b4daa916fec14ec852e05", + ) + .unwrap(), + StarkFelt::try_from( + "0x0000000000000000000000000000000000000000000000000000000000000000", + ) + .unwrap(), + StarkFelt::try_from( + "0x0000000000000000000000000000000000000000000000000000000000000002", + ) + .unwrap(), + StarkFelt::try_from( + "0x0000000000000000000000000000000000000000000000000000000000000002", + ) + .unwrap(), + StarkFelt::try_from( + "0x0383538353434346334616431626237363933663435643237376236313461663", + ) + .unwrap(), + StarkFelt::try_from( + "0x0393762666334373463313762393535303530383563613961323435643965666", + ) + .unwrap(), + ])), + }); + + let tx_sir = + InvokeFunction::from_invoke_transaction(tx, StarknetChainId::MainNet, Felt252::one()) + .unwrap(); + assert_eq!( + tx_sir.hash_value.to_str_radix(16), + "5b6cf416d56e7c7c519b44e6d06a41657ff6c6a3f2629044fac395e6d200ac4" + ); + } + #[test] fn test_invoke_apply_without_fees() { let internal_invoke_function = InvokeFunction { From 3a71b9f543d8d91da5ea22b1db29ec8e91127f93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Est=C3=A9fano=20Bargas?= Date: Mon, 4 Sep 2023 15:03:11 -0300 Subject: [PATCH 16/44] Deprecate old RPC StateReader in favor of `starknet_api` compatible one, support SiR execution (#967) * From/TryFrom starknet api types * Add deploy account * Modify gitignore * Deploy account and invoke function * Change into_iter to iter * Update .gitignore Co-authored-by: fmoletta <99273364+fmoletta@users.noreply.github.com> * change to try_from * Move functions to its respective files * WIP Added SIR support to SNRPC * Implemented state reader for sir * WIP Transaction * WIP SiR execution * Fixed rpc sir execute_tx * Fix clippy * Import last version of sn_api * Formatting * Test * Test try from * Delete test * Fix format * Fix test * Fix clippy * Replaced try_from with from_invoke_transaction * infer version * Fix version * Changed test_try_from_invoke * Ignore test_recent_tx * Refactor tx deser, (un)ignore tests * Added support for reverted --------- Co-authored-by: Milton Co-authored-by: Juan Bono Co-authored-by: fmoletta <99273364+fmoletta@users.noreply.github.com> Co-authored-by: mmsc2 <88055861+mmsc2@users.noreply.github.com> Co-authored-by: Edgar Luque --- Cargo.lock | 573 ++++++++++++++--------------- rpc_state_reader_sn_api/Cargo.toml | 1 + rpc_state_reader_sn_api/src/lib.rs | 467 +++++++++++++++++------ src/transaction/invoke_function.rs | 21 +- 4 files changed, 645 insertions(+), 417 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6b5dc8f09..8407c9fe1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,17 +21,17 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.3.1" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2079246596c18b4a33e274ae10c0e50613f4d32a4198e09c7b93771013fed74" +checksum = "a92ef85799cba03f76e4f7c10f533e66d87c9a7e7055f3391f09000ad8351bc9" dependencies = [ "actix-codec", "actix-rt", "actix-service", "actix-utils", "ahash 0.8.3", - "base64 0.21.2", - "bitflags 1.3.2", + "base64 0.21.3", + "bitflags 2.4.0", "brotli", "bytes", "bytestring", @@ -65,7 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -83,9 +83,9 @@ dependencies = [ [[package]] name = "actix-rt" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e" +checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" dependencies = [ "futures-core", "tokio", @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "actix-server" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e8613a75dd50cc45f473cee3c34d59ed677c0f7b44480ce3b8247d7dc519327" +checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" dependencies = [ "actix-rt", "actix-service", @@ -103,8 +103,7 @@ dependencies = [ "futures-core", "futures-util", "mio", - "num_cpus", - "socket2", + "socket2 0.5.3", "tokio", "tracing", ] @@ -122,19 +121,22 @@ dependencies = [ [[package]] name = "actix-tls" -version = "3.0.3" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fde0cf292f7cdc7f070803cb9a0d45c018441321a78b1042ffbbb81ec333297" +checksum = "72616e7fbec0aa99c6f3164677fa48ff5a60036d0799c98cab894a44f3e0efc3" dependencies = [ - "actix-codec", "actix-rt", "actix-service", "actix-utils", "futures-core", "http", - "log", + "impl-more", "pin-project-lite", + "rustls", + "rustls-webpki 0.101.4", + "tokio", "tokio-util", + "tracing", ] [[package]] @@ -149,9 +151,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.3.1" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3cb42f9566ab176e1ef0b8b3a896529062b4efc6be0123046095914c4c1c96" +checksum = "0e4a5b5e29603ca8c94a77c65cf874718ceb60292c5a5c3e5f4ace041af462b9" dependencies = [ "actix-codec", "actix-http", @@ -162,7 +164,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.7.6", + "ahash 0.8.3", "bytes", "bytestring", "cfg-if", @@ -171,7 +173,6 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "http", "itoa", "language-tags", "log", @@ -183,28 +184,28 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2", + "socket2 0.5.3", "time", "url", ] [[package]] name = "actix-web-codegen" -version = "4.2.0" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2262160a7ae29e3415554a3f1fc04c764b1540c116aa524683208078b7a75bc9" +checksum = "eb1f50ebbb30eca122b188319a4398b3f7bb4a8cdf50ecfb73bfc6a3c3ce54f5" dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.29", ] [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -251,9 +252,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" dependencies = [ "memchr", ] @@ -296,24 +297,23 @@ dependencies = [ [[package]] name = "anstream" -version = "0.3.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", - "is-terminal", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" +checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" [[package]] name = "anstyle-parse" @@ -335,9 +335,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "1.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" dependencies = [ "anstyle", "windows-sys", @@ -345,9 +345,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.72" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arbitrary" @@ -506,13 +506,13 @@ checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" [[package]] name = "async-trait" -version = "0.1.72" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -535,9 +535,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "awc" -version = "3.1.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ef547a81796eb2dfe9b345aba34c2e08391a0502493711395b36dd64052b69" +checksum = "7fa3c705a9c7917ac0f41c0757a0a747b43bbc29b0b364b081bd7c5fc67fb223" dependencies = [ "actix-codec", "actix-http", @@ -545,8 +545,7 @@ dependencies = [ "actix-service", "actix-tls", "actix-utils", - "ahash 0.7.6", - "base64 0.21.2", + "base64 0.21.3", "bytes", "cfg-if", "cookie", @@ -569,9 +568,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -590,9 +589,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.2" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" [[package]] name = "bigdecimal" @@ -638,9 +637,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "bitvec" @@ -789,9 +788,9 @@ checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663" [[package]] name = "cairo-felt" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed22664386f178bf9ca7b9ae7235727d92fa37b731a9063b5122488a1f699834" +checksum = "5972097b8800ca5dffb458040e74c724a2ac4fa4b5b480b50f5b96c7e67d6427" dependencies = [ "lazy_static", "num-bigint", @@ -802,9 +801,9 @@ dependencies = [ [[package]] name = "cairo-lang-casm" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213103e1cf9049abd443f97088939d9cf6ef5500b295003be2b244c702d8fe9c" +checksum = "afc7f7cb89bc3f52c2c738f3e87c8f8773bd3456cae1d322d100d4b0da584f3c" dependencies = [ "cairo-lang-utils", "indoc", @@ -819,9 +818,9 @@ dependencies = [ [[package]] name = "cairo-lang-compiler" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb857feb6d7a73fd33193a2cc141c04ab345d47bcbd9e2c014ef3422ebc6d55" +checksum = "d4f2c54b065f7fd97bf8d5df76cbcbbd01d8a8c319d281796ee20ecc48e16ca8" dependencies = [ "anyhow", "cairo-lang-defs", @@ -836,6 +835,7 @@ dependencies = [ "cairo-lang-sierra-generator", "cairo-lang-syntax", "cairo-lang-utils", + "itertools 0.11.0", "log", "salsa", "smol_str", @@ -844,18 +844,18 @@ dependencies = [ [[package]] name = "cairo-lang-debug" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af06d0c89bd515707d6f0140a880f6463b955189fa5f97719edd62348c36ee2c" +checksum = "873ba77d4c3f780c727c7d6c738cded22b3f6d4023e30546dfe14f97a087887e" dependencies = [ "cairo-lang-utils", ] [[package]] name = "cairo-lang-defs" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ead2773a4d8147c3c25666d9a97a41161eeb59e0d0d1060b5f9b6fa68d0da1" +checksum = "f5031fff038c27ed43769b73a6f5d41aeaea34df9af862e024c23fbb4f076249" dependencies = [ "cairo-lang-debug", "cairo-lang-diagnostics", @@ -871,9 +871,9 @@ dependencies = [ [[package]] name = "cairo-lang-diagnostics" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6924bc3d558495a5327955da3aec15e6ab71c0f83e955258ffbb0e1a20ead87" +checksum = "7b6cb1492e5784e1076320a5018ce7584f391b2f3b414bc0a8ab7c289fa118ce" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -884,9 +884,9 @@ dependencies = [ [[package]] name = "cairo-lang-eq-solver" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ac8853dae37b4f3b4d3d8d36002b2fb0b52aa5f578f15b0bf47cedd2ec7358b" +checksum = "c35dddbc63b2a4870891cc74498726aa32bfaa518596352f9bb101411cc4c584" dependencies = [ "cairo-lang-utils", "good_lp", @@ -896,9 +896,9 @@ dependencies = [ [[package]] name = "cairo-lang-filesystem" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acb3fc0d5582fd27910e63cca94a7c9d41acc0045a815ff99ed941eb45183375" +checksum = "32ce0b8e66a6085ae157d43b5c162d60166f0027d6f125c50ee74e4dc7916ff6" dependencies = [ "cairo-lang-debug", "cairo-lang-utils", @@ -910,9 +910,9 @@ dependencies = [ [[package]] name = "cairo-lang-lowering" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7d7f5acc6e4c67a6f2232df1d1f13039453cb50d2971183a1fd254067735cd0" +checksum = "29cc679f501725e03ee703559ed27d084c6f4031bd51ff86378cf845a85ee207" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -929,15 +929,16 @@ dependencies = [ "log", "num-bigint", "num-traits 0.2.16", + "once_cell", "salsa", "smol_str", ] [[package]] name = "cairo-lang-parser" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9716a807fd4430a4af396ad9f7bd1228414c972a24a7e4211ac83d83f538d1" +checksum = "cdcadb046659134466bc7e11961ea8a56969dae8a54d8f985955ce0b95185c7f" dependencies = [ "cairo-lang-diagnostics", "cairo-lang-filesystem", @@ -956,17 +957,17 @@ dependencies = [ [[package]] name = "cairo-lang-plugins" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb782377b1cb01ccb3e00aec3903912895ae3cf6b5a8e05918bc0e4a837c1929" +checksum = "4632790cd4ea11d4849934456a400eae7ed419f6d721f24a6b637df67b7e902f" dependencies = [ "cairo-lang-defs", "cairo-lang-diagnostics", "cairo-lang-filesystem", "cairo-lang-parser", - "cairo-lang-semantic", "cairo-lang-syntax", "cairo-lang-utils", + "indent", "indoc", "itertools 0.11.0", "num-bigint", @@ -976,20 +977,20 @@ dependencies = [ [[package]] name = "cairo-lang-proc-macros" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756fe3fdb86d3d8fda40ee250d146300381e98110ec7e4a624407c7e0b7e63f" +checksum = "170838817fc33ddb65e0a9480526df0b226b148a0fca0a5cd7071be4c6683157" dependencies = [ "cairo-lang-debug", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] name = "cairo-lang-project" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "913cdcd5e567d7ca13d1b37822feeac19973f5133a4fbab76b67e12c847bff3a" +checksum = "4162ee976c61fdeb3b621f4a76fd256e46a5c0890f750a3a9d2c9560a3bc1daf" dependencies = [ "cairo-lang-filesystem", "cairo-lang-utils", @@ -1001,9 +1002,9 @@ dependencies = [ [[package]] name = "cairo-lang-runner" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ce3aa736c0180b5ed5320138b3f8ed70696618f2cb23bc86217eebfa2274ea" +checksum = "11d66ef01350e2e7f7e6b2b43b865da2513a42600082ee1a2975d3af3da7f0ca" dependencies = [ "anyhow", "ark-ff", @@ -1038,15 +1039,16 @@ dependencies = [ [[package]] name = "cairo-lang-semantic" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6962d05da3c355f8fc49e97dda4252dfa71969399ef5658130b9cdc86d8a805" +checksum = "13e544fa9a222bf2d007df2b5fc9b21c2a20ab7e17d6fefbcbc193de209451cd" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", "cairo-lang-diagnostics", "cairo-lang-filesystem", "cairo-lang-parser", + "cairo-lang-plugins", "cairo-lang-proc-macros", "cairo-lang-syntax", "cairo-lang-utils", @@ -1055,15 +1057,16 @@ dependencies = [ "log", "num-bigint", "num-traits 0.2.16", + "once_cell", "salsa", "smol_str", ] [[package]] name = "cairo-lang-sierra" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "872cf03415aa48c7757e4cee4b0223a158fcc9abddf55574f6c387324f25cc1f" +checksum = "d5e136b79e95a14ef38a2be91a67ceb85317407d336a5b0d418c33b23c78596a" dependencies = [ "cairo-lang-utils", "const-fnv1a-hash", @@ -1084,9 +1087,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-ap-change" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eba2fbd5f13210a46c2050fe156776490c556f6f0335401bda810640c1e65fd" +checksum = "511ca7708faa7ba8d14ae26e1d60ead2d02028c8f664baf5ecb0fd6a0d1e20f6" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -1098,9 +1101,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-gas" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9f4cec68f861b86dd6429592d9c0c535cbb983a9b7c21fc906b659b35e7882e" +checksum = "351a25bc010b910919c01d5c57e937b0c3d330fc30d92702c0cb4061819df8df" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -1112,9 +1115,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-generator" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65f050d6c717090ee10be52950cfe639709af27138eb9cd4122b0ab171a5cf2a" +checksum = "114091bb971c06fd072aca816af1c3f62566cd8a4b1453c786155161a36c7bce" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -1132,15 +1135,16 @@ dependencies = [ "indexmap 2.0.0", "itertools 0.11.0", "num-bigint", + "once_cell", "salsa", "smol_str", ] [[package]] name = "cairo-lang-sierra-to-casm" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c53fa4c6013827c42c1e02ee9a58fa5901cb18a711bdfeb1af379f69d2055c" +checksum = "fa1c799de62972dfd7112d563000695be94305b6f7d9bedd29f347799bf03e1c" dependencies = [ "assert_matches", "cairo-felt", @@ -1160,9 +1164,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-type-size" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07a5e70b5a5826edeb61ec375886847f51e1b995709e3f36d657844fbd703d45" +checksum = "d2fe73d9d58aaf9088f6ba802bcf43ce9ca4bd198190cf5bf91caa7d408dd11a" dependencies = [ "cairo-lang-sierra", "cairo-lang-utils", @@ -1170,9 +1174,9 @@ dependencies = [ [[package]] name = "cairo-lang-starknet" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfaa6629cd5a9cc13543d59bd5494fc01cc4118efbcc5b13528be4539a35f77f" +checksum = "75df624e71e33a31a924e799dd2a9a8284204b41d8db9c51803317bd9edff81f" dependencies = [ "anyhow", "cairo-felt", @@ -1211,9 +1215,9 @@ dependencies = [ [[package]] name = "cairo-lang-syntax" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b23b312f07e45bc0bb2d240187a37db2816393c285896c9ab453c8ca8e128d25" +checksum = "0b1af0ae21f9e539f97cfdf56f5ce0934dae5d87f568fd778c3d624a102f8dbb" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -1228,9 +1232,9 @@ dependencies = [ [[package]] name = "cairo-lang-syntax-codegen" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0225e4b5f09523bc424fae216ea899cb8f9132fb0da164096cee5e2ce79076fe" +checksum = "822ffabf24f6a5506262edcece315260a82d9dfba3abe6548791a6d654563ad0" dependencies = [ "genco", "xshell", @@ -1238,9 +1242,9 @@ dependencies = [ [[package]] name = "cairo-lang-utils" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b4bdb1d6509e2579d04d1757070f88c2542ff033194f749772669a1615c7e4" +checksum = "f974b6e859f0b09c0f13ec8188c96e9e8bbb5da04214f911dbb5bcda67cb812b" dependencies = [ "indexmap 2.0.0", "itertools 0.11.0", @@ -1254,9 +1258,9 @@ dependencies = [ [[package]] name = "cairo-vm" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74af2798567c670dc274245ca135c4501100fc5639e91c83b8527d9e46a97249" +checksum = "00d9bf139b0fe845627cf09d11af43eec9575dba702033bf6b08050c776b8553" dependencies = [ "anyhow", "ark-ff", @@ -1288,11 +1292,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "jobserver", + "libc", ] [[package]] @@ -1303,15 +1308,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "95ed24df0632f708f5f6d8082675bef2596f7084dee3dd55f632290bf35bfe0f" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits 0.2.16", "serde", - "winapi", + "windows-targets", ] [[package]] @@ -1326,20 +1331,19 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.19" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" +checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" dependencies = [ "clap_builder", "clap_derive", - "once_cell", ] [[package]] name = "clap_builder" -version = "4.3.19" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" +checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" dependencies = [ "anstream", "anstyle", @@ -1349,21 +1353,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.3.12" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" [[package]] name = "colorchoice" @@ -1487,7 +1491,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f34ba9a9bcb8645379e9de8cb3ecfcf4d1c85ba66d90deb3259206fa5aa193b" dependencies = [ "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -1544,7 +1548,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -1566,14 +1570,14 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core 0.20.3", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] name = "deranged" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8810e7e2cf385b1e9b50d68264908ec367ba642c96d02edfe61c39e88e2a3c01" +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" dependencies = [ "serde", ] @@ -1648,9 +1652,9 @@ checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" [[package]] name = "dyn-clone" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "304e6508efa593091e97a9abbc10f90aa7ca635b6d2784feff3c89d41dd12272" +checksum = "bbfc4744c1b8f2a09adc0e55242f60b1af195d88596bd8700be74418c056c555" [[package]] name = "either" @@ -1669,9 +1673,9 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] @@ -1684,9 +1688,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" dependencies = [ "errno-dragonfly", "libc", @@ -1778,9 +1782,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" dependencies = [ "crc32fast", "miniz_oxide", @@ -1851,7 +1855,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -1953,15 +1957,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] name = "good_lp" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0833c2bc3cee9906df9969ade12b0b3b8759faa7bc2682b428be767033cdcd4" +checksum = "fa7f3b0e0de4e671b6ffc1274b153a9394cb58bf04ee67505b0cb9915513115f" dependencies = [ "fnv", "minilp", @@ -1969,9 +1973,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.20" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" dependencies = [ "bytes", "fnv", @@ -2093,9 +2097,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" @@ -2114,7 +2118,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -2189,6 +2193,12 @@ dependencies = [ "parity-scale-codec", ] +[[package]] +name = "impl-more" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206ca75c9c03ba3d4ace2460e57b189f39f43de612c2f85836e65c929701bb2d" + [[package]] name = "impl-rlp" version = "0.3.0" @@ -2393,9 +2403,9 @@ checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libmimalloc-sys" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ac0e912c8ef1b735e92369695618dc5b1819f5a7bf3f167301a3ba1cea515e" +checksum = "25d058a81af0d1c22d7a1c948576bee6d673f7af3c0f35564abd6c81122f513d" dependencies = [ "cc", "libc", @@ -2437,9 +2447,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "lru" @@ -2461,9 +2471,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e" [[package]] name = "memmap2" @@ -2476,9 +2486,9 @@ dependencies = [ [[package]] name = "mimalloc" -version = "0.1.37" +version = "0.1.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e2894987a3459f3ffb755608bd82188f8ed00d0ae077f1edea29c068d639d98" +checksum = "972e5f23f6716f62665760b0f4cbf592576a80c7b879ba9beaafc0e558894127" dependencies = [ "libmimalloc-sys", ] @@ -2557,9 +2567,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", @@ -2633,21 +2643,11 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" dependencies = [ "memchr", ] @@ -2680,9 +2680,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.4" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a296c3079b5fefbc499e1de58dc26c09b1b9a5952d26694ee89f04a43ebbb3e" +checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2767,12 +2767,12 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "petgraph" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 1.9.3", + "indexmap 2.0.0", ] [[package]] @@ -2805,7 +2805,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -2834,9 +2834,9 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -2920,9 +2920,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -3000,9 +3000,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.1" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" dependencies = [ "aho-corasick", "memchr", @@ -3012,9 +3012,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" dependencies = [ "aho-corasick", "memchr", @@ -3023,23 +3023,23 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "relative-path" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bf2521270932c3c7bed1a59151222bd7643c79310f2916f01925e1e16255698" +checksum = "c707298afce11da2efef2f600116fa93ffa7a032b5d7b628aa17711ec81383ca" [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ - "base64 0.21.2", + "base64 0.21.3", "bytes", "encoding_rs", "futures-core", @@ -3068,7 +3068,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.22.6", + "webpki-roots 0.25.2", "winreg", ] @@ -3116,7 +3116,7 @@ dependencies = [ "dotenv", "serde", "serde_json", - "serde_with 3.1.0", + "serde_with 3.3.0", "starknet", "starknet_api", "starknet_in_rust", @@ -3136,9 +3136,10 @@ dependencies = [ "flate2", "serde", "serde_json", - "serde_with 3.1.0", + "serde_with 3.3.0", "starknet", "starknet_api", + "starknet_in_rust", "thiserror", "ureq", ] @@ -3172,11 +3173,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.4" +version = "0.38.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "errno", "libc", "linux-raw-sys", @@ -3185,13 +3186,13 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.5" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79ea77c539259495ce8ca47f53e66ae0330a8819f67e23ac96ca02f50e7b7d36" +checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" dependencies = [ "log", "ring", - "rustls-webpki 0.101.2", + "rustls-webpki 0.101.4", "sct", ] @@ -3201,14 +3202,14 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.2", + "base64 0.21.3", ] [[package]] name = "rustls-webpki" -version = "0.100.1" +version = "0.100.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" +checksum = "e98ff011474fa39949b7e5c0428f9b4937eda7da7848bbb947786b7be0b27dab" dependencies = [ "ring", "untrusted", @@ -3216,9 +3217,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.2" +version = "0.101.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "513722fd73ad80a71f72b61009ea1b584bcfa1483ca93949c8f290298837fa59" +checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d" dependencies = [ "ring", "untrusted", @@ -3276,9 +3277,9 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.12" +version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" +checksum = "763f8cd0d4c71ed8389c90cb8100cba87e763bd01a8e614d4f0af97bcd50a161" dependencies = [ "dyn-clone", "indexmap 1.9.3", @@ -3289,9 +3290,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.12" +version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" +checksum = "ec0f696e21e10fa546b7ffb1c9672c6de8fbc7a81acf59524386d8639bf12737" dependencies = [ "proc-macro2", "quote", @@ -3350,7 +3351,7 @@ checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -3366,9 +3367,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" dependencies = [ "itoa", "ryu", @@ -3435,17 +3436,18 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e47d95bc83ed33b2ecf84f4187ad1ab9685d18ff28db000c99deac8ce180e3" +checksum = "1ca3b16a3d82c4088f343b7480a93550b3eabe1a358569c2dfe38bbcead07237" dependencies = [ - "base64 0.21.2", + "base64 0.21.3", "chrono", "hex", "indexmap 1.9.3", + "indexmap 2.0.0", "serde", "serde_json", - "serde_with_macros 3.1.0", + "serde_with_macros 3.3.0", "time", ] @@ -3458,19 +3460,19 @@ dependencies = [ "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] name = "serde_with_macros" -version = "3.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea3cee93715c2e266b9338b7544da68a9f24e227722ba482bd1c024367c77c65" +checksum = "2e6be15c453eb305019bfa438b1593c731f36a289a7853f7707ee29e870b3b3c" dependencies = [ "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -3516,15 +3518,15 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -3554,6 +3556,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "spin" version = "0.5.2" @@ -3621,7 +3633,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91f89c79b641618de8aa9668d74c6b6634659ceca311c6318a35c025f9d4d969" dependencies = [ - "base64 0.21.2", + "base64 0.21.3", "flate2", "hex", "serde", @@ -3681,7 +3693,7 @@ checksum = "af6527b845423542c8a16e060ea1bc43f67229848e7cd4c4d80be994a84220ce" dependencies = [ "starknet-curve 0.4.0", "starknet-ff", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -3724,7 +3736,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28a5865ee0ed22ade86bdf45e7c09c5641f1c59ccae12c21ecde535b2b6bf64a" dependencies = [ "starknet-core", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -3803,7 +3815,7 @@ version = "0.3.1" dependencies = [ "anyhow", "assert_matches", - "base64 0.21.2", + "base64 0.21.3", "cairo-lang-casm", "cairo-lang-runner", "cairo-lang-sierra", @@ -3894,9 +3906,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.28" +version = "2.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" dependencies = [ "proc-macro2", "quote", @@ -3911,9 +3923,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.7.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ "cfg-if", "fastrand", @@ -3935,22 +3947,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -3975,9 +3987,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b79eabcd964882a646b3584543ccabeae7869e9ac32a46f6f22b7a5bd405308b" +checksum = "a79d09ac6b08c1ab3906a2f7cc2e81a0e27c7ae89c63812df75e52bef0751e07" dependencies = [ "deranged", "itoa", @@ -3994,9 +4006,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" +checksum = "75c65469ed6b3a4809d987a41eb1dc918e9bc1d92211cbad7ae82931846f7451" dependencies = [ "time-core", ] @@ -4027,11 +4039,10 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", @@ -4039,7 +4050,7 @@ dependencies = [ "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.3", "tokio-macros", "windows-sys", ] @@ -4052,7 +4063,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -4166,9 +4177,9 @@ dependencies = [ [[package]] name = "unescaper" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995483205de764db1185c9461a000fff73fa4b9ee2bbe4c8b4027a94692700fe" +checksum = "a96a44ae11e25afb520af4534fd7b0bd8cd613e35a78def813b8cf41631fa3c8" dependencies = [ "thiserror", ] @@ -4218,12 +4229,12 @@ version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b11c96ac7ee530603dcdf68ed1557050f374ce55a5a07193ebf8cbc9f8927e9" dependencies = [ - "base64 0.21.2", + "base64 0.21.3", "flate2", "log", "once_cell", "rustls", - "rustls-webpki 0.100.1", + "rustls-webpki 0.100.2", "serde", "serde_json", "url", @@ -4232,9 +4243,9 @@ dependencies = [ [[package]] name = "url" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna", @@ -4299,7 +4310,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", "wasm-bindgen-shared", ] @@ -4333,7 +4344,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4354,33 +4365,20 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "webpki-roots" -version = "0.22.6" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" dependencies = [ - "webpki", + "rustls-webpki 0.100.2", ] [[package]] name = "webpki-roots" -version = "0.23.1" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" -dependencies = [ - "rustls-webpki 0.100.1", -] +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" [[package]] name = "winapi" @@ -4424,9 +4422,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -4439,62 +4437,63 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.3" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46aab759304e4d7b2075a9aecba26228bb073ee8c50db796b2c72c676b5d807" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ "memchr", ] [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys", ] [[package]] @@ -4538,7 +4537,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] diff --git a/rpc_state_reader_sn_api/Cargo.toml b/rpc_state_reader_sn_api/Cargo.toml index ba20520ba..7b9612204 100644 --- a/rpc_state_reader_sn_api/Cargo.toml +++ b/rpc_state_reader_sn_api/Cargo.toml @@ -22,3 +22,4 @@ serde_with = "3.0.0" dotenv = "0.15.0" cairo-vm = "0.8.5" blockifier = "0.2.0-rc0" +starknet_in_rust = { path = "../", version = "0.3.1" } diff --git a/rpc_state_reader_sn_api/src/lib.rs b/rpc_state_reader_sn_api/src/lib.rs index ef1c81d4a..61393d32a 100644 --- a/rpc_state_reader_sn_api/src/lib.rs +++ b/rpc_state_reader_sn_api/src/lib.rs @@ -16,7 +16,7 @@ use starknet_api::block::{BlockNumber, BlockTimestamp}; use starknet_api::core::{ChainId, ClassHash, EntryPointSelector}; use starknet_api::deprecated_contract_class::EntryPointOffset; use starknet_api::hash::StarkFelt; -use starknet_api::transaction::{InvokeTransaction, Transaction, TransactionHash}; +use starknet_api::transaction::{InvokeTransaction, Transaction as SNTransaction, TransactionHash}; use starknet_api::{core::ContractAddress, hash::StarkHash, state::StorageKey}; use std::collections::HashMap; use std::env; @@ -129,7 +129,7 @@ pub struct RpcBlockInfo { /// The sequencer address of this block. pub sequencer_address: ContractAddress, /// The transactions of this block. - pub transactions: Vec, + pub transactions: Vec, } #[derive(Deserialize)] @@ -185,12 +185,13 @@ impl RpcState { } } -#[derive(Debug)] +#[derive(Debug, Deserialize)] pub struct TransactionTrace { pub validate_invocation: RpcCallInfo, - pub function_invocation: RpcCallInfo, + pub function_invocation: Option, pub fee_transfer_invocation: RpcCallInfo, pub signature: Vec, + pub revert_error: Option, } #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)] @@ -277,53 +278,6 @@ impl<'de> Deserialize<'de> for RpcCallInfo { } } -impl<'de> Deserialize<'de> for TransactionTrace { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let value: serde_json::Value = Deserialize::deserialize(deserializer)?; - - let validate_invocation = value["validate_invocation"].clone(); - let function_invocation = value["function_invocation"].clone(); - let fee_transfer_invocation = value["fee_transfer_invocation"].clone(); - let signature_value = value["signature"].clone(); - - Ok(TransactionTrace { - validate_invocation: serde_json::from_value(validate_invocation) - .map_err(serde::de::Error::custom)?, - function_invocation: serde_json::from_value(function_invocation) - .map_err(serde::de::Error::custom)?, - fee_transfer_invocation: serde_json::from_value(fee_transfer_invocation) - .map_err(serde::de::Error::custom)?, - signature: serde_json::from_value(signature_value).map_err(serde::de::Error::custom)?, - }) - } -} - -/// Freestanding deserialize method to avoid a new type. -fn deserialize_transaction_json(transaction: serde_json::Value) -> serde_json::Result { - let tx_type: String = serde_json::from_value(transaction["type"].clone())?; - let tx_version: String = serde_json::from_value(transaction["version"].clone())?; - - match tx_type.as_str() { - "INVOKE" => match tx_version.as_str() { - "0x0" => Ok(Transaction::Invoke(InvokeTransaction::V0( - serde_json::from_value(transaction)?, - ))), - "0x1" => Ok(Transaction::Invoke(InvokeTransaction::V1( - serde_json::from_value(transaction)?, - ))), - x => Err(serde::de::Error::custom(format!( - "unimplemented invoke version: {x}" - ))), - }, - x => Err(serde::de::Error::custom(format!( - "unimplemented transaction type deserialization: {x}" - ))), - } -} - impl RpcState { /// Requests the transaction trace to the Feeder Gateway API. /// It's useful for testing the transaction outputs like: @@ -341,11 +295,11 @@ impl RpcState { .call() .unwrap(); - serde_json::from_str(&response.into_string().unwrap()).unwrap() + serde_json::from_value(response.into_json().unwrap()).unwrap() } /// Requests the given transaction to the Feeder Gateway API. - pub fn get_transaction(&self, hash: &TransactionHash) -> Transaction { + pub fn get_transaction(&self, hash: &TransactionHash) -> SNTransaction { let params = ureq::json!({ "jsonrpc": "2.0", "method": "starknet_getTransactionByHash", @@ -353,19 +307,7 @@ impl RpcState { "id": 1 }); let result = self.rpc_call::(¶ms).unwrap()["result"].clone(); - - match result["type"].as_str().unwrap() { - "INVOKE" => match result["version"].as_str().unwrap() { - "0x0" => Transaction::Invoke(InvokeTransaction::V0( - serde_json::from_value(result).unwrap(), - )), - "0x1" => Transaction::Invoke(InvokeTransaction::V1( - serde_json::from_value(result).unwrap(), - )), - _ => unimplemented!(), - }, - _ => unimplemented!(), - } + utils::deserialize_transaction_json(result).unwrap() } /// Gets the gas price of a given block. @@ -411,7 +353,7 @@ impl RpcState { .as_array() .unwrap() .iter() - .filter_map(|result| deserialize_transaction_json(result.clone()).ok()) + .filter_map(|result| utils::deserialize_transaction_json(result.clone()).ok()) .collect(); RpcBlockInfo { @@ -432,10 +374,7 @@ impl RpcState { } } - pub fn get_contract_class( - &self, - class_hash: &starknet_api::core::ClassHash, - ) -> BlockifierContractClass { + pub fn get_contract_class(&self, class_hash: &ClassHash) -> SNContractClass { let params = ureq::json!({ "jsonrpc": "2.0", "method": "starknet_getClass", @@ -443,37 +382,7 @@ impl RpcState { "id": 1 }); - let response = self.rpc_call_result(¶ms).unwrap(); - - match response { - SNContractClass::Legacy(compressed_legacy_cc) => { - let as_str = utils::decode_reader(compressed_legacy_cc.program).unwrap(); - let program = Program::from_bytes(as_str.as_bytes(), None).unwrap(); - let entry_points_by_type = utils::map_entry_points_by_type_legacy( - compressed_legacy_cc.entry_points_by_type, - ); - let inner = Arc::new(ContractClassV0Inner { - program, - entry_points_by_type, - }); - BlockifierContractClass::V0(ContractClassV0(inner)) - } - SNContractClass::Sierra(flattened_sierra_cc) => { - let middle_sierra: utils::MiddleSierraContractClass = { - let v = serde_json::to_value(flattened_sierra_cc).unwrap(); - serde_json::from_value(v).unwrap() - }; - let sierra_cc = SierraContractClass { - sierra_program: middle_sierra.sierra_program, - contract_class_version: middle_sierra.contract_class_version, - entry_points_by_type: middle_sierra.entry_points_by_type, - sierra_program_debug_info: None, - abi: None, - }; - let casm_cc = CasmContractClass::from_contract_class(sierra_cc, false).unwrap(); - BlockifierContractClass::V1(casm_cc.try_into().unwrap()) - } - } + self.rpc_call_result(¶ms).unwrap() } pub fn get_class_hash_at(&self, contract_address: &ContractAddress) -> ClassHash { @@ -574,8 +483,8 @@ mod utils { entry_points_by_type_map } - // Uncompresses a Gz Encoded vector of bytes and returns a string or error - // Here &[u8] implements BufRead + /// Uncompresses a Gz Encoded vector of bytes and returns a string or error + /// Here &[u8] implements BufRead pub(crate) fn decode_reader(bytes: Vec) -> io::Result { use flate2::bufread; let mut gz = bufread::GzDecoder::new(&bytes[..]); @@ -583,6 +492,31 @@ mod utils { gz.read_to_string(&mut s)?; Ok(s) } + + /// Freestanding deserialize method to avoid a new type. + pub(crate) fn deserialize_transaction_json( + transaction: serde_json::Value, + ) -> serde_json::Result { + let tx_type: String = serde_json::from_value(transaction["type"].clone())?; + let tx_version: String = serde_json::from_value(transaction["version"].clone())?; + + match tx_type.as_str() { + "INVOKE" => match tx_version.as_str() { + "0x0" => Ok(SNTransaction::Invoke(InvokeTransaction::V0( + serde_json::from_value(transaction)?, + ))), + "0x1" => Ok(SNTransaction::Invoke(InvokeTransaction::V1( + serde_json::from_value(transaction)?, + ))), + x => Err(serde::de::Error::custom(format!( + "unimplemented invoke version: {x}" + ))), + }, + x => Err(serde::de::Error::custom(format!( + "unimplemented transaction type deserialization: {x}" + ))), + } + } } #[cfg(test)] @@ -592,6 +526,9 @@ mod tests { hash::StarkFelt, stark_felt, }; + use starknet_in_rust::{ + definitions::block_context::StarknetChainId, transaction::InvokeFunction, + }; use super::*; @@ -684,6 +621,23 @@ mod tests { rpc_state.get_transaction(&tx_hash); } + #[test] + fn test_try_from_invoke() { + let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + let tx_hash = TransactionHash(stark_felt!( + "06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955" + )); + + let tx = rpc_state.get_transaction(&tx_hash); + match tx { + SNTransaction::Invoke(tx) => { + InvokeFunction::from_invoke_transaction(tx, StarknetChainId::MainNet) + } + _ => unreachable!(), + } + .unwrap(); + } + #[test] fn test_get_block_info() { let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); @@ -747,7 +701,7 @@ mod tests { assert_eq!(tx_trace.validate_invocation.internal_calls.len(), 1); assert_eq!( - tx_trace.function_invocation.calldata, + tx_trace.function_invocation.as_ref().unwrap().calldata, Some(vec![ stark_felt!("1"), stark_felt!("690c876e61beda61e994543af68038edac4e1cb1990ab06e52a2d27e56a1232"), @@ -767,11 +721,15 @@ mod tests { ]) ); assert_eq!( - tx_trace.function_invocation.retdata, + tx_trace.function_invocation.as_ref().unwrap().retdata, Some(vec![0u128.into()]) ); assert_eq!( - tx_trace.function_invocation.execution_resources, + tx_trace + .function_invocation + .as_ref() + .unwrap() + .execution_resources, VmExecutionResources { n_steps: 2808, n_memory_holes: 136, @@ -781,15 +739,32 @@ mod tests { ]), } ); - assert_eq!(tx_trace.function_invocation.internal_calls.len(), 1); assert_eq!( - tx_trace.function_invocation.internal_calls[0] + tx_trace + .function_invocation + .as_ref() + .unwrap() .internal_calls .len(), 1 ); assert_eq!( - tx_trace.function_invocation.internal_calls[0].internal_calls[0] + tx_trace + .function_invocation + .as_ref() + .unwrap() + .internal_calls[0] + .internal_calls + .len(), + 1 + ); + assert_eq!( + tx_trace + .function_invocation + .as_ref() + .unwrap() + .internal_calls[0] + .internal_calls[0] .internal_calls .len(), 7 @@ -882,7 +857,35 @@ mod blockifier_transaction_tests { &mut self, class_hash: &ClassHash, ) -> StateResult { - Ok(self.0.get_contract_class(class_hash)) + Ok(match self.0.get_contract_class(class_hash) { + SNContractClass::Legacy(compressed_legacy_cc) => { + let as_str = utils::decode_reader(compressed_legacy_cc.program).unwrap(); + let program = Program::from_bytes(as_str.as_bytes(), None).unwrap(); + let entry_points_by_type = utils::map_entry_points_by_type_legacy( + compressed_legacy_cc.entry_points_by_type, + ); + let inner = Arc::new(ContractClassV0Inner { + program, + entry_points_by_type, + }); + BlockifierContractClass::V0(ContractClassV0(inner)) + } + SNContractClass::Sierra(flattened_sierra_cc) => { + let middle_sierra: utils::MiddleSierraContractClass = { + let v = serde_json::to_value(flattened_sierra_cc).unwrap(); + serde_json::from_value(v).unwrap() + }; + let sierra_cc = SierraContractClass { + sierra_program: middle_sierra.sierra_program, + contract_class_version: middle_sierra.contract_class_version, + entry_points_by_type: middle_sierra.entry_points_by_type, + sierra_program_debug_info: None, + abi: None, + }; + let casm_cc = CasmContractClass::from_contract_class(sierra_cc, false).unwrap(); + BlockifierContractClass::V1(casm_cc.try_into().unwrap()) + } + }) } /// Returns the compiled class hash of the given class hash. @@ -969,7 +972,7 @@ mod blockifier_transaction_tests { // Map starknet_api transaction to blockifier's let blockifier_tx = match sn_api_tx { - Transaction::Invoke(tx) => { + SNTransaction::Invoke(tx) => { let invoke = InvokeTransaction { tx, tx_hash }; AccountTransaction::Invoke(invoke) } @@ -1020,13 +1023,247 @@ mod blockifier_transaction_tests { .. } = execute_call_info.unwrap(); - assert_eq!(vm_resources, trace.function_invocation.execution_resources); + assert_eq!(actual_fee.0, receipt.actual_fee); + assert_eq!( + vm_resources, + trace + .function_invocation + .as_ref() + .unwrap() + .execution_resources + ); assert_eq!( inner_calls.len(), - trace.function_invocation.internal_calls.len() + trace + .function_invocation + .as_ref() + .unwrap() + .internal_calls + .len() + ); + } + } +} + +mod starknet_in_rust_transaction_tests { + use cairo_vm::felt::{felt_str, Felt252}; + use starknet_api::{core::PatriciaKey, stark_felt, transaction::TransactionHash}; + use starknet_in_rust::{ + core::errors::state_errors::StateError, + definitions::{ + block_context::{BlockContext, StarknetChainId, StarknetOsConfig}, + constants::{ + DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS, + DEFAULT_CONTRACT_STORAGE_COMMITMENT_TREE_HEIGHT, + DEFAULT_GLOBAL_STATE_COMMITMENT_TREE_HEIGHT, DEFAULT_INVOKE_TX_MAX_N_STEPS, + DEFAULT_VALIDATE_MAX_N_STEPS, + }, + }, + execution::TransactionExecutionInfo, + services::api::contract_classes::compiled_class::CompiledClass, + state::{ + cached_state::{CachedState, ContractClassCache}, + state_api::StateReader, + state_cache::StorageEntry, + BlockInfo, + }, + transaction::{InvokeFunction, Transaction}, + utils::{Address, ClassHash}, + }; + + use super::*; + + pub struct RpcStateReader(RpcState); + + impl StateReader for RpcStateReader { + fn get_contract_class(&self, class_hash: &ClassHash) -> Result { + let hash = ClassHash(StarkHash::new(*class_hash).unwrap()); + Ok(CompiledClass::from(self.0.get_contract_class(&hash))) + } + + fn get_class_hash_at(&self, contract_address: &Address) -> Result { + let address = ContractAddress( + PatriciaKey::try_from( + StarkHash::new(contract_address.clone().0.to_be_bytes()).unwrap(), + ) + .unwrap(), ); + let mut bytes = [0u8; 32]; + bytes.copy_from_slice(self.0.get_class_hash_at(&address).0.bytes()); + Ok(bytes) + } - assert_eq!(actual_fee.0, receipt.actual_fee); + fn get_nonce_at(&self, contract_address: &Address) -> Result { + let address = ContractAddress( + PatriciaKey::try_from( + StarkHash::new(contract_address.clone().0.to_be_bytes()).unwrap(), + ) + .unwrap(), + ); + let nonce = self.0.get_nonce_at(&address); + Ok(Felt252::from_bytes_be(nonce.bytes())) + } + fn get_storage_at(&self, storage_entry: &StorageEntry) -> Result { + let (contract_address, key) = storage_entry; + let address = ContractAddress( + PatriciaKey::try_from( + StarkHash::new(contract_address.clone().0.to_be_bytes()).unwrap(), + ) + .unwrap(), + ); + let key = StorageKey(PatriciaKey::try_from(StarkHash::new(*key).unwrap()).unwrap()); + let value = self.0.get_storage_at(&address, &key); + Ok(Felt252::from_bytes_be(value.bytes())) + } + fn get_compiled_class_hash(&self, class_hash: &ClassHash) -> Result<[u8; 32], StateError> { + let address = ContractAddress( + PatriciaKey::try_from(StarkHash::new(*class_hash).unwrap()).unwrap(), + ); + let mut bytes = [0u8; 32]; + bytes.copy_from_slice(self.0.get_class_hash_at(&address).0.bytes()); + Ok(bytes) + } + } + + #[allow(unused)] + pub fn execute_tx( + tx_hash: &str, + network: RpcChain, + block_number: BlockNumber, + ) -> ( + TransactionExecutionInfo, + TransactionTrace, + RpcTransactionReceipt, + ) { + let fee_token_address = Address(felt_str!( + "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + 16 + )); + + let tx_hash = tx_hash.strip_prefix("0x").unwrap(); + + // Instantiate the RPC StateReader and the CachedState + let rpc_reader = RpcStateReader(RpcState::new(network, block_number.into())); + let gas_price = rpc_reader.0.get_gas_price(block_number.0).unwrap(); + + // Get values for block context before giving ownership of the reader + let chain_id = match rpc_reader.0.chain { + RpcChain::MainNet => StarknetChainId::MainNet, + RpcChain::TestNet => StarknetChainId::TestNet, + RpcChain::TestNet2 => StarknetChainId::TestNet2, + }; + let starknet_os_config = + StarknetOsConfig::new(chain_id.to_felt(), fee_token_address, gas_price); + let block_info = { + let RpcBlockInfo { + block_number, + block_timestamp, + sequencer_address, + .. + } = rpc_reader.0.get_block_info(); + + let block_number = block_number.0; + let block_timestamp = block_timestamp.0; + let sequencer_address = + Address(Felt252::from_bytes_be(sequencer_address.0.key().bytes())); + + BlockInfo { + block_number, + block_timestamp, + gas_price, + sequencer_address, + } + }; + + // Get transaction before giving ownership of the reader + let tx_hash = TransactionHash(stark_felt!(tx_hash)); + let tx = match rpc_reader.0.get_transaction(&tx_hash) { + SNTransaction::Invoke(tx) => Transaction::InvokeFunction( + InvokeFunction::from_invoke_transaction(tx, chain_id).unwrap(), + ), + _ => unimplemented!(), + }; + + let trace = rpc_reader.0.get_transaction_trace(&tx_hash); + let receipt = rpc_reader.0.get_transaction_receipt(&tx_hash); + + let class_cache = ContractClassCache::default(); + let mut state = CachedState::new(Arc::new(rpc_reader), class_cache); + + let block_context = BlockContext::new( + starknet_os_config, + DEFAULT_CONTRACT_STORAGE_COMMITMENT_TREE_HEIGHT, + DEFAULT_GLOBAL_STATE_COMMITMENT_TREE_HEIGHT, + DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS.clone(), + DEFAULT_INVOKE_TX_MAX_N_STEPS, + DEFAULT_VALIDATE_MAX_N_STEPS, + block_info, + Default::default(), + true, + ); + + ( + tx.execute(&mut state, &block_context, u128::MAX).unwrap(), + trace, + receipt, + ) + } + + #[cfg(test)] + mod test { + use starknet_in_rust::execution::CallInfo; + + use super::*; + + #[test] + fn test_get_gas_price() { + let block = BlockValue::Number(BlockNumber(169928)); + let rpc_state = RpcState::new(RpcChain::MainNet, block); + + let price = rpc_state.get_gas_price(169928).unwrap(); + assert_eq!(price, 22804578690); + } + + #[test] + #[ignore = "working on fixes"] + fn test_recent_tx() { + let (tx_info, trace, receipt) = execute_tx( + "0x05d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91", + RpcChain::MainNet, + BlockNumber(169928), + ); + + let TransactionExecutionInfo { + call_info, + actual_fee, + .. + } = tx_info; + + let CallInfo { + execution_resources, + internal_calls, + .. + } = call_info.unwrap(); + + assert_eq!( + execution_resources, + trace + .function_invocation + .as_ref() + .unwrap() + .execution_resources + ); + assert_eq!( + internal_calls.len(), + trace + .function_invocation + .as_ref() + .unwrap() + .internal_calls + .len() + ); + + assert_eq!(actual_fee, receipt.actual_fee); } } } diff --git a/src/transaction/invoke_function.rs b/src/transaction/invoke_function.rs index 1f2cc3e08..f05e3e942 100644 --- a/src/transaction/invoke_function.rs +++ b/src/transaction/invoke_function.rs @@ -124,15 +124,10 @@ impl InvokeFunction { pub fn from_invoke_transaction( tx: starknet_api::transaction::InvokeTransaction, chain_id: StarknetChainId, - version: Felt252, ) -> Result { match tx { - starknet_api::transaction::InvokeTransaction::V0(v0) => { - convert_invoke_v0(v0, chain_id, version) - } - starknet_api::transaction::InvokeTransaction::V1(v1) => { - convert_invoke_v1(v1, chain_id, version) - } + starknet_api::transaction::InvokeTransaction::V0(v0) => convert_invoke_v0(v0, chain_id), + starknet_api::transaction::InvokeTransaction::V1(v1) => convert_invoke_v1(v1, chain_id), } } @@ -423,7 +418,6 @@ pub(crate) fn preprocess_invoke_function_fields( fn convert_invoke_v0( value: starknet_api::transaction::InvokeTransactionV0, chain_id: StarknetChainId, - version: Felt252, ) -> Result { let contract_address = Address(Felt252::from_bytes_be( value.contract_address.0.key().bytes(), @@ -450,7 +444,7 @@ fn convert_invoke_v0( contract_address, entry_point_selector, max_fee, - version, + Felt252::new(0), calldata, signature, chain_id.to_felt(), @@ -461,7 +455,6 @@ fn convert_invoke_v0( fn convert_invoke_v1( value: starknet_api::transaction::InvokeTransactionV1, chain_id: StarknetChainId, - version: Felt252, ) -> Result { let contract_address = Address(Felt252::from_bytes_be(value.sender_address.0.key().bytes())); let max_fee = value.max_fee.0; @@ -486,7 +479,7 @@ fn convert_invoke_v1( contract_address, entry_point_selector, max_fee, - version, + Felt252::new(1), calldata, signature, chain_id.to_felt(), @@ -506,7 +499,7 @@ mod tests { utils::calculate_sn_keccak, }; use cairo_lang_starknet::casm_contract_class::CasmContractClass; - use num_traits::{Num, One}; + use num_traits::Num; use starknet_api::{ core::{ContractAddress, Nonce, PatriciaKey}, hash::{StarkFelt, StarkHash}, @@ -573,9 +566,7 @@ mod tests { ])), }); - let tx_sir = - InvokeFunction::from_invoke_transaction(tx, StarknetChainId::MainNet, Felt252::one()) - .unwrap(); + let tx_sir = InvokeFunction::from_invoke_transaction(tx, StarknetChainId::MainNet).unwrap(); assert_eq!( tx_sir.hash_value.to_str_radix(16), "5b6cf416d56e7c7c519b44e6d06a41657ff6c6a3f2629044fac395e6d200ac4" From b697c580af9ed2ce4ab43dcb194977e2921f2c0b Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Tue, 5 Sep 2023 14:26:27 -0300 Subject: [PATCH 17/44] perf: remove clone from compute_sierra_class_hash (#1008) --- src/core/contract_address/sierra_contract_address.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/contract_address/sierra_contract_address.rs b/src/core/contract_address/sierra_contract_address.rs index 1cefac37d..1bbcfb1e9 100644 --- a/src/core/contract_address/sierra_contract_address.rs +++ b/src/core/contract_address/sierra_contract_address.rs @@ -63,7 +63,7 @@ pub fn compute_sierra_class_hash( let abi = serde_json_pythonic::to_string_pythonic( &contract_class .abi - .clone() + .as_ref() .ok_or(ContractAddressError::MissingAbi)? .items, ) From a7493d10716bccdb7acc05274684f2f9e25ee5cf Mon Sep 17 00:00:00 2001 From: fmoletta <99273364+fmoletta@users.noreply.github.com> Date: Tue, 5 Sep 2023 21:29:49 +0300 Subject: [PATCH 18/44] fix: Read before writing when executing the deprecated version of `storate_write` syscall (#1006) * Read before writing * Add test * Fix some tests * Fix test * Fix test * Fix test * Fix test * Fix tests * Fix tests * Fix tests --- ...precated_business_logic_syscall_handler.rs | 36 ++++++++++++-- src/transaction/l1_handler.rs | 2 +- tests/complex_contracts/amm_contracts/amm.rs | 12 ++++- .../amm_contracts/amm_proxy.rs | 18 +++++-- tests/complex_contracts/nft/erc721.rs | 26 ++++++---- tests/increase_balance.rs | 2 +- tests/internals.rs | 48 ++++++++++++------- tests/storage.rs | 2 +- tests/syscalls.rs | 13 ++--- 9 files changed, 115 insertions(+), 44 deletions(-) diff --git a/src/syscalls/deprecated_business_logic_syscall_handler.rs b/src/syscalls/deprecated_business_logic_syscall_handler.rs index 1de042db5..6f8108de4 100644 --- a/src/syscalls/deprecated_business_logic_syscall_handler.rs +++ b/src/syscalls/deprecated_business_logic_syscall_handler.rs @@ -872,8 +872,9 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { address: Address, value: Felt252, ) -> Result<(), SyscallHandlerError> { - self.starknet_storage_state - .write(&felt_to_hash(&address.0), value); + let address = felt_to_hash(&address.0); + self.starknet_storage_state.read(&address)?; + self.starknet_storage_state.write(&address, value); Ok(()) } @@ -978,7 +979,7 @@ mod tests { state::cached_state::CachedState, state::in_memory_state_reader::InMemoryStateReader, syscalls::syscall_handler_errors::SyscallHandlerError, - utils::{test_utils::*, Address}, + utils::{felt_to_hash, test_utils::*, Address}, }; use cairo_vm::felt::Felt252; use cairo_vm::hint_processor::hint_processor_definition::HintProcessorLogic; @@ -993,8 +994,8 @@ mod tests { }, vm::{errors::memory_errors::MemoryError, vm_core::VirtualMachine}, }; - use num_traits::Zero; - use std::{any::Any, borrow::Cow, collections::HashMap}; + use num_traits::{One, Zero}; + use std::{any::Any, borrow::Cow, collections::HashMap, sync::Arc}; type DeprecatedBLSyscallHandler<'a> = super::DeprecatedBLSyscallHandler<'a, InMemoryStateReader>; @@ -1111,4 +1112,29 @@ mod tests { Ok(value) if value == Felt252::zero() ); } + + #[test] + fn test_storage_write_update_initial_values() { + // Initialize state reader with value + let mut state_reader = InMemoryStateReader::default(); + state_reader.address_to_storage.insert( + (Address(Felt252::one()), felt_to_hash(&Felt252::one())), + Felt252::zero(), + ); + // Create empty-cached state + let mut state = CachedState::new(Arc::new(state_reader), HashMap::new()); + let mut syscall_handler = DeprecatedBLSyscallHandler::default_with(&mut state); + // Perform write + assert!(syscall_handler + .syscall_storage_write(Address(Felt252::one()), Felt252::one()) + .is_ok()); + // Check that initial values have beed updated in the cache + assert_eq!( + state.cache().storage_initial_values, + HashMap::from([( + (Address(Felt252::one()), felt_to_hash(&Felt252::one())), + Felt252::zero() + )]) + ) + } } diff --git a/src/transaction/l1_handler.rs b/src/transaction/l1_handler.rs index ea4bb95a8..d08d8ccf5 100644 --- a/src/transaction/l1_handler.rs +++ b/src/transaction/l1_handler.rs @@ -323,7 +323,7 @@ mod test { }, events: vec![], l2_to_l1_messages: vec![], - storage_read_values: vec![0.into()], + storage_read_values: vec![0.into(), 0.into()], accessed_storage_keys: HashSet::from([[ 4, 40, 11, 247, 0, 35, 63, 18, 141, 159, 101, 81, 182, 2, 213, 216, 100, 110, 5, 5, 101, 122, 13, 252, 204, 72, 77, 8, 58, 226, 194, 24, diff --git a/tests/complex_contracts/amm_contracts/amm.rs b/tests/complex_contracts/amm_contracts/amm.rs index 6f987ed64..a750eb3f8 100644 --- a/tests/complex_contracts/amm_contracts/amm.rs +++ b/tests/complex_contracts/amm_contracts/amm.rs @@ -97,6 +97,7 @@ fn amm_init_pool_test() { }, class_hash: Some(class_hash), accessed_storage_keys, + storage_read_values: vec![Felt252::zero(), Felt252::zero()], ..Default::default() }; @@ -182,7 +183,12 @@ fn amm_add_demo_tokens_test() { }, class_hash: Some(class_hash), accessed_storage_keys: accessed_storage_keys_add_demo_token, - storage_read_values: vec![Felt252::zero(), Felt252::zero()], + storage_read_values: vec![ + Felt252::zero(), + Felt252::zero(), + Felt252::zero(), + Felt252::zero(), + ], ..Default::default() }; @@ -351,6 +357,10 @@ fn amm_swap_test() { 10000.into(), 100.into(), 100.into(), + 10000.into(), + 100.into(), + 100.into(), + 10000.into(), ] .to_vec(), ..Default::default() diff --git a/tests/complex_contracts/amm_contracts/amm_proxy.rs b/tests/complex_contracts/amm_contracts/amm_proxy.rs index ed6834e09..b4196d833 100644 --- a/tests/complex_contracts/amm_contracts/amm_proxy.rs +++ b/tests/complex_contracts/amm_contracts/amm_proxy.rs @@ -1,6 +1,7 @@ use crate::complex_contracts::utils::*; use cairo_vm::felt::Felt252; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; +use num_traits::Zero; use starknet_crypto::FieldElement; use starknet_in_rust::definitions::block_context::BlockContext; use starknet_in_rust::services::api::contract_classes::deprecated_contract_class::ContractClass; @@ -84,6 +85,7 @@ fn amm_proxy_init_pool_test() { }, class_hash: Some(contract_class_hash), accessed_storage_keys, + storage_read_values: vec![Felt252::zero(), Felt252::zero()], ..Default::default() }]; @@ -288,7 +290,7 @@ fn amm_proxy_add_demo_token_test() { entry_point_selector: Some(amm_entrypoint_selector), entry_point_type: Some(EntryPointType::External), calldata: calldata.clone()[1..].to_vec(), - storage_read_values: vec![0.into(), 0.into()], + storage_read_values: vec![0.into(), 0.into(), 0.into(), 0.into()], execution_resources: ExecutionResources { n_steps: 397, n_memory_holes: 42, @@ -539,8 +541,18 @@ fn amm_proxy_swap() { entry_point_type: Some(EntryPointType::External), calldata: calldata.clone()[1..].to_vec(), retdata: [90.into()].to_vec(), - storage_read_values: [100.into(), 1000.into(), 1000.into(), 100.into(), 200.into()] - .to_vec(), + storage_read_values: [ + 100.into(), + 1000.into(), + 1000.into(), + 100.into(), + 100.into(), + 1000.into(), + 200.into(), + 200.into(), + 1000.into(), + ] + .to_vec(), execution_resources: ExecutionResources { n_steps: 826, n_memory_holes: 92, diff --git a/tests/complex_contracts/nft/erc721.rs b/tests/complex_contracts/nft/erc721.rs index 417eb18cd..0961d9ff8 100644 --- a/tests/complex_contracts/nft/erc721.rs +++ b/tests/complex_contracts/nft/erc721.rs @@ -474,7 +474,7 @@ fn erc721_test_approve() { let expected_read_result = vec![]; // Checks only the storage variable ERC721_operator_approvals - let storage_read_values = vec![Felt252::from(666), Felt252::from(666)]; + let storage_read_values = vec![Felt252::from(666), Felt252::zero(), Felt252::from(666)]; // Ask for the owner of the token let mut accessed_storage_keys = @@ -577,7 +577,7 @@ fn erc721_set_approval_for_all() { let expected_read_result = vec![]; // Only writes in operator_approvals - let storage_read_values = vec![]; + let storage_read_values = vec![Felt252::zero()]; // Writes to the operator the new set value let accessed_storage_keys = get_accessed_keys( @@ -696,14 +696,20 @@ fn erc721_transfer_from_test() { accessed_storage_keys.insert(balance_to); let expected_read_values = vec![ - Felt252::from(666), - Felt252::from(666), - Felt252::from(666), - Felt252::from(666), - Felt252::from(1), - Felt252::zero(), - Felt252::zero(), - Felt252::zero(), + 666.into(), + 666.into(), + 666.into(), + 0.into(), + 666.into(), + 1.into(), + 0.into(), + 1.into(), + 0.into(), + 0.into(), + 0.into(), + 0.into(), + 0.into(), + 666.into(), ]; let approval_event_hash = Felt252::from_bytes_be(&calculate_sn_keccak("Approval".as_bytes())); diff --git a/tests/increase_balance.rs b/tests/increase_balance.rs index 141583e7b..678182e5d 100644 --- a/tests/increase_balance.rs +++ b/tests/increase_balance.rs @@ -112,7 +112,7 @@ fn hello_starknet_increase_balance() { let mut expected_accessed_storage_keys = HashSet::new(); expected_accessed_storage_keys.insert(expected_key); - let expected_storage_read_values = vec![Felt252::zero()]; + let expected_storage_read_values = vec![Felt252::zero(), Felt252::zero()]; let expected_call_info = CallInfo { caller_address: Address(0.into()), diff --git a/tests/internals.rs b/tests/internals.rs index d089ac2c1..7d6d6ab92 100644 --- a/tests/internals.rs +++ b/tests/internals.rs @@ -469,6 +469,10 @@ fn expected_fee_transfer_call_info( storage_read_values: vec![ INITIAL_BALANCE.clone(), Felt252::zero(), + INITIAL_BALANCE.clone(), + Felt252::zero(), + Felt252::zero(), + Felt252::zero(), Felt252::zero(), Felt252::zero(), ], @@ -636,15 +640,19 @@ fn expected_fee_transfer_info(fee: u128) -> CallInfo { ], }], storage_read_values: vec![ + INITIAL_BALANCE.clone(), + Felt252::zero(), INITIAL_BALANCE.clone(), Felt252::zero(), Felt252::zero(), Felt252::zero(), + Felt252::zero(), + Felt252::zero(), ], accessed_storage_keys: HashSet::from([ [ 7, 35, 151, 50, 8, 99, 155, 120, 57, 206, 41, 143, 127, 254, 166, 30, 63, 149, 51, - 135, 45, 239, 215, 171, 219, 145, 2, 61, 180, 101, 136, 19, + 135, 45, 239, 215, 171, 219, 145, 2, 61, 180, 101, 136, 18, ], [ 2, 162, 196, 156, 77, 186, 13, 145, 179, 79, 42, 222, 133, 212, 29, 9, 86, 31, 154, @@ -652,7 +660,7 @@ fn expected_fee_transfer_info(fee: u128) -> CallInfo { ], [ 7, 35, 151, 50, 8, 99, 155, 120, 57, 206, 41, 143, 127, 254, 166, 30, 63, 149, 51, - 135, 45, 239, 215, 171, 219, 145, 2, 61, 180, 101, 136, 18, + 135, 45, 239, 215, 171, 219, 145, 2, 61, 180, 101, 136, 19, ], [ 2, 162, 196, 156, 77, 186, 13, 145, 179, 79, 42, 222, 133, 212, 29, 9, 86, 31, 154, @@ -698,26 +706,30 @@ fn expected_fib_fee_transfer_info(fee: u128) -> CallInfo { storage_read_values: vec![ INITIAL_BALANCE.clone() - Felt252::from(2476), Felt252::zero(), + INITIAL_BALANCE.clone() - Felt252::from(2476), + Felt252::zero(), + Felt252::from(2476), + Felt252::zero(), Felt252::from(2476), Felt252::zero(), ], accessed_storage_keys: HashSet::from([ - [ - 2, 162, 196, 156, 77, 186, 13, 145, 179, 79, 42, 222, 133, 212, 29, 9, 86, 31, 154, - 119, 136, 76, 21, 186, 42, 176, 242, 36, 27, 8, 13, 235, - ], [ 7, 35, 151, 50, 8, 99, 155, 120, 57, 206, 41, 143, 127, 254, 166, 30, 63, 149, 51, - 135, 45, 239, 215, 171, 219, 145, 2, 61, 180, 101, 136, 19, + 135, 45, 239, 215, 171, 219, 145, 2, 61, 180, 101, 136, 18, ], [ - 7, 35, 151, 50, 8, 99, 155, 120, 57, 206, 41, 143, 127, 254, 166, 30, 63, 149, 51, - 135, 45, 239, 215, 171, 219, 145, 2, 61, 180, 101, 136, 18, + 2, 162, 196, 156, 77, 186, 13, 145, 179, 79, 42, 222, 133, 212, 29, 9, 86, 31, 154, + 119, 136, 76, 21, 186, 42, 176, 242, 36, 27, 8, 13, 235, ], [ 2, 162, 196, 156, 77, 186, 13, 145, 179, 79, 42, 222, 133, 212, 29, 9, 86, 31, 154, 119, 136, 76, 21, 186, 42, 176, 242, 36, 27, 8, 13, 236, ], + [ + 7, 35, 151, 50, 8, 99, 155, 120, 57, 206, 41, 143, 127, 254, 166, 30, 63, 149, 51, + 135, 45, 239, 215, 171, 219, 145, 2, 61, 180, 101, 136, 19, + ], ]), } } @@ -832,27 +844,32 @@ fn expected_declare_fee_transfer_info(fee: u128) -> CallInfo { storage_read_values: vec![ INITIAL_BALANCE.clone(), Felt252::zero(), + INITIAL_BALANCE.clone(), + Felt252::zero(), + Felt252::zero(), + Felt252::zero(), Felt252::zero(), Felt252::zero(), ], accessed_storage_keys: HashSet::from([ [ 7, 35, 151, 50, 8, 99, 155, 120, 57, 206, 41, 143, 127, 254, 166, 30, 63, 149, 51, - 135, 45, 239, 215, 171, 219, 145, 2, 61, 180, 101, 136, 18, - ], - [ - 2, 162, 196, 156, 77, 186, 13, 145, 179, 79, 42, 222, 133, 212, 29, 9, 86, 31, 154, - 119, 136, 76, 21, 186, 42, 176, 242, 36, 27, 8, 13, 235, + 135, 45, 239, 215, 171, 219, 145, 2, 61, 180, 101, 136, 19, ], [ 7, 35, 151, 50, 8, 99, 155, 120, 57, 206, 41, 143, 127, 254, 166, 30, 63, 149, 51, - 135, 45, 239, 215, 171, 219, 145, 2, 61, 180, 101, 136, 19, + 135, 45, 239, 215, 171, 219, 145, 2, 61, 180, 101, 136, 18, ], [ 2, 162, 196, 156, 77, 186, 13, 145, 179, 79, 42, 222, 133, 212, 29, 9, 86, 31, 154, 119, 136, 76, 21, 186, 42, 176, 242, 36, 27, 8, 13, 236, ], + [ + 2, 162, 196, 156, 77, 186, 13, 145, 179, 79, 42, 222, 133, 212, 29, 9, 86, 31, 154, + 119, 136, 76, 21, 186, 42, 176, 242, 36, 27, 8, 13, 235, + ], ]), + execution_resources: ExecutionResources { n_steps: 525, n_memory_holes: 59, @@ -1287,7 +1304,6 @@ fn test_invoke_tx() { // transaction. let result = invoke_tx.execute(state, block_context, 0).unwrap(); let expected_execution_info = expected_transaction_execution_info(block_context); - assert_eq!(result, expected_execution_info); } diff --git a/tests/storage.rs b/tests/storage.rs index f13bc141c..b75a55ba6 100644 --- a/tests/storage.rs +++ b/tests/storage.rs @@ -124,7 +124,7 @@ fn integration_storage_test() { ..Default::default() }, class_hash: Some(class_hash), - storage_read_values: vec![42.into()], + storage_read_values: vec![0.into(), 42.into()], accessed_storage_keys: expected_accessed_storage_keys, ..Default::default() }; diff --git a/tests/syscalls.rs b/tests/syscalls.rs index 03bfd188f..6672c7d5e 100644 --- a/tests/syscalls.rs +++ b/tests/syscalls.rs @@ -190,7 +190,7 @@ fn call_contract_syscall() { None, [], [], - [10.into()], + [0.into(), 10.into()], [calculate_sn_keccak("lib_state".as_bytes())].into_iter(), [( [2u8; 32], @@ -229,7 +229,7 @@ fn call_contract_syscall() { "1785358123477195475640323002883645042461033713657726545236059599395452130340" )), entry_point_type: Some(EntryPointType::External), - storage_read_values: vec![10.into()], + storage_read_values: vec![10.into(), 10.into()], accessed_storage_keys: [[ 3, 189, 169, 58, 108, 116, 165, 116, 249, 48, 17, 133, 28, 149, 186, 141, 157, 76, 34, 41, 77, 210, 154, 246, 164, 151, 207, 138, 139, 182, 155, 161, @@ -685,7 +685,7 @@ fn library_call_syscall() { None, [], [], - [11.into()], + [0.into(), 11.into()], [calculate_sn_keccak("lib_state".as_bytes())].into_iter(), [( [2; 32], @@ -722,7 +722,7 @@ fn library_call_syscall() { "1785358123477195475640323002883645042461033713657726545236059599395452130340" )), entry_point_type: Some(EntryPointType::External), - storage_read_values: vec![10.into()], + storage_read_values: vec![10.into(), 10.into()], accessed_storage_keys: [[ 3, 189, 169, 58, 108, 116, 165, 116, 249, 48, 17, 133, 28, 149, 186, 141, 157, 76, 34, 41, 77, 210, 154, 246, 164, 151, 207, 138, 139, 182, 155, 161, @@ -800,6 +800,7 @@ fn library_call_l1_handler_syscall() { ]] .into_iter() .collect(), + storage_read_values: vec![0.into()], execution_resources: ExecutionResources { n_steps: 40, ..Default::default() @@ -998,7 +999,7 @@ fn test_deploy_and_call_contract_syscall() { entry_point_type: Some(EntryPointType::External), calldata: vec![4.into()], retdata: vec![(constructor_constant.clone() * Felt252::new(4))], - storage_read_values: vec![constructor_constant], + storage_read_values: vec![constructor_constant.clone()], accessed_storage_keys: HashSet::from([constant_storage_key]), execution_resources: ExecutionResources { n_steps: 52, @@ -1023,7 +1024,7 @@ fn test_deploy_and_call_contract_syscall() { entry_point_type: Some(EntryPointType::External), calldata: vec![new_constant.clone()], retdata: vec![], - storage_read_values: vec![], + storage_read_values: vec![constructor_constant], accessed_storage_keys: HashSet::from([constant_storage_key]), execution_resources: ExecutionResources { n_steps: 40, From 2dd1c8fb4abc893c8b3aaff830b1fac2f7f9e869 Mon Sep 17 00:00:00 2001 From: fmoletta <99273364+fmoletta@users.noreply.github.com> Date: Wed, 6 Sep 2023 00:30:40 +0300 Subject: [PATCH 19/44] BREAKING: `StateReader::get_storage_at` return zero by default (#1011) * update InMemoryStateReader & CachedState * Add comments * Apply changes to State implementation too * Fix behaviour * Add test --- src/state/cached_state.rs | 53 ++++++++--------------------- src/state/in_memory_state_reader.rs | 17 +++++++-- src/state/state_api.rs | 3 ++ 3 files changed, 32 insertions(+), 41 deletions(-) diff --git a/src/state/cached_state.rs b/src/state/cached_state.rs index 98b37deb6..2a63a88cf 100644 --- a/src/state/cached_state.rs +++ b/src/state/cached_state.rs @@ -105,28 +105,12 @@ impl StateReader for CachedState { } /// Returns storage data for a given storage entry. + /// Returns zero as default value if missing fn get_storage_at(&self, storage_entry: &StorageEntry) -> Result { - if self.cache.get_storage(storage_entry).is_none() { - match self.state_reader.get_storage_at(storage_entry) { - Ok(storage) => { - return Ok(storage); - } - Err( - StateError::EmptyKeyInStorage - | StateError::NoneStoragLeaf(_) - | StateError::NoneStorage(_) - | StateError::NoneContractState(_), - ) => return Ok(Felt252::zero()), - Err(e) => { - return Err(e); - } - } - } - self.cache .get_storage(storage_entry) - .ok_or_else(|| StateError::NoneStorage(storage_entry.clone())) - .cloned() + .map(|v| Ok(v.clone())) + .unwrap_or_else(|| self.state_reader.get_storage_at(storage_entry)) } // TODO: check if that the proper way to store it (converting hash to address) @@ -353,27 +337,20 @@ impl State for CachedState { .clone()) } + /// Returns storage data for a given storage entry. + /// Returns zero as default value if missing + /// Adds the value to the cache's inital_values if not present fn get_storage_at(&mut self, storage_entry: &StorageEntry) -> Result { - if self.cache.get_storage(storage_entry).is_none() { - let value = match self.state_reader.get_storage_at(storage_entry) { - Ok(value) => value, - Err( - StateError::EmptyKeyInStorage - | StateError::NoneStoragLeaf(_) - | StateError::NoneStorage(_) - | StateError::NoneContractState(_), - ) => Felt252::zero(), - Err(e) => return Err(e), - }; - self.cache - .storage_initial_values - .insert(storage_entry.clone(), value); + match self.cache.get_storage(storage_entry) { + Some(value) => Ok(value.clone()), + None => { + let value = self.state_reader.get_storage_at(storage_entry)?; + self.cache + .storage_initial_values + .insert(storage_entry.clone(), value.clone()); + Ok(value) + } } - - self.cache - .get_storage(storage_entry) - .ok_or_else(|| StateError::NoneStorage(storage_entry.clone())) - .cloned() } // TODO: check if that the proper way to store it (converting hash to address) diff --git a/src/state/in_memory_state_reader.rs b/src/state/in_memory_state_reader.rs index 2d6a001f7..82c0dc734 100644 --- a/src/state/in_memory_state_reader.rs +++ b/src/state/in_memory_state_reader.rs @@ -97,11 +97,11 @@ impl StateReader for InMemoryStateReader { } fn get_storage_at(&self, storage_entry: &StorageEntry) -> Result { - let storage = self + Ok(self .address_to_storage .get(storage_entry) - .ok_or_else(|| StateError::NoneStorage(storage_entry.clone())); - storage.cloned() + .cloned() + .unwrap_or_default()) } fn get_compiled_class_hash( @@ -132,10 +132,21 @@ impl StateReader for InMemoryStateReader { #[cfg(test)] mod tests { + use num_traits::One; + use super::*; use crate::services::api::contract_classes::deprecated_contract_class::ContractClass; use std::sync::Arc; + #[test] + fn get_storage_returns_zero_if_missing() { + let state_reader = InMemoryStateReader::default(); + assert!(state_reader + .get_storage_at(&(Address(Felt252::one()), Felt252::one().to_be_bytes())) + .unwrap() + .is_zero()) + } + #[test] fn get_contract_state_test() { let mut state_reader = InMemoryStateReader::new( diff --git a/src/state/state_api.rs b/src/state/state_api.rs index edeab04de..663ba5825 100644 --- a/src/state/state_api.rs +++ b/src/state/state_api.rs @@ -16,6 +16,7 @@ pub trait StateReader { /// Returns the nonce of the given contract instance. fn get_nonce_at(&self, contract_address: &Address) -> Result; /// Returns the storage value under the given key in the given contract instance. + /// Returns zero by default if the value is not present fn get_storage_at(&self, storage_entry: &StorageEntry) -> Result; /// Return the class hash of the given casm contract class fn get_compiled_class_hash( @@ -65,6 +66,8 @@ pub trait State { /// Default: 0 for an uninitialized contract address. fn get_nonce_at(&mut self, contract_address: &Address) -> Result; + /// Returns storage data for a given storage entry. + /// Returns zero as default value if missing fn get_storage_at(&mut self, storage_entry: &StorageEntry) -> Result; fn get_compiled_class_hash(&mut self, class_hash: &ClassHash) -> Result; From 59243951055b2e512531985a5b5f5048e7ed96a9 Mon Sep 17 00:00:00 2001 From: fmoletta <99273364+fmoletta@users.noreply.github.com> Date: Wed, 6 Sep 2023 20:08:25 +0300 Subject: [PATCH 20/44] BREAKING: `StateReader::get_class_hash_at` return zero by default (#1012) * Use unwrap_or_default * return zero by default state reader get_class_hash_at * Add changes * clippy --- src/state/cached_state.rs | 45 ++++++++++------------------- src/state/in_memory_state_reader.rs | 27 +++++++++++------ src/state/state_api.rs | 3 ++ 3 files changed, 36 insertions(+), 39 deletions(-) diff --git a/src/state/cached_state.rs b/src/state/cached_state.rs index 2a63a88cf..ed5b4da76 100644 --- a/src/state/cached_state.rs +++ b/src/state/cached_state.rs @@ -72,25 +72,12 @@ impl CachedState { impl StateReader for CachedState { /// Returns the class hash for a given contract address. + /// Returns zero as default value if missing fn get_class_hash_at(&self, contract_address: &Address) -> Result { - if self.cache.get_class_hash(contract_address).is_none() { - match self.state_reader.get_class_hash_at(contract_address) { - Ok(class_hash) => { - return Ok(class_hash); - } - Err(StateError::NoneContractState(_)) => { - return Ok([0; 32]); - } - Err(e) => { - return Err(e); - } - } - } - self.cache .get_class_hash(contract_address) - .ok_or_else(|| StateError::NoneClassHash(contract_address.clone())) - .cloned() + .map(|a| Ok(*a)) + .unwrap_or_else(|| self.state_reader.get_class_hash_at(contract_address)) } /// Returns the nonce for a given contract address. @@ -305,22 +292,20 @@ impl State for CachedState { Ok((n_modified_contracts, storage_updates.len())) } + /// Returns the class hash for a given contract address. + /// Returns zero as default value if missing + /// Adds the value to the cache's inital_values if not present fn get_class_hash_at(&mut self, contract_address: &Address) -> Result { - if self.cache.get_class_hash(contract_address).is_none() { - let class_hash = match self.state_reader.get_class_hash_at(contract_address) { - Ok(class_hash) => class_hash, - Err(StateError::NoneContractState(_)) => [0; 32], - Err(e) => return Err(e), - }; - self.cache - .class_hash_initial_values - .insert(contract_address.clone(), class_hash); + match self.cache.get_class_hash(contract_address) { + Some(class_hash) => Ok(*class_hash), + None => { + let class_hash = self.state_reader.get_class_hash_at(contract_address)?; + self.cache + .class_hash_initial_values + .insert(contract_address.clone(), class_hash); + Ok(class_hash) + } } - - self.cache - .get_class_hash(contract_address) - .ok_or_else(|| StateError::NoneClassHash(contract_address.clone())) - .cloned() } fn get_nonce_at(&mut self, contract_address: &Address) -> Result { diff --git a/src/state/in_memory_state_reader.rs b/src/state/in_memory_state_reader.rs index 82c0dc734..ce223c830 100644 --- a/src/state/in_memory_state_reader.rs +++ b/src/state/in_memory_state_reader.rs @@ -8,7 +8,6 @@ use crate::{ }; use cairo_vm::felt::Felt252; use getset::{Getters, MutGetters}; -use num_traits::Zero; use std::collections::HashMap; /// A [StateReader] that holds all the data in memory. @@ -80,20 +79,19 @@ impl InMemoryStateReader { impl StateReader for InMemoryStateReader { fn get_class_hash_at(&self, contract_address: &Address) -> Result { - let class_hash = self + Ok(self .address_to_class_hash .get(contract_address) - .ok_or_else(|| StateError::NoneContractState(contract_address.clone())); - class_hash.cloned() + .cloned() + .unwrap_or_default()) } fn get_nonce_at(&self, contract_address: &Address) -> Result { - let default = Felt252::zero(); - let nonce = self + Ok(self .address_to_nonce .get(contract_address) - .unwrap_or(&default); - Ok(nonce.clone()) + .cloned() + .unwrap_or_default()) } fn get_storage_at(&self, storage_entry: &StorageEntry) -> Result { @@ -132,12 +130,23 @@ impl StateReader for InMemoryStateReader { #[cfg(test)] mod tests { - use num_traits::One; + use num_traits::{One, Zero}; use super::*; use crate::services::api::contract_classes::deprecated_contract_class::ContractClass; use std::sync::Arc; + #[test] + fn get_class_hash_at_returns_zero_if_missing() { + let state_reader = InMemoryStateReader::default(); + assert!(Felt252::from_bytes_be( + &state_reader + .get_class_hash_at(&Address(Felt252::one())) + .unwrap() + ) + .is_zero()) + } + #[test] fn get_storage_returns_zero_if_missing() { let state_reader = InMemoryStateReader::default(); diff --git a/src/state/state_api.rs b/src/state/state_api.rs index 663ba5825..08748abdc 100644 --- a/src/state/state_api.rs +++ b/src/state/state_api.rs @@ -12,6 +12,7 @@ pub trait StateReader { /// Returns the contract class of the given class hash or compiled class hash. fn get_contract_class(&self, class_hash: &ClassHash) -> Result; /// Returns the class hash of the contract class at the given address. + /// Returns zero by default if the value is not present fn get_class_hash_at(&self, contract_address: &Address) -> Result; /// Returns the nonce of the given contract instance. fn get_nonce_at(&self, contract_address: &Address) -> Result; @@ -61,6 +62,8 @@ pub trait State { fee_token_and_sender_address: Option<(&Address, &Address)>, ) -> Result<(usize, usize), FromByteArrayError>; + /// Returns the class hash of the contract class at the given address. + /// Returns zero by default if the value is not present fn get_class_hash_at(&mut self, contract_address: &Address) -> Result; /// Default: 0 for an uninitialized contract address. From 820a336f5e2d89bcdd3f5ac896b21f78f0bf2972 Mon Sep 17 00:00:00 2001 From: Edgar Date: Wed, 6 Sep 2023 19:11:07 +0200 Subject: [PATCH 21/44] RPC use test_case with local cache and add more tests (#970) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * From/TryFrom starknet api types * Add deploy account * Modify gitignore * Deploy account and invoke function * Change into_iter to iter * Update .gitignore Co-authored-by: fmoletta <99273364+fmoletta@users.noreply.github.com> * change to try_from * Move functions to its respective files * WIP Added SIR support to SNRPC * Implemented state reader for sir * WIP Transaction * WIP SiR execution * Fixed rpc sir execute_tx * Fix clippy * Import last version of sn_api * Formatting * Test * Test try from * Delete test * Fix format * Fix test * local test cases * specify block manually * add test_case for blockifier * use more recent txs * dont keep cached responses * add failing tx on blockifier * more tests * Fix clippy * fix bug * tests * Replaced try_from with from_invoke_transaction * infer version * Fix version * Changed test_try_from_invoke * Ignore test_recent_tx * ignore failing tests * Refactor tx deser, (un)ignore tests * sorted assert and fee threshold * fixes --------- Co-authored-by: Milton Co-authored-by: Juan Bono Co-authored-by: fmoletta <99273364+fmoletta@users.noreply.github.com> Co-authored-by: mmsc2 <88055861+mmsc2@users.noreply.github.com> Co-authored-by: Estéfano Bargas --- Cargo.lock | 99 ++++++++ rpc_state_reader_sn_api/Cargo.toml | 4 + rpc_state_reader_sn_api/src/lib.rs | 214 ++++++++++++++++-- .../test-responses/.gitkeep | 0 4 files changed, 300 insertions(+), 17 deletions(-) create mode 100644 rpc_state_reader_sn_api/test-responses/.gitkeep diff --git a/Cargo.lock b/Cargo.lock index 8407c9fe1..923d2df25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1573,6 +1573,18 @@ dependencies = [ "syn 2.0.29", ] +[[package]] +name = "darrentsung_debug_parser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf488eca7807ce3c8e64bee95c3fbf8f1935c905b3b73835e75db16fc458fdc4" +dependencies = [ + "anyhow", + "html-escape", + "nom", + "ordered-float", +] + [[package]] name = "deranged" version = "0.3.8" @@ -2067,6 +2079,15 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "html-escape" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" +dependencies = [ + "utf8-width", +] + [[package]] name = "http" version = "0.2.9" @@ -2664,6 +2685,15 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "ordered-float" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" +dependencies = [ + "num-traits 0.2.16", +] + [[package]] name = "parity-scale-codec" version = "3.6.4" @@ -2862,6 +2892,26 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + +[[package]] +name = "pretty_assertions_sorted" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa95d32882f2adbdfd30312733271b83c527ee8007bf78dc21afe510463ac6a0" +dependencies = [ + "darrentsung_debug_parser", + "pretty_assertions", +] + [[package]] name = "primitive-types" version = "0.12.1" @@ -3134,12 +3184,14 @@ dependencies = [ "cairo-vm", "dotenv", "flate2", + "pretty_assertions_sorted", "serde", "serde_json", "serde_with 3.3.0", "starknet", "starknet_api", "starknet_in_rust", + "test-case", "thiserror", "ureq", ] @@ -3945,6 +3997,41 @@ dependencies = [ "winapi", ] +[[package]] +name = "test-case" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a1d6e7bde536b0412f20765b76e921028059adfd1b90d8974d33fd3c91b25df" +dependencies = [ + "test-case-macros", +] + +[[package]] +name = "test-case-core" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d10394d5d1e27794f772b6fc854c7e91a2dc26e2cbf807ad523370c2a59c0cee" +dependencies = [ + "cfg-if", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "test-case-macros" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeb9a44b1c6a54c1ba58b152797739dba2a83ca74e18168a68c980eb142f9404" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", + "test-case-core", +] + [[package]] name = "thiserror" version = "1.0.47" @@ -4252,6 +4339,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf8-width" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1" + [[package]] name = "utf8parse" version = "0.2.1" @@ -4520,6 +4613,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e2c411759b501fb9501aac2b1b2d287a6e93e5bdcf13c25306b23e1b716dd0e" +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + [[package]] name = "zeroize" version = "1.6.0" diff --git a/rpc_state_reader_sn_api/Cargo.toml b/rpc_state_reader_sn_api/Cargo.toml index 7b9612204..49a84c7fd 100644 --- a/rpc_state_reader_sn_api/Cargo.toml +++ b/rpc_state_reader_sn_api/Cargo.toml @@ -23,3 +23,7 @@ dotenv = "0.15.0" cairo-vm = "0.8.5" blockifier = "0.2.0-rc0" starknet_in_rust = { path = "../", version = "0.3.1" } + +[dev-dependencies] +pretty_assertions_sorted = "1.2.3" +test-case = "3.1.0" diff --git a/rpc_state_reader_sn_api/src/lib.rs b/rpc_state_reader_sn_api/src/lib.rs index 61393d32a..f1e856260 100644 --- a/rpc_state_reader_sn_api/src/lib.rs +++ b/rpc_state_reader_sn_api/src/lib.rs @@ -161,7 +161,34 @@ impl RpcState { &self, params: &serde_json::Value, ) -> Result { - Self::deserialize_call(self.rpc_call_no_deserialize(params)?.into_json().unwrap()) + #[cfg(test)] + { + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + use std::path::Path; + + let dir = Path::new("test-responses"); + let mut hasher = DefaultHasher::new(); + params.to_string().hash(&mut hasher); + let hash = hasher.finish(); + let filename = format!("{}-{}.json", self.chain, hash); + let file = dir.join(filename); + + if file.exists() { + let res = std::fs::read_to_string(file).unwrap(); + serde_json::from_str(&res).map_err(|err| RpcError::RpcCall(err.to_string())) + } else { + let res: serde_json::Value = Self::deserialize_call( + self.rpc_call_no_deserialize(params)?.into_json().unwrap(), + )?; + std::fs::write(file, res.to_string()).unwrap(); + serde_json::from_value(res).map_err(|err| RpcError::RpcCall(err.to_string())) + } + } + #[cfg(not(test))] + { + Self::deserialize_call(self.rpc_call_no_deserialize(params)?.into_json().unwrap()) + } } fn rpc_call_no_deserialize( @@ -521,6 +548,7 @@ mod utils { #[cfg(test)] mod tests { + use pretty_assertions_sorted::{assert_eq, assert_eq_sorted}; use starknet_api::{ core::{ClassHash, PatriciaKey}, hash::StarkFelt, @@ -608,7 +636,7 @@ mod tests { contract_address!("00b081f7ba1efc6fe98770b09a827ae373ef2baa6116b3d2a0bf5154136573a9"); let key = StorageKey(patricia_key!(0u128)); - assert_eq!(rpc_state.get_storage_at(&address, &key), stark_felt!("0x0")); + assert_eq_sorted!(rpc_state.get_storage_at(&address, &key), stark_felt!("0x0")); } #[test] @@ -686,7 +714,7 @@ mod tests { ]) ); assert_eq!(tx_trace.validate_invocation.retdata, Some(vec![])); - assert_eq!( + assert_eq_sorted!( tx_trace.validate_invocation.execution_resources, VmExecutionResources { n_steps: 790, @@ -724,7 +752,7 @@ mod tests { tx_trace.function_invocation.as_ref().unwrap().retdata, Some(vec![0u128.into()]) ); - assert_eq!( + assert_eq_sorted!( tx_trace .function_invocation .as_ref() @@ -782,7 +810,7 @@ mod tests { tx_trace.fee_transfer_invocation.retdata, Some(vec![1u128.into()]) ); - assert_eq!( + assert_eq_sorted!( tx_trace.fee_transfer_invocation.execution_resources, VmExecutionResources { n_steps: 586, @@ -991,6 +1019,8 @@ mod blockifier_transaction_tests { #[cfg(test)] mod test { use blockifier::execution::entry_point::CallInfo; + use pretty_assertions_sorted::{assert_eq, assert_eq_sorted}; + use test_case::test_case; use super::*; @@ -1042,6 +1072,90 @@ mod blockifier_transaction_tests { .len() ); } + + #[test_case( + "0x05d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91", + 169928, // real block 169929 + RpcChain::MainNet + => ignore["gas mismatch"] + )] + #[test_case( + "0x0528ec457cf8757f3eefdf3f0728ed09feeecc50fd97b1e4c5da94e27e9aa1d6", + 169928, // real block 169929 + RpcChain::MainNet + => ignore["gas mismatch"] + )] + #[test_case( + "0x0737677385a30ec4cbf9f6d23e74479926975b74db3d55dc5e46f4f8efee41cf", + 169928, // real block 169929 + RpcChain::MainNet + => ignore["resource mismatch"] + )] + #[test_case( + "0x026c17728b9cd08a061b1f17f08034eb70df58c1a96421e73ee6738ad258a94c", + 169928, // real block 169929 + RpcChain::MainNet + => ignore["gas mismatch"] + )] + #[test_case( + // review later + "0x0743092843086fa6d7f4a296a226ee23766b8acf16728aef7195ce5414dc4d84", + 186548, // real block 186549 + RpcChain::MainNet + => ignore["resource mismatch"] + )] + #[test_case( + // fails in blockifier too + "0x00724fc4a84f489ed032ebccebfc9541eb8dc64b0e76b933ed6fc30cd6000bd1", + 186551, // real block 186552 + RpcChain::MainNet + => ignore["gas mismatch"] + )] + fn test_case_tx(hash: &str, block_number: u64, chain: RpcChain) { + let (tx_info, trace, receipt) = execute_tx(hash, chain, BlockNumber(block_number)); + + let TransactionExecutionInfo { + execute_call_info, + actual_fee, + .. + } = tx_info; + + let CallInfo { + vm_resources, + inner_calls, + .. + } = execute_call_info.unwrap(); + + let actual_fee = actual_fee.0; + if receipt.actual_fee != actual_fee { + let diff = 100 * receipt.actual_fee.abs_diff(actual_fee) / receipt.actual_fee; + + if diff >= 5 { + assert_eq!( + actual_fee, receipt.actual_fee, + "actual_fee mismatch differs from the baseline by more than 5% ({diff}%)", + ); + } + } + + assert_eq_sorted!( + vm_resources, + trace + .function_invocation + .as_ref() + .unwrap() + .execution_resources + ); + assert_eq!( + inner_calls.len(), + trace + .function_invocation + .as_ref() + .unwrap() + .internal_calls + .len() + ); + } } } @@ -1211,10 +1325,33 @@ mod starknet_in_rust_transaction_tests { #[cfg(test)] mod test { + use pretty_assertions_sorted::{assert_eq, assert_eq_sorted}; use starknet_in_rust::execution::CallInfo; + use test_case::test_case; use super::*; + #[test] + fn test_get_transaction_try_from() { + let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + let str_hash = + stark_felt!("0x5d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91"); + let tx_hash = TransactionHash(str_hash); + + let sn_tx = rpc_state.get_transaction(&tx_hash); + match &sn_tx { + SNTransaction::Invoke(sn_tx) => { + let tx = InvokeFunction::from_invoke_transaction( + sn_tx.clone(), + StarknetChainId::MainNet, + ) + .unwrap(); + assert_eq!(tx.hash_value().to_be_bytes().as_slice(), str_hash.bytes()) + } + _ => unimplemented!(), + }; + } + #[test] fn test_get_gas_price() { let block = BlockValue::Number(BlockNumber(169928)); @@ -1224,14 +1361,46 @@ mod starknet_in_rust_transaction_tests { assert_eq!(price, 22804578690); } - #[test] - #[ignore = "working on fixes"] - fn test_recent_tx() { - let (tx_info, trace, receipt) = execute_tx( - "0x05d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91", - RpcChain::MainNet, - BlockNumber(169928), - ); + #[test_case( + "0x05d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91", + 169928, // real block 169929 + RpcChain::MainNet + => ignore["gas mismatch"] + )] + #[test_case( + "0x0528ec457cf8757f3eefdf3f0728ed09feeecc50fd97b1e4c5da94e27e9aa1d6", + 169928, // real block 169929 + RpcChain::MainNet + => ignore["gas mismatch"] + )] + #[test_case( + "0x0737677385a30ec4cbf9f6d23e74479926975b74db3d55dc5e46f4f8efee41cf", + 169928, // real block 169929 + RpcChain::MainNet + => ignore["resource mismatch"] + )] + #[test_case( + "0x026c17728b9cd08a061b1f17f08034eb70df58c1a96421e73ee6738ad258a94c", + 169928, // real block 169929 + RpcChain::MainNet + => ignore["gas mismatch"] + )] + #[test_case( + // review later + "0x0743092843086fa6d7f4a296a226ee23766b8acf16728aef7195ce5414dc4d84", + 186548, // real block 186549 + RpcChain::MainNet + => ignore["resource mismatch"] + )] + #[test_case( + // fails in blockifier too + "0x00724fc4a84f489ed032ebccebfc9541eb8dc64b0e76b933ed6fc30cd6000bd1", + 186551, // real block 186552 + RpcChain::MainNet + => ignore["gas mismatch"] + )] + fn test_case_tx(hash: &str, block_number: u64, chain: RpcChain) { + let (tx_info, trace, receipt) = execute_tx(hash, chain, BlockNumber(block_number)); let TransactionExecutionInfo { call_info, @@ -1245,13 +1414,14 @@ mod starknet_in_rust_transaction_tests { .. } = call_info.unwrap(); - assert_eq!( + assert_eq_sorted!( execution_resources, trace .function_invocation .as_ref() .unwrap() - .execution_resources + .execution_resources, + "execution resources mismatch" ); assert_eq!( internal_calls.len(), @@ -1260,10 +1430,20 @@ mod starknet_in_rust_transaction_tests { .as_ref() .unwrap() .internal_calls - .len() + .len(), + "internal calls length mismatch" ); - assert_eq!(actual_fee, receipt.actual_fee); + if receipt.actual_fee != actual_fee { + let diff = 100 * receipt.actual_fee.abs_diff(actual_fee) / receipt.actual_fee; + + if diff >= 5 { + assert_eq!( + actual_fee, receipt.actual_fee, + "actual_fee mismatch differs from the baseline by more than 5% ({diff}%)", + ); + } + } } } } diff --git a/rpc_state_reader_sn_api/test-responses/.gitkeep b/rpc_state_reader_sn_api/test-responses/.gitkeep new file mode 100644 index 000000000..e69de29bb From 1b3c72ffd2a2961f54600a95981fd936a4c6fb63 Mon Sep 17 00:00:00 2001 From: fmoletta <99273364+fmoletta@users.noreply.github.com> Date: Wed, 6 Sep 2023 20:43:23 +0300 Subject: [PATCH 22/44] Update cache initial values with write-only accesses in `CachedState::count_actual_storage_changes` (#1009) * Add update_initial_values_of_write_only_access * Change name * Update variable names * Fix + expand test * Add band-aid soluction + restore test * update InMemoryStateReader & CachedState * Add comments * Apply changes to State implementation too * Fix behaviour * Add test * Remove band-aid solution * Use unwrap_or_default * return zero by default state reader get_class_hash_at * Add changes * clippy * Add initial values to test * remove duplictaed test --- src/core/errors/state_errors.rs | 3 ++ src/state/cached_state.rs | 67 +++++++++++++++++++++++++++++++-- src/state/state_api.rs | 3 +- tests/internals.rs | 7 ++++ 4 files changed, 74 insertions(+), 6 deletions(-) diff --git a/src/core/errors/state_errors.rs b/src/core/errors/state_errors.rs index 29e03846d..e5ab48713 100644 --- a/src/core/errors/state_errors.rs +++ b/src/core/errors/state_errors.rs @@ -3,6 +3,7 @@ use crate::{ state::state_cache::StorageEntry, utils::{Address, ClassHash}, }; +use starknet::core::types::FromByteArrayError; use thiserror::Error; #[derive(Debug, Error)] @@ -53,4 +54,6 @@ pub enum StateError { Io(#[from] std::io::Error), #[error("{0:?}")] CustomError(String), + #[error(transparent)] + ByteArray(#[from] FromByteArrayError), } diff --git a/src/state/cached_state.rs b/src/state/cached_state.rs index ed5b4da76..2f60eabd3 100644 --- a/src/state/cached_state.rs +++ b/src/state/cached_state.rs @@ -14,7 +14,6 @@ use crate::{ use cairo_vm::felt::Felt252; use getset::{Getters, MutGetters}; use num_traits::Zero; -use starknet::core::types::FromByteArrayError; use std::{ collections::{HashMap, HashSet}, sync::Arc, @@ -246,7 +245,9 @@ impl State for CachedState { fn count_actual_storage_changes( &mut self, fee_token_and_sender_address: Option<(&Address, &Address)>, - ) -> Result<(usize, usize), FromByteArrayError> { + ) -> Result<(usize, usize), StateError> { + self.update_initial_values_of_write_only_accesses()?; + let mut storage_updates = subtract_mappings( self.cache.storage_writes.clone(), self.cache.storage_initial_values.clone(), @@ -394,6 +395,52 @@ impl State for CachedState { } } +impl CachedState { + // Updates the cache's storage_initial_values according to those in storage_writes + // If a key is present in the storage_writes but not in storage_initial_values, + // the initial value for that key will be fetched from the state_reader and inserted into the cache's storage_initial_values + // The same process is applied to class hash and nonce values. + fn update_initial_values_of_write_only_accesses(&mut self) -> Result<(), StateError> { + // Update storage_initial_values with keys in storage_writes + for storage_entry in self.cache.storage_writes.keys() { + if !self + .cache + .storage_initial_values + .contains_key(storage_entry) + { + // This key was first accessed via write, so we need to cache its initial value + self.cache.storage_initial_values.insert( + storage_entry.clone(), + self.state_reader.get_storage_at(storage_entry)?, + ); + } + } + for address in self.cache.class_hash_writes.keys() { + if !self.cache.class_hash_initial_values.contains_key(address) { + // This key was first accessed via write, so we need to cache its initial value + self.cache.class_hash_initial_values.insert( + address.clone(), + self.state_reader.get_class_hash_at(address)?, + ); + } + } + for contract_address in self.cache.nonce_writes.keys() { + if !self + .cache + .nonce_initial_values + .contains_key(contract_address) + { + // This key was first accessed via write, so we need to cache its initial value + self.cache.nonce_initial_values.insert( + contract_address.clone(), + self.state_reader.get_nonce_at(contract_address)?, + ); + } + } + Ok(()) + } +} + #[cfg(test)] mod tests { use super::*; @@ -668,6 +715,7 @@ mod tests { #[test] fn count_actual_storage_changes_test() { let state_reader = InMemoryStateReader::default(); + let mut cached_state = CachedState::new(Arc::new(state_reader), HashMap::new()); let address_one = Address(1.into()); @@ -679,9 +727,9 @@ mod tests { HashMap::from([((address_one.clone(), storage_key_one), Felt252::from(1))]); cached_state.cache.storage_writes = HashMap::from([ ((address_one.clone(), storage_key_one), Felt252::from(1)), - ((address_one, storage_key_two), Felt252::from(1)), + ((address_one.clone(), storage_key_two), Felt252::from(1)), ((address_two.clone(), storage_key_one), Felt252::from(1)), - ((address_two, storage_key_two), Felt252::from(1)), + ((address_two.clone(), storage_key_two), Felt252::from(1)), ]); let fee_token_address = Address(123.into()); @@ -698,5 +746,16 @@ mod tests { .unwrap(); assert_eq!(changes, expected_changes); + + // Check that the initial values were updated when counting changes + assert_eq!( + cached_state.cache.storage_initial_values, + HashMap::from([ + ((address_one.clone(), storage_key_one), Felt252::from(1)), + ((address_one, storage_key_two), Felt252::from(0)), + ((address_two.clone(), storage_key_one), Felt252::from(0)), + ((address_two, storage_key_two), Felt252::from(0)), + ]) + ) } } diff --git a/src/state/state_api.rs b/src/state/state_api.rs index 08748abdc..ff468671a 100644 --- a/src/state/state_api.rs +++ b/src/state/state_api.rs @@ -6,7 +6,6 @@ use crate::{ utils::{Address, ClassHash, CompiledClassHash}, }; use cairo_vm::felt::Felt252; -use starknet::core::types::FromByteArrayError; pub trait StateReader { /// Returns the contract class of the given class hash or compiled class hash. @@ -60,7 +59,7 @@ pub trait State { fn count_actual_storage_changes( &mut self, fee_token_and_sender_address: Option<(&Address, &Address)>, - ) -> Result<(usize, usize), FromByteArrayError>; + ) -> Result<(usize, usize), StateError>; /// Returns the class hash of the contract class at the given address. /// Returns zero by default if the value is not present diff --git a/tests/internals.rs b/tests/internals.rs index 7d6d6ab92..d51fa39ea 100644 --- a/tests/internals.rs +++ b/tests/internals.rs @@ -1659,6 +1659,13 @@ fn expected_deploy_account_states() -> ( ), Felt252::zero(), ); + state_after.cache_mut().storage_initial_values_mut().insert( + ( + Address(0x1001.into()), + felt_to_hash(&TEST_ERC20_DEPLOYED_ACCOUNT_BALANCE_KEY), + ), + Felt252::zero(), + ); state_after.cache_mut().nonce_writes_mut().insert( Address(felt_str!( "386181506763903095743576862849245034886954647214831045800703908858571591162" From f01ad8f1c9e3cb0e97ad45ad383501dc55a2e1fe Mon Sep 17 00:00:00 2001 From: Edgar Date: Wed, 6 Sep 2023 20:01:16 +0200 Subject: [PATCH 23/44] Refactor new RPC into several files (#1007) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * From/TryFrom starknet api types * Add deploy account * Modify gitignore * Deploy account and invoke function * Change into_iter to iter * Update .gitignore Co-authored-by: fmoletta <99273364+fmoletta@users.noreply.github.com> * change to try_from * Move functions to its respective files * WIP Added SIR support to SNRPC * Implemented state reader for sir * WIP Transaction * WIP SiR execution * Fixed rpc sir execute_tx * Fix clippy * Import last version of sn_api * Formatting * Test * Test try from * Delete test * Fix format * Fix test * local test cases * specify block manually * add test_case for blockifier * use more recent txs * dont keep cached responses * add failing tx on blockifier * more tests * Fix clippy * fix bug * tests * Replaced try_from with from_invoke_transaction * infer version * Fix version * Changed test_try_from_invoke * Ignore test_recent_tx * ignore failing tests * Refactor tx deser, (un)ignore tests * sorted assert and fee threshold * refactor rpc state reader * fixes --------- Co-authored-by: Milton Co-authored-by: Juan Bono Co-authored-by: fmoletta <99273364+fmoletta@users.noreply.github.com> Co-authored-by: mmsc2 <88055861+mmsc2@users.noreply.github.com> Co-authored-by: Estéfano Bargas --- rpc_state_reader_sn_api/Cargo.toml | 2 +- rpc_state_reader_sn_api/src/lib.rs | 1217 +---------------- rpc_state_reader_sn_api/src/rpc_state.rs | 449 ++++++ rpc_state_reader_sn_api/src/utils.rs | 89 ++ .../tests/blockifier_tests.rs | 318 +++++ rpc_state_reader_sn_api/tests/sir_tests.rs | 283 ++++ 6 files changed, 1164 insertions(+), 1194 deletions(-) create mode 100644 rpc_state_reader_sn_api/src/rpc_state.rs create mode 100644 rpc_state_reader_sn_api/src/utils.rs create mode 100644 rpc_state_reader_sn_api/tests/blockifier_tests.rs create mode 100644 rpc_state_reader_sn_api/tests/sir_tests.rs diff --git a/rpc_state_reader_sn_api/Cargo.toml b/rpc_state_reader_sn_api/Cargo.toml index 49a84c7fd..35be6617f 100644 --- a/rpc_state_reader_sn_api/Cargo.toml +++ b/rpc_state_reader_sn_api/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] ureq = { version = "2.7.1", features = ["json"] } -serde = { version = "=1.0.171", features = ["derive"] } +serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = [ "arbitrary_precision", "raw_value", diff --git a/rpc_state_reader_sn_api/src/lib.rs b/rpc_state_reader_sn_api/src/lib.rs index f1e856260..2ae84fab1 100644 --- a/rpc_state_reader_sn_api/src/lib.rs +++ b/rpc_state_reader_sn_api/src/lib.rs @@ -1,580 +1,24 @@ -use blockifier::execution::contract_class::{ - ContractClass as BlockifierContractClass, ContractClassV0, ContractClassV0Inner, -}; -use cairo_lang_starknet::casm_contract_class::CasmContractClass; -use cairo_lang_starknet::contract_class::{ - ContractClass as SierraContractClass, ContractEntryPoints, -}; -use cairo_vm::types::program::Program; -use cairo_vm::vm::runners::cairo_runner::ExecutionResources as VmExecutionResources; -use core::fmt; -use dotenv::dotenv; -use serde::{Deserialize, Deserializer}; -use serde_json::json; -use starknet::core::types::ContractClass as SNContractClass; -use starknet_api::block::{BlockNumber, BlockTimestamp}; -use starknet_api::core::{ChainId, ClassHash, EntryPointSelector}; -use starknet_api::deprecated_contract_class::EntryPointOffset; -use starknet_api::hash::StarkFelt; -use starknet_api::transaction::{InvokeTransaction, Transaction as SNTransaction, TransactionHash}; -use starknet_api::{core::ContractAddress, hash::StarkHash, state::StorageKey}; -use std::collections::HashMap; -use std::env; -use std::fmt::Display; -use std::sync::Arc; -use thiserror::Error; - -/// Starknet chains supported in Infura. -#[derive(Debug, Clone, Copy)] -pub enum RpcChain { - MainNet, - TestNet, - TestNet2, -} - -impl fmt::Display for RpcChain { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - RpcChain::MainNet => write!(f, "starknet-mainnet"), - RpcChain::TestNet => write!(f, "starknet-goerli"), - RpcChain::TestNet2 => write!(f, "starknet-goerli2"), - } - } -} - -/// A [StateReader] that holds all the data in memory. -/// -/// This implementation is uses HTTP requests to call the RPC endpoint, -/// using Infura. -/// In order to use it an Infura API key is necessary. -pub struct RpcState { - /// Enum with one of the supported Infura chains/ - chain: RpcChain, - /// Infura API key. - api_key: String, - /// Struct that holds information on the block where we are going to use to read the state. - block: BlockValue, -} - -#[derive(Debug, Error)] -enum RpcError { - #[error("RPC call failed with error: {0}")] - RpcCall(String), - #[error("Request failed with error: {0}")] - Request(String), -} - -/// Represents the tag of a block value. -#[derive(Copy, Clone)] -pub enum BlockTag { - Latest, - Pending, -} - -impl Display for BlockTag { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let string = match self { - BlockTag::Latest => "latest", - BlockTag::Pending => "pending", - }; - write!(f, "{}", string) - } -} - -/// [`BlockValue`] is an Enum that represent which block we are going to use to retrieve information. -#[allow(dead_code)] -#[derive(Copy, Clone)] -pub enum BlockValue { - /// String one of: ["latest", "pending"] - Tag(BlockTag), - /// Integer - Number(BlockNumber), - /// String with format: 0x{felt252} - Hash(StarkHash), -} - -impl From for BlockValue { - fn from(value: BlockTag) -> Self { - BlockValue::Tag(value) - } -} - -impl From for BlockValue { - fn from(value: BlockNumber) -> Self { - BlockValue::Number(value) - } -} - -impl From for BlockValue { - fn from(value: StarkHash) -> Self { - BlockValue::Hash(value) - } -} - -impl BlockValue { - fn to_value(self) -> Result { - serde_json::to_value(match self { - BlockValue::Tag(block_tag) => block_tag.to_string().into(), - BlockValue::Number(block_number) => json!({ "block_number": block_number }), - BlockValue::Hash(block_hash) => json!({ "block_hash": block_hash }), - }) - } -} - -pub struct RpcBlockInfo { - /// The sequence number of the last block created. - pub block_number: BlockNumber, - /// Timestamp of the beginning of the last block creation attempt. - pub block_timestamp: BlockTimestamp, - /// The sequencer address of this block. - pub sequencer_address: ContractAddress, - /// The transactions of this block. - pub transactions: Vec, -} - -#[derive(Deserialize)] -pub struct RpcResponse { - result: T, -} - -impl RpcState { - pub fn new(chain: RpcChain, block: BlockValue) -> Self { - if env::var("INFURA_API_KEY").is_err() { - dotenv().expect("Missing .env file"); - } - Self { - chain, - api_key: env::var("INFURA_API_KEY") - .expect("Missing API Key in environment: INFURA_API_KEY"), - block, - } - } - - fn rpc_call_result Deserialize<'a>>( - &self, - params: &serde_json::Value, - ) -> Result { - Ok(self.rpc_call::>(params)?.result) - } - - fn rpc_call Deserialize<'a>>( - &self, - params: &serde_json::Value, - ) -> Result { - #[cfg(test)] - { - use std::collections::hash_map::DefaultHasher; - use std::hash::{Hash, Hasher}; - use std::path::Path; - - let dir = Path::new("test-responses"); - let mut hasher = DefaultHasher::new(); - params.to_string().hash(&mut hasher); - let hash = hasher.finish(); - let filename = format!("{}-{}.json", self.chain, hash); - let file = dir.join(filename); - - if file.exists() { - let res = std::fs::read_to_string(file).unwrap(); - serde_json::from_str(&res).map_err(|err| RpcError::RpcCall(err.to_string())) - } else { - let res: serde_json::Value = Self::deserialize_call( - self.rpc_call_no_deserialize(params)?.into_json().unwrap(), - )?; - std::fs::write(file, res.to_string()).unwrap(); - serde_json::from_value(res).map_err(|err| RpcError::RpcCall(err.to_string())) - } - } - #[cfg(not(test))] - { - Self::deserialize_call(self.rpc_call_no_deserialize(params)?.into_json().unwrap()) - } - } - - fn rpc_call_no_deserialize( - &self, - params: &serde_json::Value, - ) -> Result { - ureq::post(&format!( - "https://{}.infura.io/v3/{}", - self.chain, self.api_key - )) - .set("Content-Type", "application/json") - .set("accept", "application/json") - .send_json(params) - .map_err(|err| RpcError::Request(err.to_string())) - } - - fn deserialize_call Deserialize<'a>>( - response: serde_json::Value, - ) -> Result { - serde_json::from_value(response).map_err(|err| RpcError::RpcCall(err.to_string())) - } -} - -#[derive(Debug, Deserialize)] -pub struct TransactionTrace { - pub validate_invocation: RpcCallInfo, - pub function_invocation: Option, - pub fee_transfer_invocation: RpcCallInfo, - pub signature: Vec, - pub revert_error: Option, -} - -#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)] -pub struct RpcExecutionResources { - pub n_steps: usize, - pub n_memory_holes: usize, - pub builtin_instance_counter: HashMap, -} - -#[derive(Debug)] -pub struct RpcCallInfo { - pub execution_resources: VmExecutionResources, - pub retdata: Option>, - pub calldata: Option>, - pub internal_calls: Vec, -} - -#[allow(unused)] -#[derive(Debug, Deserialize)] -pub struct RpcTransactionReceipt { - #[serde(deserialize_with = "actual_fee_deser")] - actual_fee: u128, - block_hash: StarkHash, - block_number: u64, - execution_status: String, - #[serde(rename = "type")] - tx_type: String, -} - -fn actual_fee_deser<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let hex: String = Deserialize::deserialize(deserializer)?; - Ok(u128::from_str_radix(&hex[2..], 16).unwrap()) -} - -impl<'de> Deserialize<'de> for RpcCallInfo { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let value: serde_json::Value = Deserialize::deserialize(deserializer)?; - - // Parse execution_resources - let execution_resources_value = value["execution_resources"].clone(); - - let execution_resources = VmExecutionResources { - n_steps: serde_json::from_value(execution_resources_value["n_steps"].clone()) - .map_err(serde::de::Error::custom)?, - n_memory_holes: serde_json::from_value( - execution_resources_value["n_memory_holes"].clone(), - ) - .map_err(serde::de::Error::custom)?, - builtin_instance_counter: serde_json::from_value( - execution_resources_value["builtin_instance_counter"].clone(), - ) - .map_err(serde::de::Error::custom)?, - }; - - // Parse retdata - let retdata_value = value["result"].clone(); - let retdata = serde_json::from_value(retdata_value).unwrap(); - - // Parse calldata - let calldata_value = value["calldata"].clone(); - let calldata = serde_json::from_value(calldata_value).unwrap(); - - // Parse internal calls - let internal_calls_value = value["internal_calls"].clone(); - let mut internal_calls = vec![]; - - for call in internal_calls_value.as_array().unwrap() { - internal_calls - .push(serde_json::from_value(call.clone()).map_err(serde::de::Error::custom)?); - } - - Ok(RpcCallInfo { - execution_resources, - retdata, - calldata, - internal_calls, - }) - } -} - -impl RpcState { - /// Requests the transaction trace to the Feeder Gateway API. - /// It's useful for testing the transaction outputs like: - /// - execution resources - /// - actual fee - /// - events - /// - return data - pub fn get_transaction_trace(&self, hash: &TransactionHash) -> TransactionTrace { - let chain_name = self.get_chain_name(); - let response = ureq::get(&format!( - "https://{}.starknet.io/feeder_gateway/get_transaction_trace", - chain_name - )) - .query("transactionHash", &hash.0.to_string()) - .call() - .unwrap(); - - serde_json::from_value(response.into_json().unwrap()).unwrap() - } - - /// Requests the given transaction to the Feeder Gateway API. - pub fn get_transaction(&self, hash: &TransactionHash) -> SNTransaction { - let params = ureq::json!({ - "jsonrpc": "2.0", - "method": "starknet_getTransactionByHash", - "params": [hash.to_string()], - "id": 1 - }); - let result = self.rpc_call::(¶ms).unwrap()["result"].clone(); - utils::deserialize_transaction_json(result).unwrap() - } - - /// Gets the gas price of a given block. - pub fn get_gas_price(&self, block_number: u64) -> serde_json::Result { - let chain_name = self.get_chain_name(); - - let response = ureq::get(&format!( - "https://{}.starknet.io/feeder_gateway/get_block", - chain_name - )) - .query("blockNumber", &block_number.to_string()) - .call() - .unwrap(); - - let res: serde_json::Value = response.into_json().expect("should be json"); - - let gas_price_hex = res["gas_price"].as_str().unwrap(); - let gas_price = u128::from_str_radix(gas_price_hex.trim_start_matches("0x"), 16).unwrap(); - Ok(gas_price) - } - - pub fn get_chain_name(&self) -> ChainId { - ChainId(match self.chain { - RpcChain::MainNet => "alpha-mainnet".to_string(), - RpcChain::TestNet => "alpha4".to_string(), - RpcChain::TestNet2 => "alpha4-2".to_string(), - }) - } - - pub fn get_block_info(&self) -> RpcBlockInfo { - let get_block_info_params = ureq::json!({ - "jsonrpc": "2.0", - "method": "starknet_getBlockWithTxs", - "params": [self.block.to_value().unwrap()], - "id": 1 - }); - - let block_info: serde_json::Value = self.rpc_call(&get_block_info_params).unwrap(); - let sequencer_address: StarkFelt = - serde_json::from_value(block_info["result"]["sequencer_address"].clone()).unwrap(); - - let transactions: Vec<_> = block_info["result"]["transactions"] - .as_array() - .unwrap() - .iter() - .filter_map(|result| utils::deserialize_transaction_json(result.clone()).ok()) - .collect(); - - RpcBlockInfo { - block_number: BlockNumber( - block_info["result"]["block_number"] - .to_string() - .parse::() - .unwrap(), - ), - block_timestamp: BlockTimestamp( - block_info["result"]["timestamp"] - .to_string() - .parse::() - .unwrap(), - ), - sequencer_address: ContractAddress(sequencer_address.try_into().unwrap()), - transactions, - } - } - - pub fn get_contract_class(&self, class_hash: &ClassHash) -> SNContractClass { - let params = ureq::json!({ - "jsonrpc": "2.0", - "method": "starknet_getClass", - "params": [self.block.to_value().unwrap(), class_hash.0.to_string()], - "id": 1 - }); - - self.rpc_call_result(¶ms).unwrap() - } - - pub fn get_class_hash_at(&self, contract_address: &ContractAddress) -> ClassHash { - let params = ureq::json!({ - "jsonrpc": "2.0", - "method": "starknet_getClassHashAt", - "params": [self.block.to_value().unwrap(), contract_address.0.key().clone().to_string()], - "id": 1 - }); - - let hash = self.rpc_call_result(¶ms).unwrap(); - - ClassHash(hash) - } - - pub fn get_nonce_at(&self, contract_address: &ContractAddress) -> StarkFelt { - let params = ureq::json!({ - "jsonrpc": "2.0", - "method": "starknet_getNonce", - "params": [self.block.to_value().unwrap(), contract_address.0.key().clone().to_string()], - "id": 1 - }); - - self.rpc_call_result(¶ms).unwrap() - } - - fn get_storage_at(&self, contract_address: &ContractAddress, key: &StorageKey) -> StarkFelt { - let contract_address = contract_address.0.key(); - let key = key.0.key(); - let params = ureq::json!({ - "jsonrpc": "2.0", - "method": "starknet_getStorageAt", - "params": [contract_address.to_string(), - key.to_string(), self.block.to_value().unwrap()], - "id": 1 - }); - - self.rpc_call_result(¶ms).unwrap() - } - - /// Requests the given transaction to the Feeder Gateway API. - pub fn get_transaction_receipt(&self, hash: &TransactionHash) -> RpcTransactionReceipt { - let params = ureq::json!({ - "jsonrpc": "2.0", - "method": "starknet_getTransactionReceipt", - "params": [hash.to_string()], - "id": 1 - }); - self.rpc_call_result(¶ms).unwrap() - } -} - -mod utils { - use std::io::{self, Read}; - - use cairo_lang_utils::bigint::BigUintAsHex; - use starknet::core::types::{LegacyContractEntryPoint, LegacyEntryPointsByType}; - use starknet_api::deprecated_contract_class::{EntryPoint, EntryPointType}; - - use super::*; - - #[derive(Debug, Deserialize)] - pub struct MiddleSierraContractClass { - pub sierra_program: Vec, - pub contract_class_version: String, - pub entry_points_by_type: ContractEntryPoints, - } - - pub(crate) fn map_entry_points_by_type_legacy( - entry_points_by_type: LegacyEntryPointsByType, - ) -> HashMap> { - let entry_types_to_points = HashMap::from([ - ( - EntryPointType::Constructor, - entry_points_by_type.constructor, - ), - (EntryPointType::External, entry_points_by_type.external), - (EntryPointType::L1Handler, entry_points_by_type.l1_handler), - ]); - - let to_contract_entry_point = |entrypoint: &LegacyContractEntryPoint| -> EntryPoint { - let felt: StarkFelt = StarkHash::new(entrypoint.selector.to_bytes_be()).unwrap(); - EntryPoint { - offset: EntryPointOffset(entrypoint.offset as usize), - selector: EntryPointSelector(felt), - } - }; - - let mut entry_points_by_type_map = HashMap::new(); - for (entry_point_type, entry_points) in entry_types_to_points.into_iter() { - let values = entry_points - .iter() - .map(to_contract_entry_point) - .collect::>(); - entry_points_by_type_map.insert(entry_point_type, values); - } - - entry_points_by_type_map - } - - /// Uncompresses a Gz Encoded vector of bytes and returns a string or error - /// Here &[u8] implements BufRead - pub(crate) fn decode_reader(bytes: Vec) -> io::Result { - use flate2::bufread; - let mut gz = bufread::GzDecoder::new(&bytes[..]); - let mut s = String::new(); - gz.read_to_string(&mut s)?; - Ok(s) - } - - /// Freestanding deserialize method to avoid a new type. - pub(crate) fn deserialize_transaction_json( - transaction: serde_json::Value, - ) -> serde_json::Result { - let tx_type: String = serde_json::from_value(transaction["type"].clone())?; - let tx_version: String = serde_json::from_value(transaction["version"].clone())?; - - match tx_type.as_str() { - "INVOKE" => match tx_version.as_str() { - "0x0" => Ok(SNTransaction::Invoke(InvokeTransaction::V0( - serde_json::from_value(transaction)?, - ))), - "0x1" => Ok(SNTransaction::Invoke(InvokeTransaction::V1( - serde_json::from_value(transaction)?, - ))), - x => Err(serde::de::Error::custom(format!( - "unimplemented invoke version: {x}" - ))), - }, - x => Err(serde::de::Error::custom(format!( - "unimplemented transaction type deserialization: {x}" - ))), - } - } -} +pub mod rpc_state; +pub mod utils; #[cfg(test)] mod tests { + use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use pretty_assertions_sorted::{assert_eq, assert_eq_sorted}; use starknet_api::{ - core::{ClassHash, PatriciaKey}, - hash::StarkFelt, - stark_felt, + class_hash, + core::{ClassHash, ContractAddress, PatriciaKey}, + hash::{StarkFelt, StarkHash}, + patricia_key, stark_felt, + state::StorageKey, + transaction::{Transaction as SNTransaction, TransactionHash}, }; use starknet_in_rust::{ definitions::block_context::StarknetChainId, transaction::InvokeFunction, }; + use std::collections::HashMap; - use super::*; - - /// A utility macro to create a [`PatriciaKey`] from a hex string / unsigned integer representation. - /// Imported from starknet_api - macro_rules! patricia_key { - ($s:expr) => { - PatriciaKey::try_from(StarkHash::try_from($s).unwrap()).unwrap() - }; - } - - /// A utility macro to create a [`ClassHash`] from a hex string / unsigned integer representation. - /// Imported from starknet_api - macro_rules! class_hash { - ($s:expr) => { - ClassHash(StarkHash::try_from($s).unwrap()) - }; - } + use crate::rpc_state::*; /// A utility macro to create a [`ContractAddress`] from a hex string / unsigned integer /// representation. @@ -587,7 +31,7 @@ mod tests { #[test] fn test_get_contract_class_cairo1() { - let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); let class_hash = class_hash!("0298e56befa6d1446b86ed5b900a9ba51fd2faa683cd6f50e8f833c0fb847216"); @@ -600,7 +44,7 @@ mod tests { #[test] fn test_get_contract_class_cairo0() { - let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); let class_hash = class_hash!("025ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918"); @@ -609,7 +53,7 @@ mod tests { #[test] fn test_get_class_hash_at() { - let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); let address = contract_address!("00b081f7ba1efc6fe98770b09a827ae373ef2baa6116b3d2a0bf5154136573a9"); @@ -621,7 +65,7 @@ mod tests { #[test] fn test_get_nonce_at() { - let rpc_state = RpcState::new(RpcChain::TestNet, BlockTag::Latest.into()); + let rpc_state = RpcState::new_infura(RpcChain::TestNet, BlockTag::Latest.into()); // Contract deployed by xqft which will not be used again, so nonce changes will not break // this test. let address = @@ -631,7 +75,7 @@ mod tests { #[test] fn test_get_storage_at() { - let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); let address = contract_address!("00b081f7ba1efc6fe98770b09a827ae373ef2baa6116b3d2a0bf5154136573a9"); let key = StorageKey(patricia_key!(0u128)); @@ -641,7 +85,7 @@ mod tests { #[test] fn test_get_transaction() { - let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); let tx_hash = TransactionHash(stark_felt!( "06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955" )); @@ -651,7 +95,7 @@ mod tests { #[test] fn test_try_from_invoke() { - let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); let tx_hash = TransactionHash(stark_felt!( "06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955" )); @@ -668,7 +112,7 @@ mod tests { #[test] fn test_get_block_info() { - let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); rpc_state.get_block_info(); } @@ -677,7 +121,7 @@ mod tests { // https://alpha4-2.starknet.io/feeder_gateway/get_transaction_trace?transactionHash=0x019feb888a2d53ffddb7a1750264640afab8e9c23119e648b5259f1b5e7d51bc #[test] fn test_get_transaction_trace() { - let rpc_state = RpcState::new(RpcChain::TestNet2, BlockTag::Latest.into()); + let rpc_state = RpcState::new_infura(RpcChain::TestNet2, BlockTag::Latest.into()); let tx_hash = TransactionHash(stark_felt!( "19feb888a2d53ffddb7a1750264640afab8e9c23119e648b5259f1b5e7d51bc" @@ -716,7 +160,7 @@ mod tests { assert_eq!(tx_trace.validate_invocation.retdata, Some(vec![])); assert_eq_sorted!( tx_trace.validate_invocation.execution_resources, - VmExecutionResources { + ExecutionResources { n_steps: 790, n_memory_holes: 51, builtin_instance_counter: HashMap::from([ @@ -758,7 +202,7 @@ mod tests { .as_ref() .unwrap() .execution_resources, - VmExecutionResources { + ExecutionResources { n_steps: 2808, n_memory_holes: 136, builtin_instance_counter: HashMap::from([ @@ -812,7 +256,7 @@ mod tests { ); assert_eq_sorted!( tx_trace.fee_transfer_invocation.execution_resources, - VmExecutionResources { + ExecutionResources { n_steps: 586, n_memory_holes: 42, builtin_instance_counter: HashMap::from([ @@ -826,7 +270,7 @@ mod tests { #[test] fn test_get_transaction_receipt() { - let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); let tx_hash = TransactionHash(stark_felt!( "06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955" )); @@ -834,616 +278,3 @@ mod tests { rpc_state.get_transaction_receipt(&tx_hash); } } - -mod blockifier_transaction_tests { - use blockifier::{ - block_context::BlockContext, - execution::contract_class::ContractClass, - state::{ - cached_state::{CachedState, GlobalContractCache}, - state_api::{StateReader, StateResult}, - }, - transaction::{ - account_transaction::AccountTransaction, - objects::TransactionExecutionInfo, - transactions::{ExecutableTransaction, InvokeTransaction}, - }, - }; - use starknet_api::{ - contract_address, - core::{CompiledClassHash, Nonce, PatriciaKey}, - patricia_key, stark_felt, - transaction::TransactionHash, - }; - - use super::*; - - pub struct RpcStateReader(RpcState); - - impl StateReader for RpcStateReader { - fn get_storage_at( - &mut self, - contract_address: ContractAddress, - key: StorageKey, - ) -> StateResult { - Ok(self.0.get_storage_at(&contract_address, &key)) - } - - fn get_nonce_at(&mut self, contract_address: ContractAddress) -> StateResult { - Ok(Nonce(self.0.get_nonce_at(&contract_address))) - } - - fn get_class_hash_at( - &mut self, - contract_address: ContractAddress, - ) -> StateResult { - Ok(self.0.get_class_hash_at(&contract_address)) - } - - /// Returns the contract class of the given class hash. - fn get_compiled_contract_class( - &mut self, - class_hash: &ClassHash, - ) -> StateResult { - Ok(match self.0.get_contract_class(class_hash) { - SNContractClass::Legacy(compressed_legacy_cc) => { - let as_str = utils::decode_reader(compressed_legacy_cc.program).unwrap(); - let program = Program::from_bytes(as_str.as_bytes(), None).unwrap(); - let entry_points_by_type = utils::map_entry_points_by_type_legacy( - compressed_legacy_cc.entry_points_by_type, - ); - let inner = Arc::new(ContractClassV0Inner { - program, - entry_points_by_type, - }); - BlockifierContractClass::V0(ContractClassV0(inner)) - } - SNContractClass::Sierra(flattened_sierra_cc) => { - let middle_sierra: utils::MiddleSierraContractClass = { - let v = serde_json::to_value(flattened_sierra_cc).unwrap(); - serde_json::from_value(v).unwrap() - }; - let sierra_cc = SierraContractClass { - sierra_program: middle_sierra.sierra_program, - contract_class_version: middle_sierra.contract_class_version, - entry_points_by_type: middle_sierra.entry_points_by_type, - sierra_program_debug_info: None, - abi: None, - }; - let casm_cc = CasmContractClass::from_contract_class(sierra_cc, false).unwrap(); - BlockifierContractClass::V1(casm_cc.try_into().unwrap()) - } - }) - } - - /// Returns the compiled class hash of the given class hash. - fn get_compiled_class_hash( - &mut self, - class_hash: ClassHash, - ) -> StateResult { - Ok(CompiledClassHash( - self.0 - .get_class_hash_at(&ContractAddress(class_hash.0.try_into().unwrap())) - .0, - )) - } - } - - #[allow(unused)] - pub fn execute_tx( - tx_hash: &str, - network: RpcChain, - block_number: BlockNumber, - ) -> ( - TransactionExecutionInfo, - TransactionTrace, - RpcTransactionReceipt, - ) { - let tx_hash = tx_hash.strip_prefix("0x").unwrap(); - - // Instantiate the RPC StateReader and the CachedState - let rpc_reader = RpcStateReader(RpcState::new(network, block_number.into())); - let gas_price = rpc_reader.0.get_gas_price(block_number.0).unwrap(); - - // Get values for block context before giving ownership of the reader - let chain_id = rpc_reader.0.get_chain_name(); - let RpcBlockInfo { - block_number, - block_timestamp, - sequencer_address, - .. - } = rpc_reader.0.get_block_info(); - - // Get transaction before giving ownership of the reader - let tx_hash = TransactionHash(stark_felt!(tx_hash)); - let sn_api_tx = rpc_reader.0.get_transaction(&tx_hash); - - let trace = rpc_reader.0.get_transaction_trace(&tx_hash); - let receipt = rpc_reader.0.get_transaction_receipt(&tx_hash); - - // Create state from RPC reader - let global_cache = GlobalContractCache::default(); - let mut state = CachedState::new(rpc_reader, global_cache); - - let fee_token_address = - contract_address!("049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"); - - const N_STEPS_FEE_WEIGHT: f64 = 0.01; - let vm_resource_fee_cost = Arc::new(HashMap::from([ - ("n_steps".to_string(), N_STEPS_FEE_WEIGHT), - ("output_builtin".to_string(), 0.0), - ("pedersen_builtin".to_string(), N_STEPS_FEE_WEIGHT * 32.0), - ("range_check_builtin".to_string(), N_STEPS_FEE_WEIGHT * 16.0), - ("ecdsa_builtin".to_string(), N_STEPS_FEE_WEIGHT * 2048.0), - ("bitwise_builtin".to_string(), N_STEPS_FEE_WEIGHT * 64.0), - ("ec_op_builtin".to_string(), N_STEPS_FEE_WEIGHT * 1024.0), - ("poseidon_builtin".to_string(), N_STEPS_FEE_WEIGHT * 32.0), - ( - "segment_arena_builtin".to_string(), - N_STEPS_FEE_WEIGHT * 10.0, - ), - ("keccak_builtin".to_string(), N_STEPS_FEE_WEIGHT * 2048.0), // 2**11 - ])); - - let block_context = BlockContext { - chain_id, - block_number, - block_timestamp, - sequencer_address, - fee_token_address, - vm_resource_fee_cost, - gas_price, - invoke_tx_max_n_steps: 1_000_000, - validate_max_n_steps: 1_000_000, - max_recursion_depth: 500, - }; - - // Map starknet_api transaction to blockifier's - let blockifier_tx = match sn_api_tx { - SNTransaction::Invoke(tx) => { - let invoke = InvokeTransaction { tx, tx_hash }; - AccountTransaction::Invoke(invoke) - } - _ => unimplemented!(), - }; - - ( - blockifier_tx - .execute(&mut state, &block_context, true, true) - .unwrap(), - trace, - receipt, - ) - } - - #[cfg(test)] - mod test { - use blockifier::execution::entry_point::CallInfo; - use pretty_assertions_sorted::{assert_eq, assert_eq_sorted}; - use test_case::test_case; - - use super::*; - - #[test] - fn test_get_gas_price() { - let block = BlockValue::Number(BlockNumber(169928)); - let rpc_state = RpcState::new(RpcChain::MainNet, block); - - let price = rpc_state.get_gas_price(169928).unwrap(); - assert_eq!(price, 22804578690); - } - - #[test] - fn test_recent_tx() { - let (tx_info, trace, receipt) = execute_tx( - "0x05d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91", - RpcChain::MainNet, - BlockNumber(169928), - ); - - let TransactionExecutionInfo { - execute_call_info, - actual_fee, - .. - } = tx_info; - - let CallInfo { - vm_resources, - inner_calls, - .. - } = execute_call_info.unwrap(); - - assert_eq!(actual_fee.0, receipt.actual_fee); - assert_eq!( - vm_resources, - trace - .function_invocation - .as_ref() - .unwrap() - .execution_resources - ); - assert_eq!( - inner_calls.len(), - trace - .function_invocation - .as_ref() - .unwrap() - .internal_calls - .len() - ); - } - - #[test_case( - "0x05d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91", - 169928, // real block 169929 - RpcChain::MainNet - => ignore["gas mismatch"] - )] - #[test_case( - "0x0528ec457cf8757f3eefdf3f0728ed09feeecc50fd97b1e4c5da94e27e9aa1d6", - 169928, // real block 169929 - RpcChain::MainNet - => ignore["gas mismatch"] - )] - #[test_case( - "0x0737677385a30ec4cbf9f6d23e74479926975b74db3d55dc5e46f4f8efee41cf", - 169928, // real block 169929 - RpcChain::MainNet - => ignore["resource mismatch"] - )] - #[test_case( - "0x026c17728b9cd08a061b1f17f08034eb70df58c1a96421e73ee6738ad258a94c", - 169928, // real block 169929 - RpcChain::MainNet - => ignore["gas mismatch"] - )] - #[test_case( - // review later - "0x0743092843086fa6d7f4a296a226ee23766b8acf16728aef7195ce5414dc4d84", - 186548, // real block 186549 - RpcChain::MainNet - => ignore["resource mismatch"] - )] - #[test_case( - // fails in blockifier too - "0x00724fc4a84f489ed032ebccebfc9541eb8dc64b0e76b933ed6fc30cd6000bd1", - 186551, // real block 186552 - RpcChain::MainNet - => ignore["gas mismatch"] - )] - fn test_case_tx(hash: &str, block_number: u64, chain: RpcChain) { - let (tx_info, trace, receipt) = execute_tx(hash, chain, BlockNumber(block_number)); - - let TransactionExecutionInfo { - execute_call_info, - actual_fee, - .. - } = tx_info; - - let CallInfo { - vm_resources, - inner_calls, - .. - } = execute_call_info.unwrap(); - - let actual_fee = actual_fee.0; - if receipt.actual_fee != actual_fee { - let diff = 100 * receipt.actual_fee.abs_diff(actual_fee) / receipt.actual_fee; - - if diff >= 5 { - assert_eq!( - actual_fee, receipt.actual_fee, - "actual_fee mismatch differs from the baseline by more than 5% ({diff}%)", - ); - } - } - - assert_eq_sorted!( - vm_resources, - trace - .function_invocation - .as_ref() - .unwrap() - .execution_resources - ); - assert_eq!( - inner_calls.len(), - trace - .function_invocation - .as_ref() - .unwrap() - .internal_calls - .len() - ); - } - } -} - -mod starknet_in_rust_transaction_tests { - use cairo_vm::felt::{felt_str, Felt252}; - use starknet_api::{core::PatriciaKey, stark_felt, transaction::TransactionHash}; - use starknet_in_rust::{ - core::errors::state_errors::StateError, - definitions::{ - block_context::{BlockContext, StarknetChainId, StarknetOsConfig}, - constants::{ - DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS, - DEFAULT_CONTRACT_STORAGE_COMMITMENT_TREE_HEIGHT, - DEFAULT_GLOBAL_STATE_COMMITMENT_TREE_HEIGHT, DEFAULT_INVOKE_TX_MAX_N_STEPS, - DEFAULT_VALIDATE_MAX_N_STEPS, - }, - }, - execution::TransactionExecutionInfo, - services::api::contract_classes::compiled_class::CompiledClass, - state::{ - cached_state::{CachedState, ContractClassCache}, - state_api::StateReader, - state_cache::StorageEntry, - BlockInfo, - }, - transaction::{InvokeFunction, Transaction}, - utils::{Address, ClassHash}, - }; - - use super::*; - - pub struct RpcStateReader(RpcState); - - impl StateReader for RpcStateReader { - fn get_contract_class(&self, class_hash: &ClassHash) -> Result { - let hash = ClassHash(StarkHash::new(*class_hash).unwrap()); - Ok(CompiledClass::from(self.0.get_contract_class(&hash))) - } - - fn get_class_hash_at(&self, contract_address: &Address) -> Result { - let address = ContractAddress( - PatriciaKey::try_from( - StarkHash::new(contract_address.clone().0.to_be_bytes()).unwrap(), - ) - .unwrap(), - ); - let mut bytes = [0u8; 32]; - bytes.copy_from_slice(self.0.get_class_hash_at(&address).0.bytes()); - Ok(bytes) - } - - fn get_nonce_at(&self, contract_address: &Address) -> Result { - let address = ContractAddress( - PatriciaKey::try_from( - StarkHash::new(contract_address.clone().0.to_be_bytes()).unwrap(), - ) - .unwrap(), - ); - let nonce = self.0.get_nonce_at(&address); - Ok(Felt252::from_bytes_be(nonce.bytes())) - } - fn get_storage_at(&self, storage_entry: &StorageEntry) -> Result { - let (contract_address, key) = storage_entry; - let address = ContractAddress( - PatriciaKey::try_from( - StarkHash::new(contract_address.clone().0.to_be_bytes()).unwrap(), - ) - .unwrap(), - ); - let key = StorageKey(PatriciaKey::try_from(StarkHash::new(*key).unwrap()).unwrap()); - let value = self.0.get_storage_at(&address, &key); - Ok(Felt252::from_bytes_be(value.bytes())) - } - fn get_compiled_class_hash(&self, class_hash: &ClassHash) -> Result<[u8; 32], StateError> { - let address = ContractAddress( - PatriciaKey::try_from(StarkHash::new(*class_hash).unwrap()).unwrap(), - ); - let mut bytes = [0u8; 32]; - bytes.copy_from_slice(self.0.get_class_hash_at(&address).0.bytes()); - Ok(bytes) - } - } - - #[allow(unused)] - pub fn execute_tx( - tx_hash: &str, - network: RpcChain, - block_number: BlockNumber, - ) -> ( - TransactionExecutionInfo, - TransactionTrace, - RpcTransactionReceipt, - ) { - let fee_token_address = Address(felt_str!( - "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - 16 - )); - - let tx_hash = tx_hash.strip_prefix("0x").unwrap(); - - // Instantiate the RPC StateReader and the CachedState - let rpc_reader = RpcStateReader(RpcState::new(network, block_number.into())); - let gas_price = rpc_reader.0.get_gas_price(block_number.0).unwrap(); - - // Get values for block context before giving ownership of the reader - let chain_id = match rpc_reader.0.chain { - RpcChain::MainNet => StarknetChainId::MainNet, - RpcChain::TestNet => StarknetChainId::TestNet, - RpcChain::TestNet2 => StarknetChainId::TestNet2, - }; - let starknet_os_config = - StarknetOsConfig::new(chain_id.to_felt(), fee_token_address, gas_price); - let block_info = { - let RpcBlockInfo { - block_number, - block_timestamp, - sequencer_address, - .. - } = rpc_reader.0.get_block_info(); - - let block_number = block_number.0; - let block_timestamp = block_timestamp.0; - let sequencer_address = - Address(Felt252::from_bytes_be(sequencer_address.0.key().bytes())); - - BlockInfo { - block_number, - block_timestamp, - gas_price, - sequencer_address, - } - }; - - // Get transaction before giving ownership of the reader - let tx_hash = TransactionHash(stark_felt!(tx_hash)); - let tx = match rpc_reader.0.get_transaction(&tx_hash) { - SNTransaction::Invoke(tx) => Transaction::InvokeFunction( - InvokeFunction::from_invoke_transaction(tx, chain_id).unwrap(), - ), - _ => unimplemented!(), - }; - - let trace = rpc_reader.0.get_transaction_trace(&tx_hash); - let receipt = rpc_reader.0.get_transaction_receipt(&tx_hash); - - let class_cache = ContractClassCache::default(); - let mut state = CachedState::new(Arc::new(rpc_reader), class_cache); - - let block_context = BlockContext::new( - starknet_os_config, - DEFAULT_CONTRACT_STORAGE_COMMITMENT_TREE_HEIGHT, - DEFAULT_GLOBAL_STATE_COMMITMENT_TREE_HEIGHT, - DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS.clone(), - DEFAULT_INVOKE_TX_MAX_N_STEPS, - DEFAULT_VALIDATE_MAX_N_STEPS, - block_info, - Default::default(), - true, - ); - - ( - tx.execute(&mut state, &block_context, u128::MAX).unwrap(), - trace, - receipt, - ) - } - - #[cfg(test)] - mod test { - use pretty_assertions_sorted::{assert_eq, assert_eq_sorted}; - use starknet_in_rust::execution::CallInfo; - use test_case::test_case; - - use super::*; - - #[test] - fn test_get_transaction_try_from() { - let rpc_state = RpcState::new(RpcChain::MainNet, BlockTag::Latest.into()); - let str_hash = - stark_felt!("0x5d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91"); - let tx_hash = TransactionHash(str_hash); - - let sn_tx = rpc_state.get_transaction(&tx_hash); - match &sn_tx { - SNTransaction::Invoke(sn_tx) => { - let tx = InvokeFunction::from_invoke_transaction( - sn_tx.clone(), - StarknetChainId::MainNet, - ) - .unwrap(); - assert_eq!(tx.hash_value().to_be_bytes().as_slice(), str_hash.bytes()) - } - _ => unimplemented!(), - }; - } - - #[test] - fn test_get_gas_price() { - let block = BlockValue::Number(BlockNumber(169928)); - let rpc_state = RpcState::new(RpcChain::MainNet, block); - - let price = rpc_state.get_gas_price(169928).unwrap(); - assert_eq!(price, 22804578690); - } - - #[test_case( - "0x05d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91", - 169928, // real block 169929 - RpcChain::MainNet - => ignore["gas mismatch"] - )] - #[test_case( - "0x0528ec457cf8757f3eefdf3f0728ed09feeecc50fd97b1e4c5da94e27e9aa1d6", - 169928, // real block 169929 - RpcChain::MainNet - => ignore["gas mismatch"] - )] - #[test_case( - "0x0737677385a30ec4cbf9f6d23e74479926975b74db3d55dc5e46f4f8efee41cf", - 169928, // real block 169929 - RpcChain::MainNet - => ignore["resource mismatch"] - )] - #[test_case( - "0x026c17728b9cd08a061b1f17f08034eb70df58c1a96421e73ee6738ad258a94c", - 169928, // real block 169929 - RpcChain::MainNet - => ignore["gas mismatch"] - )] - #[test_case( - // review later - "0x0743092843086fa6d7f4a296a226ee23766b8acf16728aef7195ce5414dc4d84", - 186548, // real block 186549 - RpcChain::MainNet - => ignore["resource mismatch"] - )] - #[test_case( - // fails in blockifier too - "0x00724fc4a84f489ed032ebccebfc9541eb8dc64b0e76b933ed6fc30cd6000bd1", - 186551, // real block 186552 - RpcChain::MainNet - => ignore["gas mismatch"] - )] - fn test_case_tx(hash: &str, block_number: u64, chain: RpcChain) { - let (tx_info, trace, receipt) = execute_tx(hash, chain, BlockNumber(block_number)); - - let TransactionExecutionInfo { - call_info, - actual_fee, - .. - } = tx_info; - - let CallInfo { - execution_resources, - internal_calls, - .. - } = call_info.unwrap(); - - assert_eq_sorted!( - execution_resources, - trace - .function_invocation - .as_ref() - .unwrap() - .execution_resources, - "execution resources mismatch" - ); - assert_eq!( - internal_calls.len(), - trace - .function_invocation - .as_ref() - .unwrap() - .internal_calls - .len(), - "internal calls length mismatch" - ); - - if receipt.actual_fee != actual_fee { - let diff = 100 * receipt.actual_fee.abs_diff(actual_fee) / receipt.actual_fee; - - if diff >= 5 { - assert_eq!( - actual_fee, receipt.actual_fee, - "actual_fee mismatch differs from the baseline by more than 5% ({diff}%)", - ); - } - } - } - } -} diff --git a/rpc_state_reader_sn_api/src/rpc_state.rs b/rpc_state_reader_sn_api/src/rpc_state.rs new file mode 100644 index 000000000..b2d0f8149 --- /dev/null +++ b/rpc_state_reader_sn_api/src/rpc_state.rs @@ -0,0 +1,449 @@ +use cairo_vm::vm::runners::cairo_runner::ExecutionResources as VmExecutionResources; +use core::fmt; +use dotenv::dotenv; +use serde::{Deserialize, Deserializer}; +use serde_json::json; +use starknet::core::types::ContractClass as SNContractClass; +use starknet_api::{ + block::{BlockNumber, BlockTimestamp}, + core::{ChainId, ClassHash, ContractAddress}, + hash::{StarkFelt, StarkHash}, + state::StorageKey, + transaction::{Transaction as SNTransaction, TransactionHash}, +}; +use std::{collections::HashMap, env, fmt::Display}; +use thiserror::Error; + +use crate::utils; + +/// Starknet chains supported in Infura. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub enum RpcChain { + MainNet, + TestNet, + TestNet2, +} + +impl fmt::Display for RpcChain { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + RpcChain::MainNet => write!(f, "starknet-mainnet"), + RpcChain::TestNet => write!(f, "starknet-goerli"), + RpcChain::TestNet2 => write!(f, "starknet-goerli2"), + } + } +} + +impl From for ChainId { + fn from(value: RpcChain) -> Self { + ChainId(match value { + RpcChain::MainNet => "alpha-mainnet".to_string(), + RpcChain::TestNet => "alpha4".to_string(), + RpcChain::TestNet2 => "alpha4-2".to_string(), + }) + } +} + +/// A [StateReader] that holds all the data in memory. +/// +/// This implementation is uses HTTP requests to call the RPC endpoint, +/// using Infura. +/// In order to use it an Infura API key is necessary. +#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub struct RpcState { + /// Enum with one of the supported Infura chains/ + pub chain: RpcChain, + /// RPC Endpoint URL. + rpc_endpoint: String, + /// The url to the starknet feeder. + feeder_url: String, + /// Struct that holds information on the block where we are going to use to read the state. + pub block: BlockValue, +} + +#[derive(Error, Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] +enum RpcError { + #[error("RPC call failed with error: {0}")] + RpcCall(String), + #[error("Request failed with error: {0}")] + Request(String), +} + +/// Represents the tag of a block value. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub enum BlockTag { + Latest, + Pending, +} + +impl Display for BlockTag { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let string = match self { + BlockTag::Latest => "latest", + BlockTag::Pending => "pending", + }; + write!(f, "{}", string) + } +} + +/// [`BlockValue`] is an Enum that represent which block we are going to use to retrieve information. +#[allow(dead_code)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub enum BlockValue { + /// String one of: ["latest", "pending"] + Tag(BlockTag), + /// Integer + Number(BlockNumber), + /// String with format: 0x{felt252} + Hash(StarkHash), +} + +impl From for BlockValue { + fn from(value: BlockTag) -> Self { + BlockValue::Tag(value) + } +} + +impl From for BlockValue { + fn from(value: BlockNumber) -> Self { + BlockValue::Number(value) + } +} + +impl From for BlockValue { + fn from(value: StarkHash) -> Self { + BlockValue::Hash(value) + } +} + +impl BlockValue { + fn to_value(self) -> Result { + serde_json::to_value(match self { + BlockValue::Tag(block_tag) => block_tag.to_string().into(), + BlockValue::Number(block_number) => json!({ "block_number": block_number }), + BlockValue::Hash(block_hash) => json!({ "block_hash": block_hash }), + }) + } +} + +/// The RPC block info. +#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub struct RpcBlockInfo { + /// The sequence number of the last block created. + pub block_number: BlockNumber, + /// Timestamp of the beginning of the last block creation attempt. + pub block_timestamp: BlockTimestamp, + /// The sequencer address of this block. + pub sequencer_address: ContractAddress, + /// The transactions of this block. + pub transactions: Vec, +} + +/// A RPC response. +#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub struct RpcResponse { + result: T, +} + +#[derive(Debug, Deserialize, Clone, Eq, PartialEq)] +pub struct TransactionTrace { + pub validate_invocation: RpcCallInfo, + pub function_invocation: Option, + pub fee_transfer_invocation: RpcCallInfo, + pub signature: Vec, + pub revert_error: Option, +} + +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)] +pub struct RpcExecutionResources { + pub n_steps: usize, + pub n_memory_holes: usize, + pub builtin_instance_counter: HashMap, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct RpcCallInfo { + pub execution_resources: VmExecutionResources, + pub retdata: Option>, + pub calldata: Option>, + pub internal_calls: Vec, +} + +#[allow(unused)] +#[derive(Debug, Deserialize)] +pub struct RpcTransactionReceipt { + #[serde(deserialize_with = "actual_fee_deser")] + pub actual_fee: u128, + pub block_hash: StarkHash, + pub block_number: u64, + pub execution_status: String, + #[serde(rename = "type")] + pub tx_type: String, +} + +fn actual_fee_deser<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let hex: String = Deserialize::deserialize(deserializer)?; + Ok(u128::from_str_radix(&hex[2..], 16).unwrap()) +} + +impl<'de> Deserialize<'de> for RpcCallInfo { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let value: serde_json::Value = Deserialize::deserialize(deserializer)?; + + // Parse execution_resources + let execution_resources_value = value["execution_resources"].clone(); + + let execution_resources = VmExecutionResources { + n_steps: serde_json::from_value(execution_resources_value["n_steps"].clone()) + .map_err(serde::de::Error::custom)?, + n_memory_holes: serde_json::from_value( + execution_resources_value["n_memory_holes"].clone(), + ) + .map_err(serde::de::Error::custom)?, + builtin_instance_counter: serde_json::from_value( + execution_resources_value["builtin_instance_counter"].clone(), + ) + .map_err(serde::de::Error::custom)?, + }; + + // Parse retdata + let retdata_value = value["result"].clone(); + let retdata = serde_json::from_value(retdata_value).unwrap(); + + // Parse calldata + let calldata_value = value["calldata"].clone(); + let calldata = serde_json::from_value(calldata_value).unwrap(); + + // Parse internal calls + let internal_calls_value = value["internal_calls"].clone(); + let mut internal_calls = vec![]; + + for call in internal_calls_value.as_array().unwrap() { + internal_calls + .push(serde_json::from_value(call.clone()).map_err(serde::de::Error::custom)?); + } + + Ok(RpcCallInfo { + execution_resources, + retdata, + calldata, + internal_calls, + }) + } +} + +impl RpcState { + pub fn new(chain: RpcChain, block: BlockValue, rpc_endpoint: &str, feeder_url: &str) -> Self { + Self { + chain, + rpc_endpoint: rpc_endpoint.to_string(), + feeder_url: feeder_url.to_string(), + block, + } + } + + pub fn new_infura(chain: RpcChain, block: BlockValue) -> Self { + if env::var("INFURA_API_KEY").is_err() { + dotenv().expect("Missing .env file"); + } + + let rpc_endpoint = format!( + "https://{}.infura.io/v3/{}", + chain, + env::var("INFURA_API_KEY").expect("missing infura api key") + ); + + let chain_id: ChainId = chain.into(); + let feeder_url = format!("https://{}.starknet.io/feeder_gateway", chain_id); + + Self::new(chain, block, &rpc_endpoint, &feeder_url) + } + + fn rpc_call_result Deserialize<'a>>( + &self, + method: &str, + params: &serde_json::Value, + ) -> Result { + Ok(self.rpc_call::>(method, params)?.result) + } + + fn rpc_call Deserialize<'a>>( + &self, + method: &str, + params: &serde_json::Value, + ) -> Result { + let payload = serde_json::json!({ + "jsonrpc": "2.0", + "method": method, + "params": params, + "id": 1 + }); + Self::deserialize_call(self.rpc_call_no_deserialize(&payload)?.into_json().unwrap()) + } + + fn rpc_call_no_deserialize( + &self, + params: &serde_json::Value, + ) -> Result { + ureq::post(&self.rpc_endpoint) + .set("Content-Type", "application/json") + .set("accept", "application/json") + .send_json(params) + .map_err(|err| RpcError::Request(err.to_string())) + } + + fn deserialize_call Deserialize<'a>>( + response: serde_json::Value, + ) -> Result { + serde_json::from_value(response).map_err(|err| RpcError::RpcCall(err.to_string())) + } + + /// Gets the url of the feeder endpoint + fn get_feeder_endpoint(&self, path: &str) -> String { + format!("{}/{}", self.feeder_url, path) + } + + /// Requests the transaction trace to the Feeder Gateway API. + /// It's useful for testing the transaction outputs like: + /// - execution resources + /// - actual fee + /// - events + /// - return data + pub fn get_transaction_trace(&self, hash: &TransactionHash) -> TransactionTrace { + let response = ureq::get(&self.get_feeder_endpoint("get_transaction_trace")) + .query("transactionHash", &hash.0.to_string()) + .call() + .unwrap(); + + serde_json::from_value(response.into_json().unwrap()).unwrap() + } + + /// Requests the given transaction to the Feeder Gateway API. + pub fn get_transaction(&self, hash: &TransactionHash) -> SNTransaction { + let result = self + .rpc_call::( + "starknet_getTransactionByHash", + &json!([hash.to_string()]), + ) + .unwrap()["result"] + .clone(); + utils::deserialize_transaction_json(result).unwrap() + } + + /// Gets the gas price of a given block. + pub fn get_gas_price(&self, block_number: u64) -> serde_json::Result { + let response = ureq::get(&self.get_feeder_endpoint("get_block")) + .query("blockNumber", &block_number.to_string()) + .call() + .unwrap(); + + let res: serde_json::Value = response.into_json().expect("should be json"); + + let gas_price_hex = res["gas_price"].as_str().unwrap(); + let gas_price = u128::from_str_radix(gas_price_hex.trim_start_matches("0x"), 16).unwrap(); + Ok(gas_price) + } + + pub fn get_chain_name(&self) -> ChainId { + self.chain.into() + } + + pub fn get_block_info(&self) -> RpcBlockInfo { + let block_info: serde_json::Value = self + .rpc_call( + "starknet_getBlockWithTxs", + &json!([self.block.to_value().unwrap()]), + ) + .unwrap(); + let sequencer_address: StarkFelt = + serde_json::from_value(block_info["result"]["sequencer_address"].clone()).unwrap(); + + let transactions: Vec<_> = block_info["result"]["transactions"] + .as_array() + .unwrap() + .iter() + .filter_map(|result| utils::deserialize_transaction_json(result.clone()).ok()) + .collect(); + + RpcBlockInfo { + block_number: BlockNumber( + block_info["result"]["block_number"] + .to_string() + .parse::() + .unwrap(), + ), + block_timestamp: BlockTimestamp( + block_info["result"]["timestamp"] + .to_string() + .parse::() + .unwrap(), + ), + sequencer_address: ContractAddress(sequencer_address.try_into().unwrap()), + transactions, + } + } + + pub fn get_contract_class(&self, class_hash: &ClassHash) -> SNContractClass { + self.rpc_call_result( + "starknet_getClass", + &json!([self.block.to_value().unwrap(), class_hash.0.to_string()]), + ) + .unwrap() + } + + pub fn get_class_hash_at(&self, contract_address: &ContractAddress) -> ClassHash { + let hash = self + .rpc_call_result( + "starknet_getClassHashAt", + &json!([ + self.block.to_value().unwrap(), + contract_address.0.key().clone().to_string() + ]), + ) + .unwrap(); + + ClassHash(hash) + } + + pub fn get_nonce_at(&self, contract_address: &ContractAddress) -> StarkFelt { + self.rpc_call_result( + "starknet_getNonce", + &json!([ + self.block.to_value().unwrap(), + contract_address.0.key().clone().to_string() + ]), + ) + .unwrap() + } + + pub fn get_storage_at( + &self, + contract_address: &ContractAddress, + key: &StorageKey, + ) -> StarkFelt { + let contract_address = contract_address.0.key(); + let key = key.0.key(); + + self.rpc_call_result( + "starknet_getStorageAt", + &json!([ + contract_address.to_string(), + key.to_string(), + self.block.to_value().unwrap() + ]), + ) + .unwrap() + } + + /// Requests the given transaction to the Feeder Gateway API. + pub fn get_transaction_receipt(&self, hash: &TransactionHash) -> RpcTransactionReceipt { + self.rpc_call_result("starknet_getTransactionReceipt", &json!([hash.to_string()])) + .unwrap() + } +} diff --git a/rpc_state_reader_sn_api/src/utils.rs b/rpc_state_reader_sn_api/src/utils.rs new file mode 100644 index 000000000..a56d9f3b7 --- /dev/null +++ b/rpc_state_reader_sn_api/src/utils.rs @@ -0,0 +1,89 @@ +use std::{ + collections::HashMap, + io::{self, Read}, +}; + +use cairo_lang_starknet::contract_class::ContractEntryPoints; +use cairo_lang_utils::bigint::BigUintAsHex; +use serde::Deserialize; +use starknet::core::types::{LegacyContractEntryPoint, LegacyEntryPointsByType}; +use starknet_api::{ + core::EntryPointSelector, + deprecated_contract_class::{EntryPoint, EntryPointOffset, EntryPointType}, + hash::{StarkFelt, StarkHash}, + transaction::{InvokeTransaction, Transaction}, +}; + +#[derive(Debug, Deserialize)] +pub struct MiddleSierraContractClass { + pub sierra_program: Vec, + pub contract_class_version: String, + pub entry_points_by_type: ContractEntryPoints, +} + +pub fn map_entry_points_by_type_legacy( + entry_points_by_type: LegacyEntryPointsByType, +) -> HashMap> { + let entry_types_to_points = HashMap::from([ + ( + EntryPointType::Constructor, + entry_points_by_type.constructor, + ), + (EntryPointType::External, entry_points_by_type.external), + (EntryPointType::L1Handler, entry_points_by_type.l1_handler), + ]); + + let to_contract_entry_point = |entrypoint: &LegacyContractEntryPoint| -> EntryPoint { + let felt: StarkFelt = StarkHash::new(entrypoint.selector.to_bytes_be()).unwrap(); + EntryPoint { + offset: EntryPointOffset(entrypoint.offset as usize), + selector: EntryPointSelector(felt), + } + }; + + let mut entry_points_by_type_map = HashMap::new(); + for (entry_point_type, entry_points) in entry_types_to_points.into_iter() { + let values = entry_points + .iter() + .map(to_contract_entry_point) + .collect::>(); + entry_points_by_type_map.insert(entry_point_type, values); + } + + entry_points_by_type_map +} + +/// Uncompresses a Gz Encoded vector of bytes and returns a string or error +/// Here &[u8] implements BufRead +pub fn decode_reader(bytes: Vec) -> io::Result { + use flate2::bufread; + let mut gz = bufread::GzDecoder::new(&bytes[..]); + let mut s = String::new(); + gz.read_to_string(&mut s)?; + Ok(s) +} + +/// Freestanding deserialize method to avoid a new type. +pub fn deserialize_transaction_json( + transaction: serde_json::Value, +) -> serde_json::Result { + let tx_type: String = serde_json::from_value(transaction["type"].clone())?; + let tx_version: String = serde_json::from_value(transaction["version"].clone())?; + + match tx_type.as_str() { + "INVOKE" => match tx_version.as_str() { + "0x0" => Ok(Transaction::Invoke(InvokeTransaction::V0( + serde_json::from_value(transaction)?, + ))), + "0x1" => Ok(Transaction::Invoke(InvokeTransaction::V1( + serde_json::from_value(transaction)?, + ))), + x => Err(serde::de::Error::custom(format!( + "unimplemented invoke version: {x}" + ))), + }, + x => Err(serde::de::Error::custom(format!( + "unimplemented transaction type deserialization: {x}" + ))), + } +} diff --git a/rpc_state_reader_sn_api/tests/blockifier_tests.rs b/rpc_state_reader_sn_api/tests/blockifier_tests.rs new file mode 100644 index 000000000..ee3ed029b --- /dev/null +++ b/rpc_state_reader_sn_api/tests/blockifier_tests.rs @@ -0,0 +1,318 @@ +use blockifier::{ + block_context::BlockContext, + execution::{contract_class::ContractClass, entry_point::CallInfo}, + state::{ + cached_state::{CachedState, GlobalContractCache}, + state_api::{StateReader, StateResult}, + }, + transaction::{ + account_transaction::AccountTransaction, objects::TransactionExecutionInfo, + transactions::ExecutableTransaction, + }, +}; +use blockifier::{ + execution::contract_class::{ + ContractClass as BlockifierContractClass, ContractClassV0, ContractClassV0Inner, + }, + transaction::transactions::InvokeTransaction, +}; +use cairo_lang_starknet::{ + casm_contract_class::CasmContractClass, contract_class::ContractClass as SierraContractClass, +}; +use cairo_vm::types::program::Program; +use pretty_assertions_sorted::{assert_eq, assert_eq_sorted}; +use rpc_state_reader_sn_api::rpc_state::*; +use rpc_state_reader_sn_api::utils; +use starknet::core::types::ContractClass as SNContractClass; +use starknet_api::{ + block::BlockNumber, + contract_address, + core::{ClassHash, CompiledClassHash, ContractAddress, Nonce, PatriciaKey}, + hash::{StarkFelt, StarkHash}, + patricia_key, stark_felt, + state::StorageKey, + transaction::{Transaction as SNTransaction, TransactionHash}, +}; +use test_case::test_case; + +use std::{collections::HashMap, sync::Arc}; + +pub struct RpcStateReader(RpcState); + +impl StateReader for RpcStateReader { + fn get_storage_at( + &mut self, + contract_address: ContractAddress, + key: StorageKey, + ) -> StateResult { + Ok(self.0.get_storage_at(&contract_address, &key)) + } + + fn get_nonce_at(&mut self, contract_address: ContractAddress) -> StateResult { + Ok(Nonce(self.0.get_nonce_at(&contract_address))) + } + + fn get_class_hash_at(&mut self, contract_address: ContractAddress) -> StateResult { + Ok(self.0.get_class_hash_at(&contract_address)) + } + + /// Returns the contract class of the given class hash. + fn get_compiled_contract_class( + &mut self, + class_hash: &ClassHash, + ) -> StateResult { + Ok(match self.0.get_contract_class(class_hash) { + SNContractClass::Legacy(compressed_legacy_cc) => { + let as_str = utils::decode_reader(compressed_legacy_cc.program).unwrap(); + let program = Program::from_bytes(as_str.as_bytes(), None).unwrap(); + let entry_points_by_type = utils::map_entry_points_by_type_legacy( + compressed_legacy_cc.entry_points_by_type, + ); + let inner = Arc::new(ContractClassV0Inner { + program, + entry_points_by_type, + }); + BlockifierContractClass::V0(ContractClassV0(inner)) + } + SNContractClass::Sierra(flattened_sierra_cc) => { + let middle_sierra: utils::MiddleSierraContractClass = { + let v = serde_json::to_value(flattened_sierra_cc).unwrap(); + serde_json::from_value(v).unwrap() + }; + let sierra_cc = SierraContractClass { + sierra_program: middle_sierra.sierra_program, + contract_class_version: middle_sierra.contract_class_version, + entry_points_by_type: middle_sierra.entry_points_by_type, + sierra_program_debug_info: None, + abi: None, + }; + let casm_cc = CasmContractClass::from_contract_class(sierra_cc, false).unwrap(); + BlockifierContractClass::V1(casm_cc.try_into().unwrap()) + } + }) + } + + /// Returns the compiled class hash of the given class hash. + fn get_compiled_class_hash(&mut self, class_hash: ClassHash) -> StateResult { + Ok(CompiledClassHash( + self.0 + .get_class_hash_at(&ContractAddress(class_hash.0.try_into().unwrap())) + .0, + )) + } +} + +pub fn execute_tx( + tx_hash: &str, + network: RpcChain, + block_number: BlockNumber, +) -> ( + TransactionExecutionInfo, + TransactionTrace, + RpcTransactionReceipt, +) { + let tx_hash = tx_hash.strip_prefix("0x").unwrap(); + + // Instantiate the RPC StateReader and the CachedState + let rpc_reader = RpcStateReader(RpcState::new_infura(network, block_number.into())); + let gas_price = rpc_reader.0.get_gas_price(block_number.0).unwrap(); + + // Get values for block context before giving ownership of the reader + let chain_id = rpc_reader.0.get_chain_name(); + let RpcBlockInfo { + block_number, + block_timestamp, + sequencer_address, + .. + } = rpc_reader.0.get_block_info(); + + // Get transaction before giving ownership of the reader + let tx_hash = TransactionHash(stark_felt!(tx_hash)); + let sn_api_tx = rpc_reader.0.get_transaction(&tx_hash); + + let trace = rpc_reader.0.get_transaction_trace(&tx_hash); + let receipt = rpc_reader.0.get_transaction_receipt(&tx_hash); + + // Create state from RPC reader + let global_cache = GlobalContractCache::default(); + let mut state = CachedState::new(rpc_reader, global_cache); + + let fee_token_address = + contract_address!("049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"); + + const N_STEPS_FEE_WEIGHT: f64 = 0.01; + let vm_resource_fee_cost = Arc::new(HashMap::from([ + ("n_steps".to_string(), N_STEPS_FEE_WEIGHT), + ("output_builtin".to_string(), 0.0), + ("pedersen_builtin".to_string(), N_STEPS_FEE_WEIGHT * 32.0), + ("range_check_builtin".to_string(), N_STEPS_FEE_WEIGHT * 16.0), + ("ecdsa_builtin".to_string(), N_STEPS_FEE_WEIGHT * 2048.0), + ("bitwise_builtin".to_string(), N_STEPS_FEE_WEIGHT * 64.0), + ("ec_op_builtin".to_string(), N_STEPS_FEE_WEIGHT * 1024.0), + ("poseidon_builtin".to_string(), N_STEPS_FEE_WEIGHT * 32.0), + ( + "segment_arena_builtin".to_string(), + N_STEPS_FEE_WEIGHT * 10.0, + ), + ("keccak_builtin".to_string(), N_STEPS_FEE_WEIGHT * 2048.0), // 2**11 + ])); + + let block_context = BlockContext { + chain_id, + block_number, + block_timestamp, + sequencer_address, + fee_token_address, + vm_resource_fee_cost, + gas_price, + invoke_tx_max_n_steps: 1_000_000, + validate_max_n_steps: 1_000_000, + max_recursion_depth: 500, + }; + + // Map starknet_api transaction to blockifier's + let blockifier_tx = match sn_api_tx { + SNTransaction::Invoke(tx) => { + let invoke = InvokeTransaction { tx, tx_hash }; + AccountTransaction::Invoke(invoke) + } + _ => unimplemented!(), + }; + + ( + blockifier_tx + .execute(&mut state, &block_context, true, true) + .unwrap(), + trace, + receipt, + ) +} + +#[test] +fn test_get_gas_price() { + let block = BlockValue::Number(BlockNumber(169928)); + let rpc_state = RpcState::new_infura(RpcChain::MainNet, block); + + let price = rpc_state.get_gas_price(169928).unwrap(); + assert_eq!(price, 22804578690); +} + +#[test] +fn blockifier_test_recent_tx() { + let (tx_info, trace, receipt) = execute_tx( + "0x05d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91", + RpcChain::MainNet, + BlockNumber(169928), + ); + + let TransactionExecutionInfo { + execute_call_info, + actual_fee, + .. + } = tx_info; + + let CallInfo { + vm_resources, + inner_calls, + .. + } = execute_call_info.unwrap(); + + assert_eq!(actual_fee.0, receipt.actual_fee); + assert_eq!( + vm_resources, + trace + .function_invocation + .as_ref() + .unwrap() + .execution_resources + ); + assert_eq!( + inner_calls.len(), + trace + .function_invocation + .as_ref() + .unwrap() + .internal_calls + .len() + ); +} + +#[test_case( + "0x05d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91", + 169928, // real block 169929 + RpcChain::MainNet +)] +#[test_case( + "0x0528ec457cf8757f3eefdf3f0728ed09feeecc50fd97b1e4c5da94e27e9aa1d6", + 169928, // real block 169929 + RpcChain::MainNet +)] +#[test_case( + "0x0737677385a30ec4cbf9f6d23e74479926975b74db3d55dc5e46f4f8efee41cf", + 169928, // real block 169929 + RpcChain::MainNet + => ignore["resource mismatch"] +)] +#[test_case( + "0x026c17728b9cd08a061b1f17f08034eb70df58c1a96421e73ee6738ad258a94c", + 169928, // real block 169929 + RpcChain::MainNet +)] +#[test_case( + // review later + "0x0743092843086fa6d7f4a296a226ee23766b8acf16728aef7195ce5414dc4d84", + 186548, // real block 186549 + RpcChain::MainNet + => ignore["resource mismatch"] +)] +#[test_case( + // fails in blockifier too + "0x00724fc4a84f489ed032ebccebfc9541eb8dc64b0e76b933ed6fc30cd6000bd1", + 186551, // real block 186552 + RpcChain::MainNet +)] +fn blockifier_test_case_tx(hash: &str, block_number: u64, chain: RpcChain) { + let (tx_info, trace, receipt) = execute_tx(hash, chain, BlockNumber(block_number)); + + let TransactionExecutionInfo { + execute_call_info, + actual_fee, + .. + } = tx_info; + + let CallInfo { + vm_resources, + inner_calls, + .. + } = execute_call_info.unwrap(); + + let actual_fee = actual_fee.0; + if receipt.actual_fee != actual_fee { + let diff = 100 * receipt.actual_fee.abs_diff(actual_fee) / receipt.actual_fee; + + if diff >= 5 { + assert_eq!( + actual_fee, receipt.actual_fee, + "actual_fee mismatch differs from the baseline by more than 5% ({diff}%)", + ); + } + } + + assert_eq_sorted!( + vm_resources, + trace + .function_invocation + .as_ref() + .unwrap() + .execution_resources + ); + assert_eq!( + inner_calls.len(), + trace + .function_invocation + .as_ref() + .unwrap() + .internal_calls + .len() + ); +} diff --git a/rpc_state_reader_sn_api/tests/sir_tests.rs b/rpc_state_reader_sn_api/tests/sir_tests.rs new file mode 100644 index 000000000..84495160f --- /dev/null +++ b/rpc_state_reader_sn_api/tests/sir_tests.rs @@ -0,0 +1,283 @@ +use std::sync::Arc; + +use cairo_vm::felt::{felt_str, Felt252}; +use pretty_assertions_sorted::{assert_eq, assert_eq_sorted}; +use starknet_api::{ + block::BlockNumber, + core::{ClassHash as SNClassHash, ContractAddress, PatriciaKey}, + hash::{StarkFelt, StarkHash}, + stark_felt, + state::StorageKey, + transaction::{Transaction as SNTransaction, TransactionHash}, +}; +use starknet_in_rust::{ + core::errors::state_errors::StateError, + definitions::{ + block_context::{BlockContext, StarknetChainId, StarknetOsConfig}, + constants::{ + DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS, DEFAULT_CONTRACT_STORAGE_COMMITMENT_TREE_HEIGHT, + DEFAULT_GLOBAL_STATE_COMMITMENT_TREE_HEIGHT, DEFAULT_INVOKE_TX_MAX_N_STEPS, + DEFAULT_VALIDATE_MAX_N_STEPS, + }, + }, + execution::{CallInfo, TransactionExecutionInfo}, + services::api::contract_classes::compiled_class::CompiledClass, + state::{ + cached_state::{CachedState, ContractClassCache}, + state_api::StateReader, + state_cache::StorageEntry, + BlockInfo, + }, + transaction::{InvokeFunction, Transaction}, + utils::{Address, ClassHash}, +}; + +use test_case::test_case; + +use rpc_state_reader_sn_api::rpc_state::*; + +pub struct RpcStateReader(RpcState); + +impl StateReader for RpcStateReader { + fn get_contract_class(&self, class_hash: &ClassHash) -> Result { + let hash = SNClassHash(StarkHash::new(*class_hash).unwrap()); + Ok(CompiledClass::from(self.0.get_contract_class(&hash))) + } + + fn get_class_hash_at(&self, contract_address: &Address) -> Result { + let address = ContractAddress( + PatriciaKey::try_from( + StarkHash::new(contract_address.clone().0.to_be_bytes()).unwrap(), + ) + .unwrap(), + ); + let mut bytes = [0u8; 32]; + bytes.copy_from_slice(self.0.get_class_hash_at(&address).0.bytes()); + Ok(bytes) + } + + fn get_nonce_at(&self, contract_address: &Address) -> Result { + let address = ContractAddress( + PatriciaKey::try_from( + StarkHash::new(contract_address.clone().0.to_be_bytes()).unwrap(), + ) + .unwrap(), + ); + let nonce = self.0.get_nonce_at(&address); + Ok(Felt252::from_bytes_be(nonce.bytes())) + } + fn get_storage_at(&self, storage_entry: &StorageEntry) -> Result { + let (contract_address, key) = storage_entry; + let address = ContractAddress( + PatriciaKey::try_from( + StarkHash::new(contract_address.clone().0.to_be_bytes()).unwrap(), + ) + .unwrap(), + ); + let key = StorageKey(PatriciaKey::try_from(StarkHash::new(*key).unwrap()).unwrap()); + let value = self.0.get_storage_at(&address, &key); + Ok(Felt252::from_bytes_be(value.bytes())) + } + fn get_compiled_class_hash(&self, class_hash: &ClassHash) -> Result<[u8; 32], StateError> { + let address = + ContractAddress(PatriciaKey::try_from(StarkHash::new(*class_hash).unwrap()).unwrap()); + let mut bytes = [0u8; 32]; + bytes.copy_from_slice(self.0.get_class_hash_at(&address).0.bytes()); + Ok(bytes) + } +} + +#[allow(unused)] +pub fn execute_tx( + tx_hash: &str, + network: RpcChain, + block_number: BlockNumber, +) -> ( + TransactionExecutionInfo, + TransactionTrace, + RpcTransactionReceipt, +) { + let fee_token_address = Address(felt_str!( + "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + 16 + )); + + let tx_hash = tx_hash.strip_prefix("0x").unwrap(); + + // Instantiate the RPC StateReader and the CachedState + let rpc_reader = RpcStateReader(RpcState::new_infura(network, block_number.into())); + let gas_price = rpc_reader.0.get_gas_price(block_number.0).unwrap(); + + // Get values for block context before giving ownership of the reader + let chain_id = match rpc_reader.0.chain { + RpcChain::MainNet => StarknetChainId::MainNet, + RpcChain::TestNet => StarknetChainId::TestNet, + RpcChain::TestNet2 => StarknetChainId::TestNet2, + }; + let starknet_os_config = + StarknetOsConfig::new(chain_id.to_felt(), fee_token_address, gas_price); + let block_info = { + let RpcBlockInfo { + block_number, + block_timestamp, + sequencer_address, + .. + } = rpc_reader.0.get_block_info(); + + let block_number = block_number.0; + let block_timestamp = block_timestamp.0; + let sequencer_address = Address(Felt252::from_bytes_be(sequencer_address.0.key().bytes())); + + BlockInfo { + block_number, + block_timestamp, + gas_price, + sequencer_address, + } + }; + + // Get transaction before giving ownership of the reader + let tx_hash = TransactionHash(stark_felt!(tx_hash)); + let tx = match rpc_reader.0.get_transaction(&tx_hash) { + SNTransaction::Invoke(tx) => Transaction::InvokeFunction( + InvokeFunction::from_invoke_transaction(tx, chain_id).unwrap(), + ), + _ => unimplemented!(), + }; + + let trace = rpc_reader.0.get_transaction_trace(&tx_hash); + let receipt = rpc_reader.0.get_transaction_receipt(&tx_hash); + + let class_cache = ContractClassCache::default(); + let mut state = CachedState::new(Arc::new(rpc_reader), class_cache); + + let block_context = BlockContext::new( + starknet_os_config, + DEFAULT_CONTRACT_STORAGE_COMMITMENT_TREE_HEIGHT, + DEFAULT_GLOBAL_STATE_COMMITMENT_TREE_HEIGHT, + DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS.clone(), + DEFAULT_INVOKE_TX_MAX_N_STEPS, + DEFAULT_VALIDATE_MAX_N_STEPS, + block_info, + Default::default(), + true, + ); + + ( + tx.execute(&mut state, &block_context, u128::MAX).unwrap(), + trace, + receipt, + ) +} + +#[test] +fn test_get_transaction_try_from() { + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); + let str_hash = stark_felt!("0x5d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91"); + let tx_hash = TransactionHash(str_hash); + + let sn_tx = rpc_state.get_transaction(&tx_hash); + match &sn_tx { + SNTransaction::Invoke(sn_tx) => { + let tx = + InvokeFunction::from_invoke_transaction(sn_tx.clone(), StarknetChainId::MainNet) + .unwrap(); + assert_eq!(tx.hash_value().to_be_bytes().as_slice(), str_hash.bytes()) + } + _ => unimplemented!(), + }; +} + +#[test] +fn test_get_gas_price() { + let block = BlockValue::Number(BlockNumber(169928)); + let rpc_state = RpcState::new_infura(RpcChain::MainNet, block); + + let price = rpc_state.get_gas_price(169928).unwrap(); + assert_eq!(price, 22804578690); +} + +#[test_case( + "0x05d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91", + 169928, // real block 169929 + RpcChain::MainNet + => ignore["gas mismatch"] + )] +#[test_case( + "0x0528ec457cf8757f3eefdf3f0728ed09feeecc50fd97b1e4c5da94e27e9aa1d6", + 169928, // real block 169929 + RpcChain::MainNet + => ignore["gas mismatch"] + )] +#[test_case( + "0x0737677385a30ec4cbf9f6d23e74479926975b74db3d55dc5e46f4f8efee41cf", + 169928, // real block 169929 + RpcChain::MainNet + => ignore["resource mismatch"] + )] +#[test_case( + "0x026c17728b9cd08a061b1f17f08034eb70df58c1a96421e73ee6738ad258a94c", + 169928, // real block 169929 + RpcChain::MainNet + => ignore["gas mismatch"] + )] +#[test_case( + // review later + "0x0743092843086fa6d7f4a296a226ee23766b8acf16728aef7195ce5414dc4d84", + 186548, // real block 186549 + RpcChain::MainNet + => ignore["resource mismatch"] + )] +#[test_case( + // fails in blockifier too + "0x00724fc4a84f489ed032ebccebfc9541eb8dc64b0e76b933ed6fc30cd6000bd1", + 186551, // real block 186552 + RpcChain::MainNet + => ignore["gas mismatch"] + )] +fn starknet_in_rust_test_case_tx(hash: &str, block_number: u64, chain: RpcChain) { + let (tx_info, trace, receipt) = execute_tx(hash, chain, BlockNumber(block_number)); + + let TransactionExecutionInfo { + call_info, + actual_fee, + .. + } = tx_info; + + let CallInfo { + execution_resources, + internal_calls, + .. + } = call_info.unwrap(); + + assert_eq_sorted!( + execution_resources, + trace + .function_invocation + .as_ref() + .unwrap() + .execution_resources, + "execution resources mismatch" + ); + assert_eq!( + internal_calls.len(), + trace + .function_invocation + .as_ref() + .unwrap() + .internal_calls + .len(), + "internal calls length mismatch" + ); + + if receipt.actual_fee != actual_fee { + let diff = 100 * receipt.actual_fee.abs_diff(actual_fee) / receipt.actual_fee; + + if diff >= 5 { + assert_eq!( + actual_fee, receipt.actual_fee, + "actual_fee mismatch differs from the baseline by more than 5% ({diff}%)", + ); + } + } +} From 87785e2ecd67cf5bf360af160727f0b234995ed0 Mon Sep 17 00:00:00 2001 From: fmoletta <99273364+fmoletta@users.noreply.github.com> Date: Wed, 6 Sep 2023 22:21:28 +0300 Subject: [PATCH 24/44] Fix storage changes count for transactions with fee transfers (#1015) * Push clean changes * fmt * Fix test * Fix test * Fix test * Fix test * Fix tests * Fix tests * Fix tests --- src/definitions/constants.rs | 7 ------ src/lib.rs | 6 ++--- src/state/cached_state.rs | 45 ++++++++++++++++------------------- src/testing/state.rs | 4 ++-- src/transaction/declare.rs | 2 +- src/transaction/l1_handler.rs | 2 +- src/utils.rs | 3 +-- tests/deploy_account.rs | 4 ++-- tests/internals.rs | 27 ++++++++++----------- 9 files changed, 44 insertions(+), 56 deletions(-) diff --git a/src/definitions/constants.rs b/src/definitions/constants.rs index cbf706d01..77bf941c9 100644 --- a/src/definitions/constants.rs +++ b/src/definitions/constants.rs @@ -14,13 +14,6 @@ pub(crate) const N_DEFAULT_TOPICS: usize = 1; // Events have one default topic. pub(crate) const CONSUMED_MSG_TO_L2_ENCODED_DATA_SIZE: usize = (L1_TO_L2_MSG_HEADER_SIZE + 1) - CONSUMED_MSG_TO_L2_N_TOPICS; -/// Sender and sequencer balance updates. -pub(crate) const FEE_TRANSFER_N_STORAGE_CHANGES: usize = 2; - -/// Exclude the sequencer balance update, since it's charged once throught the batch. -pub(crate) const FEE_TRANSFER_N_STORAGE_CHANGES_TO_CHARGE: usize = - FEE_TRANSFER_N_STORAGE_CHANGES - 1; - lazy_static! { pub(crate) static ref QUERY_VERSION_BASE: Felt252 = felt_str!("340282366920938463463374607431768211456"); diff --git a/src/lib.rs b/src/lib.rs index 951dc2377..ef91e28c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -298,7 +298,7 @@ mod test { let transaction = Transaction::InvokeFunction(invoke_function); let estimated_fee = estimate_fee(&[transaction], state, &block_context).unwrap(); - assert_eq!(estimated_fee[0], (3707, 3672)); + assert_eq!(estimated_fee[0], (2483, 2448)); } #[test] @@ -392,7 +392,7 @@ mod test { block_context.starknet_os_config.gas_price = 1; let estimated_fee = estimate_message_fee(&l1_handler, state, &block_context).unwrap(); - assert_eq!(estimated_fee, (19709, 19695)); + assert_eq!(estimated_fee, (18485, 18471)); } #[test] @@ -1035,7 +1035,7 @@ mod test { assert_eq!( estimate_fee(&[deploy, invoke_tx], state, block_context,).unwrap(), - [(0, 3672), (0, 3672)] + [(0, 2448), (0, 2448)] ); } diff --git a/src/state/cached_state.rs b/src/state/cached_state.rs index 2f60eabd3..f54f156fb 100644 --- a/src/state/cached_state.rs +++ b/src/state/cached_state.rs @@ -253,32 +253,28 @@ impl State for CachedState { self.cache.storage_initial_values.clone(), ); - let n_modified_contracts = { - let storage_unique_updates = storage_updates.keys().map(|k| k.0.clone()); - - let class_hash_updates: Vec<_> = subtract_mappings( - self.cache.class_hash_writes.clone(), - self.cache.class_hash_initial_values.clone(), - ) - .keys() - .cloned() - .collect(); + let storage_unique_updates = storage_updates.keys().map(|k| k.0.clone()); - let nonce_updates: Vec<_> = subtract_mappings( - self.cache.nonce_writes.clone(), - self.cache.nonce_initial_values.clone(), - ) - .keys() - .cloned() - .collect(); + let class_hash_updates: Vec<_> = subtract_mappings( + self.cache.class_hash_writes.clone(), + self.cache.class_hash_initial_values.clone(), + ) + .keys() + .cloned() + .collect(); - let mut modified_contracts: HashSet
= HashSet::new(); - modified_contracts.extend(storage_unique_updates); - modified_contracts.extend(class_hash_updates); - modified_contracts.extend(nonce_updates); + let nonce_updates: Vec<_> = subtract_mappings( + self.cache.nonce_writes.clone(), + self.cache.nonce_initial_values.clone(), + ) + .keys() + .cloned() + .collect(); - modified_contracts.len() - }; + let mut modified_contracts: HashSet
= HashSet::new(); + modified_contracts.extend(storage_unique_updates); + modified_contracts.extend(class_hash_updates); + modified_contracts.extend(nonce_updates); // Add fee transfer storage update before actually charging it, as it needs to be included in the // calculation of the final fee. @@ -288,9 +284,10 @@ impl State for CachedState { (fee_token_address.clone(), sender_low_key), Felt252::default(), ); + modified_contracts.remove(fee_token_address); } - Ok((n_modified_contracts, storage_updates.len())) + Ok((modified_contracts.len(), storage_updates.len())) } /// Returns the class hash for a given contract address. diff --git a/src/testing/state.rs b/src/testing/state.rs index 58aba5d6f..82ea3a199 100644 --- a/src/testing/state.rs +++ b/src/testing/state.rs @@ -361,7 +361,7 @@ mod tests { .unwrap(); let mut actual_resources = HashMap::new(); - actual_resources.insert("l1_gas_usage".to_string(), 3672); + actual_resources.insert("l1_gas_usage".to_string(), 2448); actual_resources.insert("n_steps".to_string(), 0); let transaction_exec_info = TransactionExecutionInfo { @@ -584,7 +584,7 @@ mod tests { .unwrap(); let actual_resources = HashMap::from([ ("n_steps".to_string(), 3457), - ("l1_gas_usage".to_string(), 3672), + ("l1_gas_usage".to_string(), 2448), ("range_check_builtin".to_string(), 80), ("pedersen_builtin".to_string(), 16), ]); diff --git a/src/transaction/declare.rs b/src/transaction/declare.rs index 034132e63..1cf0ea5cc 100644 --- a/src/transaction/declare.rs +++ b/src/transaction/declare.rs @@ -438,7 +438,7 @@ mod tests { let actual_resources = HashMap::from([ ("n_steps".to_string(), 2715), - ("l1_gas_usage".to_string(), 2448), + ("l1_gas_usage".to_string(), 1224), ("range_check_builtin".to_string(), 63), ("pedersen_builtin".to_string(), 15), ]); diff --git a/src/transaction/l1_handler.rs b/src/transaction/l1_handler.rs index d08d8ccf5..bf52864de 100644 --- a/src/transaction/l1_handler.rs +++ b/src/transaction/l1_handler.rs @@ -339,7 +339,7 @@ mod test { ("n_steps".to_string(), 1319), ("pedersen_builtin".to_string(), 13), ("range_check_builtin".to_string(), 23), - ("l1_gas_usage".to_string(), 19695), + ("l1_gas_usage".to_string(), 18471), ]), tx_type: Some(TransactionType::L1Handler), } diff --git a/src/utils.rs b/src/utils.rs index affc6a726..aabc929c4 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,5 +1,4 @@ use crate::core::errors::hash_errors::HashError; -use crate::definitions::constants::FEE_TRANSFER_N_STORAGE_CHANGES_TO_CHARGE; use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; use crate::state::state_api::State; use crate::{ @@ -188,7 +187,7 @@ pub fn calculate_tx_resources( let l1_gas_usage = calculate_tx_gas_usage( l2_to_l1_messages, n_modified_contracts, - n_storage_changes + FEE_TRANSFER_N_STORAGE_CHANGES_TO_CHARGE, + n_storage_changes, l1_handler_payload_size, n_deployments, ); diff --git a/tests/deploy_account.rs b/tests/deploy_account.rs index fd30b7c89..70af6ea6d 100644 --- a/tests/deploy_account.rs +++ b/tests/deploy_account.rs @@ -104,7 +104,7 @@ fn internal_deploy_account() { ("n_steps", 3612), ("pedersen_builtin", 23), ("range_check_builtin", 83), - ("l1_gas_usage", 4896) + ("l1_gas_usage", 3672) ] .into_iter() .map(|(k, v)| (k.to_string(), v)) @@ -264,7 +264,7 @@ fn internal_deploy_account_cairo1() { ("n_steps", n_steps), ("pedersen_builtin", 23), ("range_check_builtin", 87), - ("l1_gas_usage", 6120) + ("l1_gas_usage", 4896) ] .into_iter() .map(|(k, v)| (k.to_string(), v)) diff --git a/tests/internals.rs b/tests/internals.rs index d51fa39ea..141119680 100644 --- a/tests/internals.rs +++ b/tests/internals.rs @@ -704,13 +704,13 @@ fn expected_fib_fee_transfer_info(fee: u128) -> CallInfo { ], }], storage_read_values: vec![ - INITIAL_BALANCE.clone() - Felt252::from(2476), + INITIAL_BALANCE.clone() - Felt252::from(1252), Felt252::zero(), - INITIAL_BALANCE.clone() - Felt252::from(2476), + INITIAL_BALANCE.clone() - Felt252::from(1252), Felt252::zero(), - Felt252::from(2476), + Felt252::from(1252), Felt252::zero(), - Felt252::from(2476), + Felt252::from(1252), Felt252::zero(), ], accessed_storage_keys: HashSet::from([ @@ -937,7 +937,7 @@ fn test_declare_tx() { ("n_steps".to_string(), 2715), ("range_check_builtin".to_string(), 63), ("pedersen_builtin".to_string(), 15), - ("l1_gas_usage".to_string(), 3672), + ("l1_gas_usage".to_string(), 2448), ]); let fee = calculate_tx_fee(&resources, *GAS_PRICE, &block_context).unwrap(); @@ -1025,7 +1025,7 @@ fn test_declarev2_tx() { ("n_steps".to_string(), 2715), ("range_check_builtin".to_string(), 63), ("pedersen_builtin".to_string(), 15), - ("l1_gas_usage".to_string(), 2448), + ("l1_gas_usage".to_string(), 1224), ]); let fee = calculate_tx_fee(&resources, *GAS_PRICE, &block_context).unwrap(); @@ -1243,7 +1243,7 @@ fn expected_transaction_execution_info(block_context: &BlockContext) -> Transact let resources = HashMap::from([ ("n_steps".to_string(), 4135), ("pedersen_builtin".to_string(), 16), - ("l1_gas_usage".to_string(), 3672), + ("l1_gas_usage".to_string(), 2448), ("range_check_builtin".to_string(), 101), ]); let fee = calculate_tx_fee(&resources, *GAS_PRICE, block_context).unwrap(); @@ -1272,7 +1272,7 @@ fn expected_fib_transaction_execution_info( } let resources = HashMap::from([ ("n_steps".to_string(), n_steps), - ("l1_gas_usage".to_string(), 7344), + ("l1_gas_usage".to_string(), 4896), ("pedersen_builtin".to_string(), 16), ("range_check_builtin".to_string(), 104), ]); @@ -1455,7 +1455,7 @@ fn test_invoke_with_declarev2_tx() { fn test_deploy_account() { let (block_context, mut state) = create_account_tx_test_state().unwrap(); - let expected_fee = 6157; + let expected_fee = 3709; let deploy_account_tx = DeployAccount::new( felt_to_hash(&TEST_ACCOUNT_CONTRACT_CLASS_HASH), @@ -1525,12 +1525,12 @@ fn test_deploy_account() { ("n_steps".to_string(), 3625), ("range_check_builtin".to_string(), 83), ("pedersen_builtin".to_string(), 23), - ("l1_gas_usage".to_string(), 6120), + ("l1_gas_usage".to_string(), 3672), ]); let fee = calculate_tx_fee(&resources, *GAS_PRICE, &block_context).unwrap(); - assert_eq!(fee, 6157); + assert_eq!(fee, expected_fee); let expected_execution_info = TransactionExecutionInfo::new( expected_validate_call_info.into(), @@ -1564,11 +1564,10 @@ fn expected_deploy_account_states() -> ( CachedState, CachedState, ) { - let fee = Felt252::from(6157); + let fee = Felt252::from(3709); let mut state_before = CachedState::new( Arc::new(InMemoryStateReader::new( HashMap::from([ - (Address(0x101.into()), felt_to_hash(&0x111.into())), (Address(0x100.into()), felt_to_hash(&0x110.into())), (Address(0x1001.into()), felt_to_hash(&0x1010.into())), ]), @@ -1805,7 +1804,7 @@ fn test_state_for_declare_tx() { // ]) // ); - let fee = Felt252::from(3700); + let fee = Felt252::from(2476); // Check state.cache assert_eq!( From ecc714ecb3f75489d0fd8826bcbbec25ea215519 Mon Sep 17 00:00:00 2001 From: marioiordanov Date: Thu, 7 Sep 2023 21:58:26 +0300 Subject: [PATCH 25/44] fix estimate fee missing casmclasscache (#916) Co-authored-by: Juan Bono Co-authored-by: Mario Rugiero --- src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ef91e28c5..82b790ca6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -82,15 +82,12 @@ pub fn simulate_transaction( /// Estimate the fee associated with transaction pub fn estimate_fee( transactions: &[Transaction], - state: T, + mut cached_state: CachedState, block_context: &BlockContext, ) -> Result, TransactionError> where T: StateReader, { - // This is used as a copy of the original state, we can update this cached state freely. - let mut cached_state = CachedState::::new(Arc::new(state), HashMap::new()); - let mut result = Vec::with_capacity(transactions.len()); for transaction in transactions { // Check if the contract is deployed. From 6c47599ed36ff6717f8558eef9b9642dc059fd34 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Thu, 7 Sep 2023 18:45:46 -0300 Subject: [PATCH 26/44] fix: declare v0 requires max_fee=0, consider for simulation (#1017) --- src/transaction/declare.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/transaction/declare.rs b/src/transaction/declare.rs index 1cf0ea5cc..7d8114b50 100644 --- a/src/transaction/declare.rs +++ b/src/transaction/declare.rs @@ -307,7 +307,8 @@ impl Declare { skip_validate, skip_execute, skip_fee_transfer, - max_fee: if ignore_max_fee { + // Keep the max_fee value for V0 for validation + max_fee: if ignore_max_fee && !self.version.is_zero() { u128::MAX } else { self.max_fee From 4a16bcb41c4dee8786298533b1a113b2538045e5 Mon Sep 17 00:00:00 2001 From: MrAzteca Date: Fri, 8 Sep 2023 20:23:55 +0200 Subject: [PATCH 27/44] Remove redundant `tx_type` field from transactions. (#1019) Co-authored-by: Esteve Soler Arderiu --- src/lib.rs | 2 -- src/transaction/declare.rs | 5 +---- src/transaction/declare_v2.rs | 6 ++---- src/transaction/deploy.rs | 11 ++++------- tests/internals.rs | 3 --- 5 files changed, 7 insertions(+), 20 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 82b790ca6..79e01117e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -216,7 +216,6 @@ mod test { EXECUTE_ENTRY_POINT_SELECTOR, VALIDATE_DECLARE_ENTRY_POINT_SELECTOR, VALIDATE_ENTRY_POINT_SELECTOR, }, - transaction_type::TransactionType, }; use crate::estimate_fee; use crate::estimate_message_fee; @@ -870,7 +869,6 @@ mod test { DeclareV2 { sender_address: TEST_ACCOUNT_CONTRACT_ADDRESS.clone(), - tx_type: TransactionType::Declare, validate_entry_point_selector: VALIDATE_DECLARE_ENTRY_POINT_SELECTOR.clone(), version: 1.into(), max_fee: INITIAL_GAS_COST, diff --git a/src/transaction/declare.rs b/src/transaction/declare.rs index 7d8114b50..f79005bab 100644 --- a/src/transaction/declare.rs +++ b/src/transaction/declare.rs @@ -39,7 +39,6 @@ use std::sync::Arc; pub struct Declare { pub class_hash: ClassHash, pub sender_address: Address, - pub tx_type: TransactionType, pub validate_entry_point_selector: Felt252, pub version: Felt252, pub max_fee: u128, @@ -83,7 +82,6 @@ impl Declare { let internal_declare = Declare { class_hash, sender_address, - tx_type: TransactionType::Declare, validate_entry_point_selector, version, max_fee, @@ -124,7 +122,6 @@ impl Declare { let internal_declare = Declare { class_hash, sender_address, - tx_type: TransactionType::Declare, validate_entry_point_selector, version, max_fee, @@ -187,7 +184,7 @@ impl Declare { None, None, actual_resources, - Some(self.tx_type), + Some(TransactionType::Declare), )) } diff --git a/src/transaction/declare_v2.rs b/src/transaction/declare_v2.rs index a9431326f..bad0d4ac8 100644 --- a/src/transaction/declare_v2.rs +++ b/src/transaction/declare_v2.rs @@ -35,7 +35,6 @@ use std::sync::Arc; #[derive(Debug, Clone)] pub struct DeclareV2 { pub sender_address: Address, - pub tx_type: TransactionType, pub validate_entry_point_selector: Felt252, pub version: Felt252, pub max_fee: u128, @@ -135,7 +134,6 @@ impl DeclareV2 { sierra_contract_class: sierra_contract_class.to_owned(), sierra_class_hash, sender_address, - tx_type: TransactionType::Declare, validate_entry_point_selector, version, max_fee, @@ -327,7 +325,7 @@ impl DeclareV2 { let actual_resources = calculate_tx_resources( resources_manager, &[execution_result.call_info.clone()], - self.tx_type, + TransactionType::Declare, storage_changes, None, execution_result.n_reverted_steps, @@ -350,7 +348,7 @@ impl DeclareV2 { None, None, actual_resources, - Some(self.tx_type), + Some(TransactionType::Declare), ); tx_exec_info.set_fee_info(actual_fee, fee_transfer_info); diff --git a/src/transaction/deploy.rs b/src/transaction/deploy.rs index f0b9b320a..3a2474319 100644 --- a/src/transaction/deploy.rs +++ b/src/transaction/deploy.rs @@ -43,7 +43,6 @@ pub struct Deploy { pub contract_hash: ClassHash, pub contract_class: CompiledClass, pub constructor_calldata: Vec, - pub tx_type: TransactionType, pub skip_validate: bool, pub skip_execute: bool, pub skip_fee_transfer: bool, @@ -84,7 +83,6 @@ impl Deploy { contract_hash, contract_class: CompiledClass::Deprecated(Arc::new(contract_class)), constructor_calldata, - tx_type: TransactionType::Deploy, skip_validate: false, skip_execute: false, skip_fee_transfer: false, @@ -117,7 +115,6 @@ impl Deploy { contract_hash, constructor_calldata, contract_class: CompiledClass::Deprecated(Arc::new(contract_class)), - tx_type: TransactionType::Deploy, skip_validate: false, skip_execute: false, skip_fee_transfer: false, @@ -186,7 +183,7 @@ impl Deploy { let actual_resources = calculate_tx_resources( resources_manager, &[Some(call_info.clone())], - self.tx_type, + TransactionType::Deploy, changes, None, 0, @@ -197,7 +194,7 @@ impl Deploy { Some(call_info), None, actual_resources, - Some(self.tx_type), + Some(TransactionType::Deploy), )) } @@ -249,7 +246,7 @@ impl Deploy { let actual_resources = calculate_tx_resources( resources_manager, &[call_info.clone()], - self.tx_type, + TransactionType::Deploy, changes, None, n_reverted_steps, @@ -260,7 +257,7 @@ impl Deploy { call_info, revert_error, actual_resources, - Some(self.tx_type), + Some(TransactionType::Deploy), )) } diff --git a/tests/internals.rs b/tests/internals.rs index 141119680..3c0ff2d8c 100644 --- a/tests/internals.rs +++ b/tests/internals.rs @@ -739,7 +739,6 @@ fn declare_tx() -> Declare { contract_class: ContractClass::from_path(TEST_EMPTY_CONTRACT_PATH).unwrap(), class_hash: felt_to_hash(&TEST_EMPTY_CONTRACT_CLASS_HASH), sender_address: TEST_ACCOUNT_CONTRACT_ADDRESS.clone(), - tx_type: TransactionType::Declare, validate_entry_point_selector: VALIDATE_DECLARE_ENTRY_POINT_SELECTOR.clone(), version: 1.into(), max_fee: 100000, @@ -765,7 +764,6 @@ fn declarev2_tx() -> DeclareV2 { DeclareV2 { sender_address: TEST_ACCOUNT_CONTRACT_ADDRESS.clone(), - tx_type: TransactionType::Declare, validate_entry_point_selector: VALIDATE_DECLARE_ENTRY_POINT_SELECTOR.clone(), version: 1.into(), max_fee: 50000000, @@ -808,7 +806,6 @@ fn deploy_fib_syscall() -> Deploy { contract_hash, contract_class, constructor_calldata: Vec::new(), - tx_type: TransactionType::Deploy, skip_execute: false, skip_fee_transfer: false, skip_validate: false, From 680798f44e16a97bb38719eeb958327b49a310c8 Mon Sep 17 00:00:00 2001 From: Juan Bono Date: Fri, 8 Sep 2023 16:47:45 -0300 Subject: [PATCH 28/44] remove files and rename the new one (#1020) --- Cargo.lock | 17 - Cargo.toml | 2 +- rpc_state_reader/Cargo.toml | 13 +- rpc_state_reader/src/lib.rs | 976 +++--------------- .../src/rpc_state.rs | 0 .../src/utils.rs | 0 .../test-responses/.gitkeep | 0 .../tests/blockifier_tests.rs | 4 +- .../tests/sir_tests.rs | 2 +- rpc_state_reader_sn_api/Cargo.toml | 29 - rpc_state_reader_sn_api/src/lib.rs | 280 ----- 11 files changed, 176 insertions(+), 1147 deletions(-) rename {rpc_state_reader_sn_api => rpc_state_reader}/src/rpc_state.rs (100%) rename {rpc_state_reader_sn_api => rpc_state_reader}/src/utils.rs (100%) rename {rpc_state_reader_sn_api => rpc_state_reader}/test-responses/.gitkeep (100%) rename {rpc_state_reader_sn_api => rpc_state_reader}/tests/blockifier_tests.rs (99%) rename {rpc_state_reader_sn_api => rpc_state_reader}/tests/sir_tests.rs (99%) delete mode 100644 rpc_state_reader_sn_api/Cargo.toml delete mode 100644 rpc_state_reader_sn_api/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 923d2df25..38afa0d13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3160,23 +3160,6 @@ dependencies = [ [[package]] name = "rpc_state_reader" version = "0.3.1" -dependencies = [ - "cairo-lang-starknet", - "cairo-vm", - "dotenv", - "serde", - "serde_json", - "serde_with 3.3.0", - "starknet", - "starknet_api", - "starknet_in_rust", - "thiserror", - "ureq", -] - -[[package]] -name = "rpc_state_reader_sn_api" -version = "0.3.1" dependencies = [ "blockifier", "cairo-lang-starknet", diff --git a/Cargo.toml b/Cargo.toml index b4552d465..d092646f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ with_mimalloc = ["dep:mimalloc"] cairo_1_tests = [] [workspace] -members = ["cli", "fuzzer", "rpc_state_reader", "rpc_state_reader_sn_api"] +members = ["cli", "fuzzer", "rpc_state_reader"] [workspace.dependencies] cairo-vm = { version = "0.8.5", features = ["cairo-1-hints"] } diff --git a/rpc_state_reader/Cargo.toml b/rpc_state_reader/Cargo.toml index 2f85bfdbf..e539d89c5 100644 --- a/rpc_state_reader/Cargo.toml +++ b/rpc_state_reader/Cargo.toml @@ -6,17 +6,24 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -starknet_in_rust = { path = "../", version = "0.3.1" } ureq = { version = "2.7.1", features = ["json"] } -serde = { version = "1.0.152", features = ["derive"] } +serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = [ "arbitrary_precision", "raw_value", ] } -starknet_api = { workspace = true } +starknet_api = "0.4.1" cairo-lang-starknet = { workspace = true } +cairo-lang-utils = { workspace = true } starknet = { workspace = true } thiserror = { workspace = true } +flate2 = "1.0.25" serde_with = "3.0.0" dotenv = "0.15.0" cairo-vm = "0.8.5" +blockifier = "0.2.0-rc0" +starknet_in_rust = { path = "../", version = "0.3.1" } + +[dev-dependencies] +pretty_assertions_sorted = "1.2.3" +test-case = "3.1.0" diff --git a/rpc_state_reader/src/lib.rs b/rpc_state_reader/src/lib.rs index 647ab5fa9..2ae84fab1 100644 --- a/rpc_state_reader/src/lib.rs +++ b/rpc_state_reader/src/lib.rs @@ -1,637 +1,164 @@ -use core::fmt; -use dotenv::dotenv; -use serde::{Deserialize, Deserializer}; -use serde_json::json; -use serde_with::{serde_as, DeserializeAs}; -use starknet::core::types::ContractClass; -use starknet_in_rust::definitions::block_context::StarknetChainId; -use starknet_in_rust::{ - core::errors::state_errors::StateError, - execution::CallInfo, - felt::Felt252, - services::api::contract_classes::compiled_class::CompiledClass, - state::{state_api::StateReader, state_cache::StorageEntry}, - utils::{parse_felt_array, Address, ClassHash, CompiledClassHash}, -}; -use std::env; -use thiserror::Error; - -#[cfg(test)] -use ::{ - cairo_vm::felt::felt_str, - starknet_in_rust::{ - definitions::constants::EXECUTE_ENTRY_POINT_SELECTOR, - transaction::{InvokeFunction, Transaction}, - }, -}; - -/// Starknet chains supported in Infura. -#[derive(Debug, Clone, Copy)] -pub enum RpcChain { - MainNet, - TestNet, - TestNet2, -} - -impl From for StarknetChainId { - fn from(network: RpcChain) -> Self { - match network { - RpcChain::MainNet => StarknetChainId::MainNet, - RpcChain::TestNet => StarknetChainId::TestNet, - RpcChain::TestNet2 => StarknetChainId::TestNet2, - } - } -} - -impl fmt::Display for RpcChain { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - RpcChain::MainNet => write!(f, "starknet-mainnet"), - RpcChain::TestNet => write!(f, "starknet-goerli"), - RpcChain::TestNet2 => write!(f, "starknet-goerli2"), - } - } -} - -/// A [StateReader] that holds all the data in memory. -/// -/// This implementation is uses HTTP requests to call the RPC endpoint, -/// using Infura. -/// In order to use it an Infura API key is necessary. -pub struct RpcState { - /// Enum with one of the supported Infura chains/ - chain: RpcChain, - /// Infura API key. - api_key: String, - /// Struct that holds information on the block where we are going to use to read the state. - block: BlockValue, -} - -#[derive(Debug, Error)] -enum RpcError { - #[error("RPC call failed with error: {0}")] - RpcCall(String), - #[error("Request failed with error: {0}")] - Request(String), - #[error("Failed to cast from: {0} to: {1} with error: {2}")] - Cast(String, String, String), -} - -/// [`BlockValue`] is an Enum that represent which block we are going to use to retrieve information. -#[allow(dead_code)] -pub enum BlockValue { - /// String one of: ["latest", "pending"] - Tag(serde_json::Value), - /// Integer - Number(serde_json::Value), - /// String with format: 0x{felt252} - Hash(serde_json::Value), -} - -impl BlockValue { - fn to_value(&self) -> serde_json::Value { - match self { - BlockValue::Tag(block_tag) => block_tag.clone(), - BlockValue::Number(block_number) => json!({ "block_number": block_number }), - BlockValue::Hash(block_hash) => json!({ "block_hash": block_hash }), - } - } -} - -#[derive(Debug, Deserialize)] -struct RpcResponseProgram { - result: ContractClass, -} - -// We use this new struct to cast the string that contains a [`Felt252`] in hex to a [`Felt252`] -struct FeltHex; - -impl<'de> DeserializeAs<'de, Felt252> for FeltHex { - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let value = String::deserialize(deserializer)?; - match value.starts_with("0x") { - true => Ok(Felt252::parse_bytes(value[2..].as_bytes(), 16).unwrap()), - false => Ok(Felt252::parse_bytes(value.as_bytes(), 16).unwrap()), - } - } -} - -#[serde_as] -#[derive(Debug, Deserialize)] -struct RpcResponseFelt252 { - #[serde_as(as = "FeltHex")] - result: Felt252, -} - -impl RpcState { - pub fn new(chain: RpcChain, block: BlockValue) -> Self { - if env::var("INFURA_API_KEY").is_err() { - dotenv().expect("Missing .env file"); - } - Self { - chain, - api_key: env::var("INFURA_API_KEY") - .expect("Missing API Key in environment: INFURA_API_KEY"), - block, - } - } - - fn rpc_call Deserialize<'a>>( - &self, - params: &serde_json::Value, - ) -> Result { - let response = ureq::post(&format!( - "https://{}.infura.io/v3/{}", - self.chain, self.api_key - )) - .set("Content-Type", "application/json") - .set("accept", "application/json") - .send_json(params) - .map_err(|err| RpcError::Request(err.to_string()))? - .into_string() - .map_err(|err| { - RpcError::Cast("Response".to_owned(), "String".to_owned(), err.to_string()) - })?; - serde_json::from_str(&response).map_err(|err| RpcError::RpcCall(err.to_string())) - } -} - -#[derive(Debug, Clone)] -pub struct TransactionTrace { - pub validate_invocation: CallInfo, - pub function_invocation: CallInfo, - pub fee_transfer_invocation: CallInfo, - pub signature: Vec, -} - -impl<'de> Deserialize<'de> for TransactionTrace { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let value: serde_json::Value = Deserialize::deserialize(deserializer)?; - - let validate_invocation = value["validate_invocation"].clone(); - let function_invocation = value["function_invocation"].clone(); - let fee_transfer_invocation = value["fee_transfer_invocation"].clone(); - let signature_value = value["signature"].clone(); - let signature = parse_felt_array(signature_value.as_array().unwrap()); - - Ok(TransactionTrace { - validate_invocation: serde_json::from_value(validate_invocation) - .map_err(serde::de::Error::custom)?, - function_invocation: serde_json::from_value(function_invocation) - .map_err(serde::de::Error::custom)?, - fee_transfer_invocation: serde_json::from_value(fee_transfer_invocation) - .map_err(serde::de::Error::custom)?, - signature, - }) - } -} - -#[cfg(test)] -impl RpcState { - /// Requests the transaction trace to the Feeder Gateway API. - /// It's useful for testing the transaction outputs like: - /// - execution resources - /// - actual fee - /// - events - /// - return data - pub fn get_transaction_trace(&self, hash: Felt252) -> TransactionTrace { - let chain_name = self.get_chain_name(); - let response = ureq::get(&format!( - "https://{}.starknet.io/feeder_gateway/get_transaction_trace", - chain_name - )) - .query("transactionHash", &format!("0x{}", hash.to_str_radix(16))) - .call() - .unwrap(); - - serde_json::from_str(&response.into_string().unwrap()).unwrap() - } - - /// Requests the given transaction to the Feeder Gateway API. - pub fn get_transaction(&self, hash: &str) -> Transaction { - let params = ureq::json!({ - "jsonrpc": "2.0", - "method": "starknet_getTransactionByHash", - "params": [format!("0x{}", hash)], - "id": 1 - }); - let response: serde_json::Value = self.rpc_call(¶ms).unwrap(); - - match response["result"]["type"].as_str().unwrap() { - "INVOKE" => { - let sender_address = Address(felt_str!( - response["result"]["sender_address"] - .as_str() - .unwrap() - .strip_prefix("0x") - .unwrap(), - 16 - )); - - let entry_point_selector = EXECUTE_ENTRY_POINT_SELECTOR.clone(); - let max_fee = u128::from_str_radix( - response["result"]["max_fee"] - .as_str() - .unwrap() - .strip_prefix("0x") - .unwrap(), - 16, - ) - .unwrap(); - let version = felt_str!( - response["result"]["version"] - .as_str() - .unwrap() - .strip_prefix("0x") - .unwrap(), - 16 - ); - let calldata = response["result"]["calldata"] - .as_array() - .unwrap() - .iter() - .map(|felt_as_value| { - felt_str!( - felt_as_value.as_str().unwrap().strip_prefix("0x").unwrap(), - 16 - ) - }) - .collect::>(); - let signature = response["result"]["signature"] - .as_array() - .unwrap() - .iter() - .map(|felt_as_value| { - felt_str!( - felt_as_value.as_str().unwrap().strip_prefix("0x").unwrap(), - 16 - ) - }) - .collect::>(); - let nonce = Some(felt_str!( - response["result"]["nonce"] - .as_str() - .unwrap() - .strip_prefix("0x") - .unwrap(), - 16 - )); - - let hash_felt = felt_str!(format!("{}", hash), 16); - let tx = InvokeFunction::new_with_tx_hash( - sender_address, - entry_point_selector, - max_fee, - version, - calldata, - signature, - nonce, - hash_felt, - ) - .unwrap(); - - // Note: we skip nonce checking because it can be increased twice in a single block - // and it leads to a buggy behaviour when that's the case because the get_nonce_at method - // returns a possibly higher nonce than the one we have in the transaction. - // Example: Block contains 2 transactions that execute the same entrypoint with nonce=20. - // - First tx has entrypoint with nonce=20 - // - Second tx has nonce=21 - // If we want to execute the first transaction the nonce check fails - // since get_nonce_at for that block returns 21 and the first tx has 20. - tx.create_for_simulation(false, false, false, false, true) - } - - _ => unimplemented!(), - } - } - - fn get_chain_name(&self) -> String { - match self.chain { - RpcChain::MainNet => "alpha-mainnet".to_string(), - RpcChain::TestNet => "alpha4".to_string(), - RpcChain::TestNet2 => "alpha4-2".to_string(), - } - } - - pub fn get_block_info( - &self, - starknet_os_config: starknet_in_rust::definitions::block_context::StarknetOsConfig, - ) -> starknet_in_rust::state::BlockInfo { - let get_block_info_params = ureq::json!({ - "jsonrpc": "2.0", - "method": "starknet_getBlockWithTxHashes", - "params": [self.block.to_value()], - "id": 1 - }); - - let block_info: serde_json::Value = self.rpc_call(&get_block_info_params).unwrap(); - - starknet_in_rust::state::BlockInfo { - block_number: block_info["result"]["block_number"] - .to_string() - .parse::() - .unwrap(), - block_timestamp: block_info["result"]["timestamp"] - .to_string() - .parse::() - .unwrap(), - gas_price: *starknet_os_config.gas_price(), - sequencer_address: starknet_os_config.fee_token_address().clone(), - } - } -} - -impl StateReader for RpcState { - fn get_contract_class(&self, class_hash: &ClassHash) -> Result { - let params = ureq::json!({ - "jsonrpc": "2.0", - "method": "starknet_getClass", - "params": [self.block.to_value(), format!("0x{}", Felt252::from_bytes_be(class_hash).to_str_radix(16))], - "id": 1 - }); - - let response: RpcResponseProgram = self - .rpc_call(¶ms) - .map_err(|err| StateError::CustomError(err.to_string()))?; - - Ok(CompiledClass::from(response.result)) - } - - fn get_class_hash_at(&self, contract_address: &Address) -> Result { - let params = ureq::json!({ - "jsonrpc": "2.0", - "method": "starknet_getClassHashAt", - "params": [self.block.to_value(), format!("0x{}", contract_address.0.to_str_radix(16))], - "id": 1 - }); - - let resp: RpcResponseFelt252 = self - .rpc_call(¶ms) - .map_err(|err| StateError::CustomError(err.to_string()))?; - - Ok(resp.result.to_be_bytes()) - } - - fn get_nonce_at(&self, contract_address: &Address) -> Result { - let params = ureq::json!({ - "jsonrpc": "2.0", - "method": "starknet_getNonce", - "params": [self.block.to_value(), format!("0x{}", contract_address.0.to_str_radix(16))], - "id": 1 - }); - - let resp: RpcResponseFelt252 = self - .rpc_call(¶ms) - .map_err(|err| StateError::CustomError(err.to_string()))?; - - Ok(resp.result) - } - - fn get_storage_at(&self, storage_entry: &StorageEntry) -> Result { - let params = ureq::json!({ - "jsonrpc": "2.0", - "method": "starknet_getStorageAt", - "params": [format!("0x{}", storage_entry.0 .0.to_str_radix(16)), format!( - "0x{}", - Felt252::from_bytes_be(&storage_entry.1).to_str_radix(16) - ), self.block.to_value()], - "id": 1 - }); - - let resp: RpcResponseFelt252 = self - .rpc_call(¶ms) - .map_err(|err| StateError::CustomError(err.to_string()))?; - - Ok(resp.result) - } - - fn get_compiled_class_hash( - &self, - _class_hash: &ClassHash, - ) -> Result { - todo!() - } -} +pub mod rpc_state; +pub mod utils; #[cfg(test)] mod tests { + use cairo_vm::vm::runners::cairo_runner::ExecutionResources; + use pretty_assertions_sorted::{assert_eq, assert_eq_sorted}; + use starknet_api::{ + class_hash, + core::{ClassHash, ContractAddress, PatriciaKey}, + hash::{StarkFelt, StarkHash}, + patricia_key, stark_felt, + state::StorageKey, + transaction::{Transaction as SNTransaction, TransactionHash}, + }; + use starknet_in_rust::{ + definitions::block_context::StarknetChainId, transaction::InvokeFunction, + }; use std::collections::HashMap; - use super::*; - use cairo_vm::vm::runners::cairo_runner::ExecutionResources; - use starknet_in_rust::felt::felt_str; + use crate::rpc_state::*; + + /// A utility macro to create a [`ContractAddress`] from a hex string / unsigned integer + /// representation. + /// Imported from starknet_api + macro_rules! contract_address { + ($s:expr) => { + ContractAddress(patricia_key!($s)) + }; + } #[test] fn test_get_contract_class_cairo1() { - let rpc_state = RpcState::new( - RpcChain::MainNet, - BlockValue::Tag(serde_json::to_value("latest").unwrap()), - ); + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); + + let class_hash = + class_hash!("0298e56befa6d1446b86ed5b900a9ba51fd2faa683cd6f50e8f833c0fb847216"); // This belongs to // https://starkscan.co/class/0x0298e56befa6d1446b86ed5b900a9ba51fd2faa683cd6f50e8f833c0fb847216 // which is cairo1.0 - let class_hash = felt_str!( - "0298e56befa6d1446b86ed5b900a9ba51fd2faa683cd6f50e8f833c0fb847216", - 16 - ); - rpc_state - .get_contract_class(&class_hash.to_be_bytes()) - .unwrap(); + rpc_state.get_contract_class(&class_hash); } #[test] fn test_get_contract_class_cairo0() { - let rpc_state = RpcState::new( - RpcChain::MainNet, - BlockValue::Tag(serde_json::to_value("latest").unwrap()), - ); + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); - let class_hash = felt_str!( - "025ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918", - 16 - ); - rpc_state - .get_contract_class(&class_hash.to_be_bytes()) - .unwrap(); + let class_hash = + class_hash!("025ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918"); + rpc_state.get_contract_class(&class_hash); } #[test] fn test_get_class_hash_at() { - let rpc_state = RpcState::new( - RpcChain::MainNet, - BlockValue::Tag(serde_json::to_value("latest").unwrap()), - ); - let address = Address(felt_str!( - "00b081f7ba1efc6fe98770b09a827ae373ef2baa6116b3d2a0bf5154136573a9", - 16 - )); + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); + let address = + contract_address!("00b081f7ba1efc6fe98770b09a827ae373ef2baa6116b3d2a0bf5154136573a9"); + assert_eq!( - rpc_state.get_class_hash_at(&address).unwrap(), - felt_str!( - "025ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918", - 16 - ) - .to_be_bytes() + rpc_state.get_class_hash_at(&address), + class_hash!("025ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918") ); } #[test] fn test_get_nonce_at() { - let rpc_state = RpcState::new( - RpcChain::TestNet, - BlockValue::Tag(serde_json::to_value("latest").unwrap()), - ); + let rpc_state = RpcState::new_infura(RpcChain::TestNet, BlockTag::Latest.into()); // Contract deployed by xqft which will not be used again, so nonce changes will not break // this test. - let address = Address(felt_str!( - "07185f2a350edcc7ea072888edb4507247de23e710cbd56084c356d265626bea", - 16 - )); - assert_eq!( - rpc_state.get_nonce_at(&address).unwrap(), - felt_str!("0", 16) - ); + let address = + contract_address!("07185f2a350edcc7ea072888edb4507247de23e710cbd56084c356d265626bea"); + assert_eq!(rpc_state.get_nonce_at(&address), stark_felt!("0x0")); } #[test] fn test_get_storage_at() { - let rpc_state = RpcState::new( - RpcChain::MainNet, - BlockValue::Tag(serde_json::to_value("latest").unwrap()), - ); - let storage_entry = ( - Address(felt_str!( - "00b081f7ba1efc6fe98770b09a827ae373ef2baa6116b3d2a0bf5154136573a9", - 16 - )), - [0; 32], - ); - assert_eq!( - rpc_state.get_storage_at(&storage_entry).unwrap(), - felt_str!("0", 16) - ); + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); + let address = + contract_address!("00b081f7ba1efc6fe98770b09a827ae373ef2baa6116b3d2a0bf5154136573a9"); + let key = StorageKey(patricia_key!(0u128)); + + assert_eq_sorted!(rpc_state.get_storage_at(&address, &key), stark_felt!("0x0")); } #[test] fn test_get_transaction() { - let rpc_state = RpcState::new( - RpcChain::MainNet, - BlockValue::Tag(serde_json::to_value("latest").unwrap()), - ); - let tx_hash = "06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955"; + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); + let tx_hash = TransactionHash(stark_felt!( + "06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955" + )); - rpc_state.get_transaction(tx_hash); + rpc_state.get_transaction(&tx_hash); } #[test] - fn test_get_block_info() { - let rpc_state = RpcState::new( - RpcChain::MainNet, - BlockValue::Number(serde_json::to_value(168204).unwrap()), - ); - - let gas_price_str = "13563643256"; - let gas_price_u128 = gas_price_str.parse::().unwrap(); - - let fee_token_address = Address(felt_str!( - "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - 16 + fn test_try_from_invoke() { + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); + let tx_hash = TransactionHash(stark_felt!( + "06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955" )); - let get_block_info_params = ureq::json!({ - "jsonrpc": "2.0", - "method": "starknet_getBlockWithTxHashes", - "params": [rpc_state.block.to_value()], - "id": 1 - }); - let network: StarknetChainId = rpc_state.chain.into(); - let starknet_os_config = - starknet_in_rust::definitions::block_context::StarknetOsConfig::new( - network.to_felt(), - fee_token_address.clone(), - gas_price_u128, - ); - let block_info: serde_json::Value = rpc_state.rpc_call(&get_block_info_params).unwrap(); + let tx = rpc_state.get_transaction(&tx_hash); + match tx { + SNTransaction::Invoke(tx) => { + InvokeFunction::from_invoke_transaction(tx, StarknetChainId::MainNet) + } + _ => unreachable!(), + } + .unwrap(); + } - let block_info = starknet_in_rust::state::BlockInfo { - block_number: block_info["result"]["block_number"] - .to_string() - .parse::() - .unwrap(), - block_timestamp: block_info["result"]["timestamp"] - .to_string() - .parse::() - .unwrap(), - gas_price: gas_price_u128, - sequencer_address: fee_token_address, - }; + #[test] + fn test_get_block_info() { + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); - assert_eq!(rpc_state.get_block_info(starknet_os_config,), block_info); + rpc_state.get_block_info(); } - /// Tested with the following query to the Feeder Gateway API: - /// https://alpha4-2.starknet.io/feeder_gateway/get_transaction_trace?transactionHash=0x019feb888a2d53ffddb7a1750264640afab8e9c23119e648b5259f1b5e7d51bc + // Tested with the following query to the Feeder Gateway API: + // https://alpha4-2.starknet.io/feeder_gateway/get_transaction_trace?transactionHash=0x019feb888a2d53ffddb7a1750264640afab8e9c23119e648b5259f1b5e7d51bc #[test] fn test_get_transaction_trace() { - let state_reader = RpcState::new( - RpcChain::TestNet2, - BlockValue::Number(serde_json::to_value(838683).unwrap()), - ); + let rpc_state = RpcState::new_infura(RpcChain::TestNet2, BlockTag::Latest.into()); - let tx_hash_str = "19feb888a2d53ffddb7a1750264640afab8e9c23119e648b5259f1b5e7d51bc"; - let tx_hash = felt_str!(format!("{}", tx_hash_str), 16); + let tx_hash = TransactionHash(stark_felt!( + "19feb888a2d53ffddb7a1750264640afab8e9c23119e648b5259f1b5e7d51bc" + )); - let tx_trace = state_reader.get_transaction_trace(tx_hash); + let tx_trace = rpc_state.get_transaction_trace(&tx_hash); assert_eq!( tx_trace.signature, vec![ - felt_str!( - "ffab1c47d8d5e5b76bdcc4af79e98205716c36b440f20244c69599a91ace58", - 16 - ), - felt_str!( - "6aa48a0906c9c1f7381c1a040c043b649eeac1eea08f24a9d07813f6b1d05fe", - 16 - ), + stark_felt!("ffab1c47d8d5e5b76bdcc4af79e98205716c36b440f20244c69599a91ace58"), + stark_felt!("6aa48a0906c9c1f7381c1a040c043b649eeac1eea08f24a9d07813f6b1d05fe"), ] ); assert_eq!( tx_trace.validate_invocation.calldata, - vec![ - felt_str!("1", 16), - felt_str!( - "690c876e61beda61e994543af68038edac4e1cb1990ab06e52a2d27e56a1232", - 16 - ), - felt_str!( - "1f24f689ced5802b706d7a2e28743fe45c7bfa37431c97b1c766e9622b65573", - 16 - ), - felt_str!("0", 16), - felt_str!("9", 16), - felt_str!("9", 16), - felt_str!("4", 16), - felt_str!("4254432d55534443", 16), - felt_str!("f02e7324ecbd65ce267", 16), - felt_str!("5754492d55534443", 16), - felt_str!("8e13050d06d8f514c", 16), - felt_str!("4554482d55534443", 16), - felt_str!("f0e4a142c3551c149d", 16), - felt_str!("4a50592d55534443", 16), - felt_str!("38bd34c31a0a5c", 16), - ] + Some(vec![ + stark_felt!("1"), + stark_felt!("690c876e61beda61e994543af68038edac4e1cb1990ab06e52a2d27e56a1232"), + stark_felt!("1f24f689ced5802b706d7a2e28743fe45c7bfa37431c97b1c766e9622b65573"), + stark_felt!("0"), + stark_felt!("9"), + stark_felt!("9"), + stark_felt!("4"), + stark_felt!("4254432d55534443"), + stark_felt!("f02e7324ecbd65ce267"), + stark_felt!("5754492d55534443"), + stark_felt!("8e13050d06d8f514c"), + stark_felt!("4554482d55534443"), + stark_felt!("f0e4a142c3551c149d"), + stark_felt!("4a50592d55534443"), + stark_felt!("38bd34c31a0a5c"), + ]) ); - assert_eq!(tx_trace.validate_invocation.retdata, vec![]); - assert_eq!( + assert_eq!(tx_trace.validate_invocation.retdata, Some(vec![])); + assert_eq_sorted!( tx_trace.validate_invocation.execution_resources, ExecutionResources { n_steps: 790, @@ -646,34 +173,35 @@ mod tests { assert_eq!(tx_trace.validate_invocation.internal_calls.len(), 1); assert_eq!( - tx_trace.function_invocation.calldata, - vec![ - felt_str!("1", 16), - felt_str!( - "690c876e61beda61e994543af68038edac4e1cb1990ab06e52a2d27e56a1232", - 16 - ), - felt_str!( - "1f24f689ced5802b706d7a2e28743fe45c7bfa37431c97b1c766e9622b65573", - 16 - ), - felt_str!("0", 16), - felt_str!("9", 16), - felt_str!("9", 16), - felt_str!("4", 16), - felt_str!("4254432d55534443", 16), - felt_str!("f02e7324ecbd65ce267", 16), - felt_str!("5754492d55534443", 16), - felt_str!("8e13050d06d8f514c", 16), - felt_str!("4554482d55534443", 16), - felt_str!("f0e4a142c3551c149d", 16), - felt_str!("4a50592d55534443", 16), - felt_str!("38bd34c31a0a5c", 16), - ] + tx_trace.function_invocation.as_ref().unwrap().calldata, + Some(vec![ + stark_felt!("1"), + stark_felt!("690c876e61beda61e994543af68038edac4e1cb1990ab06e52a2d27e56a1232"), + stark_felt!("1f24f689ced5802b706d7a2e28743fe45c7bfa37431c97b1c766e9622b65573"), + stark_felt!("0"), + stark_felt!("9"), + stark_felt!("9"), + stark_felt!("4"), + stark_felt!("4254432d55534443"), + stark_felt!("f02e7324ecbd65ce267"), + stark_felt!("5754492d55534443"), + stark_felt!("8e13050d06d8f514c"), + stark_felt!("4554482d55534443"), + stark_felt!("f0e4a142c3551c149d"), + stark_felt!("4a50592d55534443"), + stark_felt!("38bd34c31a0a5c"), + ]) ); - assert_eq!(tx_trace.function_invocation.retdata, vec![0.into()]); assert_eq!( - tx_trace.function_invocation.execution_resources, + tx_trace.function_invocation.as_ref().unwrap().retdata, + Some(vec![0u128.into()]) + ); + assert_eq_sorted!( + tx_trace + .function_invocation + .as_ref() + .unwrap() + .execution_resources, ExecutionResources { n_steps: 2808, n_memory_holes: 136, @@ -683,15 +211,32 @@ mod tests { ]), } ); - assert_eq!(tx_trace.function_invocation.internal_calls.len(), 1); assert_eq!( - tx_trace.function_invocation.internal_calls[0] + tx_trace + .function_invocation + .as_ref() + .unwrap() .internal_calls .len(), 1 ); assert_eq!( - tx_trace.function_invocation.internal_calls[0].internal_calls[0] + tx_trace + .function_invocation + .as_ref() + .unwrap() + .internal_calls[0] + .internal_calls + .len(), + 1 + ); + assert_eq!( + tx_trace + .function_invocation + .as_ref() + .unwrap() + .internal_calls[0] + .internal_calls[0] .internal_calls .len(), 7 @@ -699,17 +244,17 @@ mod tests { assert_eq!( tx_trace.fee_transfer_invocation.calldata, - vec![ - felt_str!( - "1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", - 16 - ), - felt_str!("2b0322a23ba4", 16), - felt_str!("0", 16), - ] + Some(vec![ + stark_felt!("1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8"), + stark_felt!("2b0322a23ba4"), + stark_felt!("0"), + ]) ); - assert_eq!(tx_trace.fee_transfer_invocation.retdata, vec![1.into()]); assert_eq!( + tx_trace.fee_transfer_invocation.retdata, + Some(vec![1u128.into()]) + ); + assert_eq_sorted!( tx_trace.fee_transfer_invocation.execution_resources, ExecutionResources { n_steps: 586, @@ -722,211 +267,14 @@ mod tests { ); assert_eq!(tx_trace.fee_transfer_invocation.internal_calls.len(), 1); } -} - -#[cfg(test)] -mod transaction_tests { - use super::*; - use starknet_in_rust::{ - definitions::{ - block_context::{BlockContext, StarknetChainId, StarknetOsConfig}, - constants::{ - DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS, - DEFAULT_CONTRACT_STORAGE_COMMITMENT_TREE_HEIGHT, - DEFAULT_GLOBAL_STATE_COMMITMENT_TREE_HEIGHT, DEFAULT_INVOKE_TX_MAX_N_STEPS, - DEFAULT_VALIDATE_MAX_N_STEPS, - }, - }, - execution::TransactionExecutionInfo, - felt::felt_str, - state::cached_state::CachedState, - }; - use std::{collections::HashMap, sync::Arc}; - - fn test_tx( - tx_hash: &str, - network: RpcChain, - block_number: u64, - gas_price: u128, - ) -> TransactionExecutionInfo { - let tx_hash = tx_hash.strip_prefix("0x").unwrap(); - - // Instantiate the RPC StateReader and the CachedState - let block = BlockValue::Number(serde_json::to_value(block_number).unwrap()); - let rpc_state = Arc::new(RpcState::new(network, block)); - let mut state = CachedState::new(rpc_state.clone(), HashMap::new()); - - let fee_token_address = Address(felt_str!( - "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - 16 - )); - - let network: StarknetChainId = rpc_state.chain.into(); - let starknet_os_config = - StarknetOsConfig::new(network.to_felt(), fee_token_address, gas_price); - - let block_info = rpc_state.get_block_info(starknet_os_config.clone()); - - let block_context = BlockContext::new( - starknet_os_config, - DEFAULT_CONTRACT_STORAGE_COMMITMENT_TREE_HEIGHT, - DEFAULT_GLOBAL_STATE_COMMITMENT_TREE_HEIGHT, - DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS.clone(), - DEFAULT_INVOKE_TX_MAX_N_STEPS, - DEFAULT_VALIDATE_MAX_N_STEPS, - block_info, - Default::default(), - true, - ); - - let tx = rpc_state.get_transaction(tx_hash); - - tx.execute(&mut state, &block_context, 0).unwrap() - } - - /// - Transaction Hash: `0x014640564509873cf9d24a311e1207040c8b60efd38d96caef79855f0b0075d5` - /// - Network: `mainnet` - /// - Type: `Invoke` - /// - Contract: StarkGate `0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7` - /// - Entrypoint: `transfer(recipient, amount)` - /// - Fee discrepancy: test=83714806176032, explorer=67749104314311, diff=15965701861721 (23%) - /// - Link to Explorer: https://starkscan.co/tx/0x014640564509873cf9d24a311e1207040c8b60efd38d96caef79855f0b0075d5 - #[test] - fn test_invoke_0x014640564509873cf9d24a311e1207040c8b60efd38d96caef79855f0b0075d5() { - let result = test_tx( - "0x014640564509873cf9d24a311e1207040c8b60efd38d96caef79855f0b0075d5", - RpcChain::MainNet, - 90_006, - 13563643256, - ); - - dbg!(&result.actual_resources); - dbg!(&result.actual_fee); // test=83714806176032, explorer=67749104314311, diff=15965701861721 (23%) - dbg!(&result.call_info.clone().unwrap().execution_resources); // Ok with explorer - dbg!(&result.call_info.unwrap().internal_calls.len()); // Ok with explorer - } - - /// - Transaction Hash: `0x06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955` - /// - Network: `mainnet` - /// - Type: `Invoke` - /// - Contract: mySwap: `0x022b05f9396d2c48183f6deaf138a57522bcc8b35b67dee919f76403d1783136` and `0x010884171baf1914edc28d7afb619b40a4051cfae78a094a55d230f19e944a28` - /// - Entrypoint: 1 call to `approve(spender, amount)` and 1 call to `withdraw_liquidity(pool_id, shares_amount, amount_min_a, amount_min_b)` - /// - Fee discrepancy: test=267319013054160, explorer=219298652474858, diff=48020360579302 (22%) - /// - Link to Explorer: https://starkscan.co/tx/0x06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955 - #[test] - fn test_invoke_mainnet_0x06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955() { - let result = test_tx( - "0x06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955", - RpcChain::MainNet, - 90_002, - 13572248835, - ); - - dbg!(&result.actual_resources); - dbg!(&result.actual_fee); // test=267319013054160, explorer=219298652474858, diff=48020360579302 (22%) - dbg!(&result.call_info.clone().unwrap().execution_resources); // Ok with explorer - dbg!(&result.call_info.unwrap().internal_calls.len()); // distinct, explorer=7, test=1 - } - - /// - Transaction Hash: `0x074dab0828ec1b6cfde5188c41d41af1c198192a7d118217f95a802aa923dacf` - /// - Network: `testnet` - /// - Type: `Invoke` - /// - Contract: Fibonacci `0x012d37c39a385cf56801b57626e039147abce1183ce55e419e4296398b81d9e2` - /// - Entrypoint: `fib(first_element, second_element, n)` - /// - Fee discrepancy: test=7252831227950, explorer=7207614784695, diff=45216443255 (0.06%) - /// - Link to Explorer: https://testnet.starkscan.co/tx/0x074dab0828ec1b6cfde5188c41d41af1c198192a7d118217f95a802aa923dacf - #[test] - fn test_0x074dab0828ec1b6cfde5188c41d41af1c198192a7d118217f95a802aa923dacf() { - let result = test_tx( - "0x074dab0828ec1b6cfde5188c41d41af1c198192a7d118217f95a802aa923dacf", - RpcChain::TestNet, - 838683, - 2917470325, - ); - - dbg!(&result.actual_resources); - dbg!(&result.actual_fee); // test=7252831227950, explorer=7207614784695, diff=45216443255 (0.06%) - dbg!(&result.call_info.clone().unwrap().execution_resources); // Ok with explorer - dbg!(&result.call_info.unwrap().internal_calls.len()); // Ok with explorer - } - /// - Transaction Hash: 0x019feb888a2d53ffddb7a1750264640afab8e9c23119e648b5259f1b5e7d51bc - /// - Network: testnet-2 - /// - Type: Invoke - /// - Contract: 0x0690c876e61beda61e994543af68038edac4e1cb1990ab06e52a2d27e56a1232 - /// - Entrypoint: update_multiple_market_prices(market_prices_list_len, market_prices_list) - /// - Fee discrepancy: test=6361070805216, explorer=47292465953700, diff=5888146145679 (0.13%) - /// - Link to Explorer: https://testnet-2.starkscan.co/tx/0x019feb888a2d53ffddb7a1750264640afab8e9c23119e648b5259f1b5e7d51bc #[test] - fn test_invoke_testnet2_0x019feb888a2d53ffddb7a1750264640afab8e9c23119e648b5259f1b5e7d51bc() { - let result = test_tx( - "0x019feb888a2d53ffddb7a1750264640afab8e9c23119e648b5259f1b5e7d51bc", - RpcChain::TestNet2, - 123001, - 272679647, - ); - - dbg!(&result.actual_resources); - dbg!(&result.actual_fee); // test=6361070805216, explorer=47292465953700, diff=5888146145679 (0.13%) - dbg!(&result.call_info.clone().unwrap().execution_resources); // Ok with explorer - dbg!(&result.call_info.unwrap().internal_calls.len()); // Ok with explorer - } - - /// - Transaction Hash: 0x02e31c976f649ba05da82e4c6a054a9a41961adda4c3dea26e6b523f4f18b382 - /// - Network: testnet - /// - Type: Invoke - /// - Entrypoint: freeMint - /// - Fee discrepancy: test=4940000049400, explorer=6191000061910, diff=25% - /// - Link to explorer: https://testnet.starkscan.co/tx/0x02e31c976f649ba05da82e4c6a054a9a41961adda4c3dea26e6b523f4f18b382 - #[test] - fn test_0x02e31c976f649ba05da82e4c6a054a9a41961adda4c3dea26e6b523f4f18b382() { - let result = test_tx( - "0x02e31c976f649ba05da82e4c6a054a9a41961adda4c3dea26e6b523f4f18b382", - RpcChain::TestNet, - 846582, - 1000000010, - ); - - dbg!(&result.actual_resources); - dbg!(&result.actual_fee); // test=6361070805216, explorer=47292465953700, diff=5888146145679 (0.13%) - dbg!(&result.call_info.clone().unwrap().execution_resources); // Ok with explorer - dbg!(&result.call_info.unwrap().internal_calls.len()); // Ok with explorer - } - - /// - Transaction Hash: 0x26a1a5b5f2b3390302ade67c766cc94804fd41c86c5ee37e20c6415dc39358c - /// - Network: mainnet - /// - Type: Invoke - /// - Entrypoint: evolve(game_id) - /// - Fee discrepancy: test=263050867669716, explorer=306031925226186, diff=16% - /// - Link to explorer: https://starkscan.co/tx/0x026a1a5b5f2b3390302ade67c766cc94804fd41c86c5ee37e20c6415dc39358c - #[test] - fn test_0x26a1a5b5f2b3390302ade67c766cc94804fd41c86c5ee37e20c6415dc39358c() { - let result = test_tx( - "0x26a1a5b5f2b3390302ade67c766cc94804fd41c86c5ee37e20c6415dc39358c", - RpcChain::MainNet, - 155054, - 33977120598, - ); + fn test_get_transaction_receipt() { + let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); + let tx_hash = TransactionHash(stark_felt!( + "06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955" + )); - dbg!(&result.actual_resources); - dbg!(&result.actual_fee); // test=6361070805216, explorer=47292465953700, diff=5888146145679 (0.13%) - dbg!(&result.call_info.clone().unwrap().execution_resources); // Ok with explorer - dbg!(&result.call_info.unwrap().internal_calls.len()); // Ok with explorer + rpc_state.get_transaction_receipt(&tx_hash); } - - // Fails because there is a problem with get_compiled_class_hash - // #[test] - // fn test_0x00eef6ba6741da8769192fac9d28c6631cf66f9e7c4e880b886ef6a2e550e4e2() { - // let result = test_tx( - // "0x00eef6ba6741da8769192fac9d28c6631cf66f9e7c4e880b886ef6a2e550e4e2", - // RpcChain::MainNet, - // 156105, - // 18348936116, - // ); - - // dbg!(&result.actual_resources); - // dbg!(&result.actual_fee); - // dbg!(&result.call_info.clone().unwrap().execution_resources); - // dbg!(&result.call_info.unwrap().internal_calls.len()); - // } } diff --git a/rpc_state_reader_sn_api/src/rpc_state.rs b/rpc_state_reader/src/rpc_state.rs similarity index 100% rename from rpc_state_reader_sn_api/src/rpc_state.rs rename to rpc_state_reader/src/rpc_state.rs diff --git a/rpc_state_reader_sn_api/src/utils.rs b/rpc_state_reader/src/utils.rs similarity index 100% rename from rpc_state_reader_sn_api/src/utils.rs rename to rpc_state_reader/src/utils.rs diff --git a/rpc_state_reader_sn_api/test-responses/.gitkeep b/rpc_state_reader/test-responses/.gitkeep similarity index 100% rename from rpc_state_reader_sn_api/test-responses/.gitkeep rename to rpc_state_reader/test-responses/.gitkeep diff --git a/rpc_state_reader_sn_api/tests/blockifier_tests.rs b/rpc_state_reader/tests/blockifier_tests.rs similarity index 99% rename from rpc_state_reader_sn_api/tests/blockifier_tests.rs rename to rpc_state_reader/tests/blockifier_tests.rs index ee3ed029b..5f5ce7c35 100644 --- a/rpc_state_reader_sn_api/tests/blockifier_tests.rs +++ b/rpc_state_reader/tests/blockifier_tests.rs @@ -21,8 +21,8 @@ use cairo_lang_starknet::{ }; use cairo_vm::types::program::Program; use pretty_assertions_sorted::{assert_eq, assert_eq_sorted}; -use rpc_state_reader_sn_api::rpc_state::*; -use rpc_state_reader_sn_api::utils; +use rpc_state_reader::rpc_state::*; +use rpc_state_reader::utils; use starknet::core::types::ContractClass as SNContractClass; use starknet_api::{ block::BlockNumber, diff --git a/rpc_state_reader_sn_api/tests/sir_tests.rs b/rpc_state_reader/tests/sir_tests.rs similarity index 99% rename from rpc_state_reader_sn_api/tests/sir_tests.rs rename to rpc_state_reader/tests/sir_tests.rs index 84495160f..b86abc273 100644 --- a/rpc_state_reader_sn_api/tests/sir_tests.rs +++ b/rpc_state_reader/tests/sir_tests.rs @@ -34,7 +34,7 @@ use starknet_in_rust::{ use test_case::test_case; -use rpc_state_reader_sn_api::rpc_state::*; +use rpc_state_reader::rpc_state::*; pub struct RpcStateReader(RpcState); diff --git a/rpc_state_reader_sn_api/Cargo.toml b/rpc_state_reader_sn_api/Cargo.toml deleted file mode 100644 index 35be6617f..000000000 --- a/rpc_state_reader_sn_api/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "rpc_state_reader_sn_api" -version = "0.3.1" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -ureq = { version = "2.7.1", features = ["json"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = { version = "1.0", features = [ - "arbitrary_precision", - "raw_value", -] } -starknet_api = "0.4.1" -cairo-lang-starknet = { workspace = true } -cairo-lang-utils = { workspace = true } -starknet = { workspace = true } -thiserror = { workspace = true } -flate2 = "1.0.25" -serde_with = "3.0.0" -dotenv = "0.15.0" -cairo-vm = "0.8.5" -blockifier = "0.2.0-rc0" -starknet_in_rust = { path = "../", version = "0.3.1" } - -[dev-dependencies] -pretty_assertions_sorted = "1.2.3" -test-case = "3.1.0" diff --git a/rpc_state_reader_sn_api/src/lib.rs b/rpc_state_reader_sn_api/src/lib.rs deleted file mode 100644 index 2ae84fab1..000000000 --- a/rpc_state_reader_sn_api/src/lib.rs +++ /dev/null @@ -1,280 +0,0 @@ -pub mod rpc_state; -pub mod utils; - -#[cfg(test)] -mod tests { - use cairo_vm::vm::runners::cairo_runner::ExecutionResources; - use pretty_assertions_sorted::{assert_eq, assert_eq_sorted}; - use starknet_api::{ - class_hash, - core::{ClassHash, ContractAddress, PatriciaKey}, - hash::{StarkFelt, StarkHash}, - patricia_key, stark_felt, - state::StorageKey, - transaction::{Transaction as SNTransaction, TransactionHash}, - }; - use starknet_in_rust::{ - definitions::block_context::StarknetChainId, transaction::InvokeFunction, - }; - use std::collections::HashMap; - - use crate::rpc_state::*; - - /// A utility macro to create a [`ContractAddress`] from a hex string / unsigned integer - /// representation. - /// Imported from starknet_api - macro_rules! contract_address { - ($s:expr) => { - ContractAddress(patricia_key!($s)) - }; - } - - #[test] - fn test_get_contract_class_cairo1() { - let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); - - let class_hash = - class_hash!("0298e56befa6d1446b86ed5b900a9ba51fd2faa683cd6f50e8f833c0fb847216"); - // This belongs to - // https://starkscan.co/class/0x0298e56befa6d1446b86ed5b900a9ba51fd2faa683cd6f50e8f833c0fb847216 - // which is cairo1.0 - - rpc_state.get_contract_class(&class_hash); - } - - #[test] - fn test_get_contract_class_cairo0() { - let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); - - let class_hash = - class_hash!("025ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918"); - rpc_state.get_contract_class(&class_hash); - } - - #[test] - fn test_get_class_hash_at() { - let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); - let address = - contract_address!("00b081f7ba1efc6fe98770b09a827ae373ef2baa6116b3d2a0bf5154136573a9"); - - assert_eq!( - rpc_state.get_class_hash_at(&address), - class_hash!("025ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918") - ); - } - - #[test] - fn test_get_nonce_at() { - let rpc_state = RpcState::new_infura(RpcChain::TestNet, BlockTag::Latest.into()); - // Contract deployed by xqft which will not be used again, so nonce changes will not break - // this test. - let address = - contract_address!("07185f2a350edcc7ea072888edb4507247de23e710cbd56084c356d265626bea"); - assert_eq!(rpc_state.get_nonce_at(&address), stark_felt!("0x0")); - } - - #[test] - fn test_get_storage_at() { - let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); - let address = - contract_address!("00b081f7ba1efc6fe98770b09a827ae373ef2baa6116b3d2a0bf5154136573a9"); - let key = StorageKey(patricia_key!(0u128)); - - assert_eq_sorted!(rpc_state.get_storage_at(&address, &key), stark_felt!("0x0")); - } - - #[test] - fn test_get_transaction() { - let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); - let tx_hash = TransactionHash(stark_felt!( - "06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955" - )); - - rpc_state.get_transaction(&tx_hash); - } - - #[test] - fn test_try_from_invoke() { - let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); - let tx_hash = TransactionHash(stark_felt!( - "06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955" - )); - - let tx = rpc_state.get_transaction(&tx_hash); - match tx { - SNTransaction::Invoke(tx) => { - InvokeFunction::from_invoke_transaction(tx, StarknetChainId::MainNet) - } - _ => unreachable!(), - } - .unwrap(); - } - - #[test] - fn test_get_block_info() { - let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); - - rpc_state.get_block_info(); - } - - // Tested with the following query to the Feeder Gateway API: - // https://alpha4-2.starknet.io/feeder_gateway/get_transaction_trace?transactionHash=0x019feb888a2d53ffddb7a1750264640afab8e9c23119e648b5259f1b5e7d51bc - #[test] - fn test_get_transaction_trace() { - let rpc_state = RpcState::new_infura(RpcChain::TestNet2, BlockTag::Latest.into()); - - let tx_hash = TransactionHash(stark_felt!( - "19feb888a2d53ffddb7a1750264640afab8e9c23119e648b5259f1b5e7d51bc" - )); - - let tx_trace = rpc_state.get_transaction_trace(&tx_hash); - - assert_eq!( - tx_trace.signature, - vec![ - stark_felt!("ffab1c47d8d5e5b76bdcc4af79e98205716c36b440f20244c69599a91ace58"), - stark_felt!("6aa48a0906c9c1f7381c1a040c043b649eeac1eea08f24a9d07813f6b1d05fe"), - ] - ); - - assert_eq!( - tx_trace.validate_invocation.calldata, - Some(vec![ - stark_felt!("1"), - stark_felt!("690c876e61beda61e994543af68038edac4e1cb1990ab06e52a2d27e56a1232"), - stark_felt!("1f24f689ced5802b706d7a2e28743fe45c7bfa37431c97b1c766e9622b65573"), - stark_felt!("0"), - stark_felt!("9"), - stark_felt!("9"), - stark_felt!("4"), - stark_felt!("4254432d55534443"), - stark_felt!("f02e7324ecbd65ce267"), - stark_felt!("5754492d55534443"), - stark_felt!("8e13050d06d8f514c"), - stark_felt!("4554482d55534443"), - stark_felt!("f0e4a142c3551c149d"), - stark_felt!("4a50592d55534443"), - stark_felt!("38bd34c31a0a5c"), - ]) - ); - assert_eq!(tx_trace.validate_invocation.retdata, Some(vec![])); - assert_eq_sorted!( - tx_trace.validate_invocation.execution_resources, - ExecutionResources { - n_steps: 790, - n_memory_holes: 51, - builtin_instance_counter: HashMap::from([ - ("range_check_builtin".to_string(), 20), - ("ecdsa_builtin".to_string(), 1), - ("pedersen_builtin".to_string(), 2), - ]), - } - ); - assert_eq!(tx_trace.validate_invocation.internal_calls.len(), 1); - - assert_eq!( - tx_trace.function_invocation.as_ref().unwrap().calldata, - Some(vec![ - stark_felt!("1"), - stark_felt!("690c876e61beda61e994543af68038edac4e1cb1990ab06e52a2d27e56a1232"), - stark_felt!("1f24f689ced5802b706d7a2e28743fe45c7bfa37431c97b1c766e9622b65573"), - stark_felt!("0"), - stark_felt!("9"), - stark_felt!("9"), - stark_felt!("4"), - stark_felt!("4254432d55534443"), - stark_felt!("f02e7324ecbd65ce267"), - stark_felt!("5754492d55534443"), - stark_felt!("8e13050d06d8f514c"), - stark_felt!("4554482d55534443"), - stark_felt!("f0e4a142c3551c149d"), - stark_felt!("4a50592d55534443"), - stark_felt!("38bd34c31a0a5c"), - ]) - ); - assert_eq!( - tx_trace.function_invocation.as_ref().unwrap().retdata, - Some(vec![0u128.into()]) - ); - assert_eq_sorted!( - tx_trace - .function_invocation - .as_ref() - .unwrap() - .execution_resources, - ExecutionResources { - n_steps: 2808, - n_memory_holes: 136, - builtin_instance_counter: HashMap::from([ - ("range_check_builtin".to_string(), 49), - ("pedersen_builtin".to_string(), 14), - ]), - } - ); - assert_eq!( - tx_trace - .function_invocation - .as_ref() - .unwrap() - .internal_calls - .len(), - 1 - ); - assert_eq!( - tx_trace - .function_invocation - .as_ref() - .unwrap() - .internal_calls[0] - .internal_calls - .len(), - 1 - ); - assert_eq!( - tx_trace - .function_invocation - .as_ref() - .unwrap() - .internal_calls[0] - .internal_calls[0] - .internal_calls - .len(), - 7 - ); - - assert_eq!( - tx_trace.fee_transfer_invocation.calldata, - Some(vec![ - stark_felt!("1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8"), - stark_felt!("2b0322a23ba4"), - stark_felt!("0"), - ]) - ); - assert_eq!( - tx_trace.fee_transfer_invocation.retdata, - Some(vec![1u128.into()]) - ); - assert_eq_sorted!( - tx_trace.fee_transfer_invocation.execution_resources, - ExecutionResources { - n_steps: 586, - n_memory_holes: 42, - builtin_instance_counter: HashMap::from([ - ("range_check_builtin".to_string(), 21), - ("pedersen_builtin".to_string(), 4), - ]), - } - ); - assert_eq!(tx_trace.fee_transfer_invocation.internal_calls.len(), 1); - } - - #[test] - fn test_get_transaction_receipt() { - let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); - let tx_hash = TransactionHash(stark_felt!( - "06da92cfbdceac5e5e94a1f40772d6c79d34f011815606742658559ec77b6955" - )); - - rpc_state.get_transaction_receipt(&tx_hash); - } -} From c4310277e7c8aba8ba5abe7af424db48b3b0b181 Mon Sep 17 00:00:00 2001 From: Fanny Guthmann <57538139+fguthmann@users.noreply.github.com> Date: Sat, 9 Sep 2023 02:25:12 +0200 Subject: [PATCH 29/44] Add contract class cache stats (#958) * added cache_hit and cahce_misses to count the number of error in our cache, abd a test for it * wip * Apply suggestions from code review * fix: qnd borrow checker * clippy --------- Co-authored-by: fannyguthmann Co-authored-by: Mario Rugiero --- Cargo.toml | 1 + src/state/cached_state.rs | 124 ++++++++++++++++++++++++++++++++------ 2 files changed, 107 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d092646f8..3e97eeaf9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ license = "Apache-2.0" default = ["with_mimalloc"] with_mimalloc = ["dep:mimalloc"] cairo_1_tests = [] +metrics = [] [workspace] members = ["cli", "fuzzer", "rpc_state_reader"] diff --git a/src/state/cached_state.rs b/src/state/cached_state.rs index f54f156fb..d1a616953 100644 --- a/src/state/cached_state.rs +++ b/src/state/cached_state.rs @@ -31,6 +31,34 @@ pub struct CachedState { pub(crate) cache: StateCache, #[get = "pub"] pub(crate) contract_classes: ContractClassCache, + cache_hits: usize, + cache_misses: usize, +} + +#[cfg(feature = "metrics")] +impl CachedState { + #[inline(always)] + pub fn add_hit(&mut self) { + self.cache_hits += 1; + } + + #[inline(always)] + pub fn add_miss(&mut self) { + self.cache_misses += 1; + } +} + +#[cfg(not(feature = "metrics"))] +impl CachedState { + #[inline(always)] + pub fn add_hit(&mut self) { + // does nothing + } + + #[inline(always)] + pub fn add_miss(&mut self) { + // does nothing + } } impl CachedState { @@ -40,6 +68,8 @@ impl CachedState { cache: StateCache::default(), state_reader, contract_classes, + cache_hits: 0, + cache_misses: 0, } } @@ -53,6 +83,8 @@ impl CachedState { cache, contract_classes, state_reader, + cache_hits: 0, + cache_misses: 0, } } @@ -294,9 +326,13 @@ impl State for CachedState { /// Returns zero as default value if missing /// Adds the value to the cache's inital_values if not present fn get_class_hash_at(&mut self, contract_address: &Address) -> Result { - match self.cache.get_class_hash(contract_address) { - Some(class_hash) => Ok(*class_hash), + match self.cache.get_class_hash(contract_address).cloned() { + Some(class_hash) => { + self.add_hit(); + Ok(class_hash) + } None => { + self.add_miss(); let class_hash = self.state_reader.get_class_hash_at(contract_address)?; self.cache .class_hash_initial_values @@ -308,10 +344,13 @@ impl State for CachedState { fn get_nonce_at(&mut self, contract_address: &Address) -> Result { if self.cache.get_nonce(contract_address).is_none() { + self.add_miss(); let nonce = self.state_reader.get_nonce_at(contract_address)?; self.cache .nonce_initial_values .insert(contract_address.clone(), nonce); + } else { + self.add_hit(); } Ok(self .cache @@ -324,9 +363,13 @@ impl State for CachedState { /// Returns zero as default value if missing /// Adds the value to the cache's inital_values if not present fn get_storage_at(&mut self, storage_entry: &StorageEntry) -> Result { - match self.cache.get_storage(storage_entry) { - Some(value) => Ok(value.clone()), + match self.cache.get_storage(storage_entry).cloned() { + Some(value) => { + self.add_hit(); + Ok(value) + } None => { + self.add_miss(); let value = self.state_reader.get_storage_at(storage_entry)?; self.cache .storage_initial_values @@ -338,16 +381,25 @@ impl State for CachedState { // TODO: check if that the proper way to store it (converting hash to address) fn get_compiled_class_hash(&mut self, class_hash: &ClassHash) -> Result { - let hash = self.cache.class_hash_to_compiled_class_hash.get(class_hash); - if let Some(hash) = hash { - Ok(*hash) - } else { - let compiled_class_hash = self.state_reader.get_compiled_class_hash(class_hash)?; - let address = Address(Felt252::from_bytes_be(&compiled_class_hash)); - self.cache - .class_hash_initial_values - .insert(address, compiled_class_hash); - Ok(compiled_class_hash) + match self + .cache + .class_hash_to_compiled_class_hash + .get(class_hash) + .cloned() + { + Some(hash) => { + self.add_hit(); + Ok(hash) + } + None => { + self.add_miss(); + let compiled_class_hash = self.state_reader.get_compiled_class_hash(class_hash)?; + let address = Address(Felt252::from_bytes_be(&compiled_class_hash)); + self.cache + .class_hash_initial_values + .insert(address, compiled_class_hash); + Ok(compiled_class_hash) + } } } @@ -360,16 +412,18 @@ impl State for CachedState { // I: FETCHING FROM CACHE // deprecated contract classes dont have compiled class hashes, so we only have one case - if let Some(compiled_class) = self.contract_classes.get(class_hash) { - return Ok(compiled_class.clone()); + if let Some(compiled_class) = self.contract_classes.get(class_hash).cloned() { + self.add_hit(); + return Ok(compiled_class); } // I: CASM CONTRACT CLASS : CLASS_HASH if let Some(compiled_class_hash) = self.cache.class_hash_to_compiled_class_hash.get(class_hash) { - if let Some(casm_class) = self.contract_classes.get(compiled_class_hash) { - return Ok(casm_class.clone()); + if let Some(casm_class) = self.contract_classes.get(compiled_class_hash).cloned() { + self.add_hit(); + return Ok(casm_class); } } @@ -755,4 +809,38 @@ mod tests { ]) ) } + + #[cfg(feature = "metrics")] + #[test] + fn test_cache_hit_miss_counter() { + let state_reader = Arc::new(InMemoryStateReader::default()); + let mut cached_state = CachedState::new(state_reader, None, None); + + let address = Address(1.into()); + + // Simulate a cache miss by querying an address not in the cache. + let _ = as State>::get_class_hash_at(&mut cached_state, &address); + assert_eq!(cached_state.cache_misses, 1); + assert_eq!(cached_state.cache_hits, 0); + + // Simulate a cache hit by adding the address to the cache and querying it again. + cached_state + .cache + .class_hash_writes + .insert(address.clone(), [0; 32]); + let _ = as State>::get_class_hash_at(&mut cached_state, &address); + assert_eq!(cached_state.cache_misses, 1); + assert_eq!(cached_state.cache_hits, 1); + + // Simulate another cache hit. + let _ = as State>::get_class_hash_at(&mut cached_state, &address); + assert_eq!(cached_state.cache_misses, 1); + assert_eq!(cached_state.cache_hits, 2); + + // Simulate another cache miss. + let other_address = Address(2.into()); + let _ = as State>::get_class_hash_at(&mut cached_state, &other_address); + assert_eq!(cached_state.cache_misses, 2); + assert_eq!(cached_state.cache_hits, 2); + } } From c1b127265875c22947e3f2a542b0f540185f9738 Mon Sep 17 00:00:00 2001 From: Juan Bono Date: Tue, 12 Sep 2023 11:28:30 -0300 Subject: [PATCH 30/44] add tests and remove ignore on fixed ones (#1021) --- rpc_state_reader/tests/blockifier_tests.rs | 17 ++++++++++++++++- rpc_state_reader/tests/sir_tests.rs | 22 +++++++++++++++++----- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/rpc_state_reader/tests/blockifier_tests.rs b/rpc_state_reader/tests/blockifier_tests.rs index 5f5ce7c35..4c7578987 100644 --- a/rpc_state_reader/tests/blockifier_tests.rs +++ b/rpc_state_reader/tests/blockifier_tests.rs @@ -237,6 +237,22 @@ fn blockifier_test_recent_tx() { ); } +#[test_case( + "0x014640564509873cf9d24a311e1207040c8b60efd38d96caef79855f0b0075d5", + 90006, + RpcChain::MainNet + => ignore["old transaction, gas mismatch"] +)] +#[test_case( + "0x025844447697eb7d5df4d8268b23aef6c11de4087936048278c2559fc35549eb", + 197000, + RpcChain::MainNet +)] +#[test_case( + "0x00164bfc80755f62de97ae7c98c9d67c1767259427bcf4ccfcc9683d44d54676", + 197000, + RpcChain::MainNet +)] #[test_case( "0x05d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91", 169928, // real block 169929 @@ -266,7 +282,6 @@ fn blockifier_test_recent_tx() { => ignore["resource mismatch"] )] #[test_case( - // fails in blockifier too "0x00724fc4a84f489ed032ebccebfc9541eb8dc64b0e76b933ed6fc30cd6000bd1", 186551, // real block 186552 RpcChain::MainNet diff --git a/rpc_state_reader/tests/sir_tests.rs b/rpc_state_reader/tests/sir_tests.rs index b86abc273..4c33dc95a 100644 --- a/rpc_state_reader/tests/sir_tests.rs +++ b/rpc_state_reader/tests/sir_tests.rs @@ -197,17 +197,31 @@ fn test_get_gas_price() { assert_eq!(price, 22804578690); } +#[test_case( + "0x014640564509873cf9d24a311e1207040c8b60efd38d96caef79855f0b0075d5", + 90006, + RpcChain::MainNet + => ignore["old transaction, gas mismatch"] +)] +#[test_case( + "0x025844447697eb7d5df4d8268b23aef6c11de4087936048278c2559fc35549eb", + 197000, + RpcChain::MainNet +)] +#[test_case( + "0x00164bfc80755f62de97ae7c98c9d67c1767259427bcf4ccfcc9683d44d54676", + 197000, + RpcChain::MainNet +)] #[test_case( "0x05d200ef175ba15d676a68b36f7a7b72c17c17604eda4c1efc2ed5e4973e2c91", 169928, // real block 169929 RpcChain::MainNet - => ignore["gas mismatch"] )] #[test_case( "0x0528ec457cf8757f3eefdf3f0728ed09feeecc50fd97b1e4c5da94e27e9aa1d6", 169928, // real block 169929 RpcChain::MainNet - => ignore["gas mismatch"] )] #[test_case( "0x0737677385a30ec4cbf9f6d23e74479926975b74db3d55dc5e46f4f8efee41cf", @@ -219,7 +233,6 @@ fn test_get_gas_price() { "0x026c17728b9cd08a061b1f17f08034eb70df58c1a96421e73ee6738ad258a94c", 169928, // real block 169929 RpcChain::MainNet - => ignore["gas mismatch"] )] #[test_case( // review later @@ -229,11 +242,10 @@ fn test_get_gas_price() { => ignore["resource mismatch"] )] #[test_case( - // fails in blockifier too + // fails in blockifier "0x00724fc4a84f489ed032ebccebfc9541eb8dc64b0e76b933ed6fc30cd6000bd1", 186551, // real block 186552 RpcChain::MainNet - => ignore["gas mismatch"] )] fn starknet_in_rust_test_case_tx(hash: &str, block_number: u64, chain: RpcChain) { let (tx_info, trace, receipt) = execute_tx(hash, chain, BlockNumber(block_number)); From affa0125472de78ebf9e925fc0268d613462a59c Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 12 Sep 2023 18:51:09 +0200 Subject: [PATCH 31/44] perf: refactor substract_mappings and friends to avoid clones (#1023) * refactor substract_mappings and friends to avoid clones of the whole hashmap * another opt * dont use deref * fix deref again * no need for contains_key * oops --- src/state/cached_state.rs | 32 ++++++++++++-------------------- src/state/mod.rs | 27 ++++++++++++--------------- src/utils.rs | 38 ++++++++++++++++++++++++++++---------- 3 files changed, 52 insertions(+), 45 deletions(-) diff --git a/src/state/cached_state.rs b/src/state/cached_state.rs index d1a616953..d44361ea3 100644 --- a/src/state/cached_state.rs +++ b/src/state/cached_state.rs @@ -7,8 +7,8 @@ use crate::{ services::api::contract_classes::compiled_class::CompiledClass, state::StateDiff, utils::{ - get_erc20_balance_var_addresses, subtract_mappings, to_cache_state_storage_mapping, - Address, ClassHash, + get_erc20_balance_var_addresses, subtract_mappings, subtract_mappings_keys, + to_cache_state_storage_mapping, Address, ClassHash, }, }; use cairo_vm::felt::Felt252; @@ -281,32 +281,24 @@ impl State for CachedState { self.update_initial_values_of_write_only_accesses()?; let mut storage_updates = subtract_mappings( - self.cache.storage_writes.clone(), - self.cache.storage_initial_values.clone(), + &self.cache.storage_writes, + &self.cache.storage_initial_values, ); let storage_unique_updates = storage_updates.keys().map(|k| k.0.clone()); - let class_hash_updates: Vec<_> = subtract_mappings( - self.cache.class_hash_writes.clone(), - self.cache.class_hash_initial_values.clone(), - ) - .keys() - .cloned() - .collect(); + let class_hash_updates = subtract_mappings_keys( + &self.cache.class_hash_writes, + &self.cache.class_hash_initial_values, + ); - let nonce_updates: Vec<_> = subtract_mappings( - self.cache.nonce_writes.clone(), - self.cache.nonce_initial_values.clone(), - ) - .keys() - .cloned() - .collect(); + let nonce_updates = + subtract_mappings_keys(&self.cache.nonce_writes, &self.cache.nonce_initial_values); let mut modified_contracts: HashSet
= HashSet::new(); modified_contracts.extend(storage_unique_updates); - modified_contracts.extend(class_hash_updates); - modified_contracts.extend(nonce_updates); + modified_contracts.extend(class_hash_updates.cloned()); + modified_contracts.extend(nonce_updates.cloned()); // Add fee transfer storage update before actually charging it, as it needs to be included in the // calculation of the final fee. diff --git a/src/state/mod.rs b/src/state/mod.rs index 33f8ab5db..f61470ed3 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -134,25 +134,23 @@ impl StateDiff { let state_cache = cached_state.cache().to_owned(); let substracted_maps = subtract_mappings( - state_cache.storage_writes.clone(), - state_cache.storage_initial_values.clone(), + &state_cache.storage_writes, + &state_cache.storage_initial_values, ); let storage_updates = to_state_diff_storage_mapping(substracted_maps); - let address_to_nonce = subtract_mappings( - state_cache.nonce_writes.clone(), - state_cache.nonce_initial_values.clone(), - ); + let address_to_nonce = + subtract_mappings(&state_cache.nonce_writes, &state_cache.nonce_initial_values); let class_hash_to_compiled_class = subtract_mappings( - state_cache.compiled_class_hash_writes.clone(), - state_cache.compiled_class_hash_initial_values.clone(), + &state_cache.compiled_class_hash_writes, + &state_cache.compiled_class_hash_initial_values, ); let address_to_class_hash = subtract_mappings( - state_cache.class_hash_writes.clone(), - state_cache.class_hash_initial_values, + &state_cache.class_hash_writes, + &state_cache.class_hash_initial_values, ); Ok(StateDiff { @@ -193,23 +191,22 @@ impl StateDiff { let mut storage_updates = HashMap::new(); - let addresses: Vec
= - get_keys(self.storage_updates.clone(), other.storage_updates.clone()); + let addresses: Vec<&Address> = get_keys(&self.storage_updates, &other.storage_updates); for address in addresses { let default: HashMap = HashMap::new(); let mut map_a = self .storage_updates - .get(&address) + .get(address) .unwrap_or(&default) .to_owned(); let map_b = other .storage_updates - .get(&address) + .get(address) .unwrap_or(&default) .to_owned(); map_a.extend(map_b); - storage_updates.insert(address, map_a.clone()); + storage_updates.insert(address.clone(), map_a.clone()); } StateDiff { diff --git a/src/utils.rs b/src/utils.rs index aabc929c4..15b70cbf9 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -230,20 +230,38 @@ where V: PartialEq + Clone, { let val = map.get(key); - !(map.contains_key(key) && (Some(value) == val)) + Some(value) != val } -pub fn subtract_mappings(map_a: HashMap, map_b: HashMap) -> HashMap +pub fn subtract_mappings<'a, K, V>( + map_a: &'a HashMap, + map_b: &'a HashMap, +) -> HashMap where K: Hash + Eq + Clone, V: PartialEq + Clone, { map_a - .into_iter() - .filter(|(k, v)| contained_and_not_updated(k, v, &map_b)) + .iter() + .filter(|(k, v)| contained_and_not_updated(*k, *v, map_b)) + .map(|(k, v)| (k.clone(), v.clone())) .collect() } +pub fn subtract_mappings_keys<'a, K, V>( + map_a: &'a HashMap, + map_b: &'a HashMap, +) -> impl Iterator +where + K: Hash + Eq + Clone, + V: PartialEq + Clone, +{ + map_a + .iter() + .filter(|(k, v)| contained_and_not_updated(*k, *v, map_b)) + .map(|x| x.0) +} + /// Converts StateDiff storage mapping (addresses map to a key-value mapping) to CachedState /// storage mapping (Tuple of address and key map to the associated value). pub fn to_cache_state_storage_mapping( @@ -260,12 +278,12 @@ pub fn to_cache_state_storage_mapping( // get a vector of keys from two hashmaps -pub fn get_keys(map_a: HashMap, map_b: HashMap) -> Vec +pub fn get_keys<'a, K, V>(map_a: &'a HashMap, map_b: &'a HashMap) -> Vec<&'a K> where K: Hash + Eq, { - let mut keys1: HashSet = map_a.into_keys().collect(); - let keys2: HashSet = map_b.into_keys().collect(); + let mut keys1: HashSet<&K> = map_a.keys().collect(); + let keys2: HashSet<&K> = map_b.keys().collect(); keys1.extend(keys2); @@ -647,7 +665,7 @@ mod test { .into_iter() .collect::>(); - assert_eq!(subtract_mappings(a, b), res); + assert_eq!(subtract_mappings(&a, &b), res); let mut c = HashMap::new(); let mut d = HashMap::new(); @@ -664,7 +682,7 @@ mod test { .into_iter() .collect::>(); - assert_eq!(subtract_mappings(c, d), res); + assert_eq!(subtract_mappings(&c, &d), res); let mut e = HashMap::new(); let mut f = HashMap::new(); @@ -676,7 +694,7 @@ mod test { f.insert(3, 4); f.insert(6, 7); - assert_eq!(subtract_mappings(e, f), HashMap::new()) + assert_eq!(subtract_mappings(&e, &f), HashMap::new()) } #[test] From 6046d7533deb982bed9c66a4a4c29b9aa2afc7b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Est=C3=A9fano=20Bargas?= Date: Wed, 13 Sep 2023 12:14:13 -0300 Subject: [PATCH 32/44] Fix transactions bypassing the max_fee by introducing new revert logic (#901) * Make tx fail when actual_fee exceeds max_fee * Changed test * Formatting * Fix logic * Leave fail only without charging * Change test * Fix test broken by better fee calc * Fixed test fee * Update fee on test_deploy_account * Remove comment * Added fee transfer * Test with invoke * Added revert logic for invoke * Modify tests, add fixes * Add revert error * Fix test_invoke_tx_account * Fixed test_invoke_tx_exceeded_max_fee * Fix test_get_nonce_at * Rely on another contract * Introduced transactional state (#917) * Introduced transactional state * WIP * Fixed the rest of tests * Replaced old revert logic from entrypoint exec * depl acc revert test * Remove update writes fix * WIP Fixed many tests * fix test * fix more tests * more fixes * fix another test * fix latest test * name * remove comment * merge * unignore * format * vis * need to be pub for tests * fix test * format * use the count_actual_storage_changes impl from cached state * fix bug * fix tests --------- Co-authored-by: Juan Bono Co-authored-by: Edgar Luque --- Cargo.lock | 1 + Cargo.toml | 1 + cli/src/main.rs | 6 +- rpc_state_reader/tests/blockifier_tests.rs | 26 +++ rpc_state_reader/tests/sir_tests.rs | 26 +++ src/execution/execution_entry_point.rs | 21 +- src/execution/mod.rs | 10 + src/lib.rs | 1 + src/state/cached_state.rs | 137 ++++++++++- src/state/in_memory_state_reader.rs | 2 +- src/state/mod.rs | 25 +- src/state/state_cache.rs | 2 +- src/syscalls/deprecated_syscall_handler.rs | 8 +- src/testing/erc20.rs | 10 +- src/testing/state.rs | 3 +- src/transaction/declare_v2.rs | 3 + src/transaction/deploy_account.rs | 35 ++- src/transaction/fee.rs | 53 +++-- src/transaction/invoke_function.rs | 95 ++++++-- tests/deploy_account.rs | 6 + tests/internals.rs | 251 +++++++++++++++++---- 21 files changed, 584 insertions(+), 138 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 38afa0d13..7b32171e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3868,6 +3868,7 @@ dependencies = [ "num-integer", "num-traits 0.2.16", "once_cell", + "pretty_assertions_sorted", "serde", "serde_json", "serde_json_pythonic 0.1.2 (git+https://github.com/xJonathanLEI/serde_json_pythonic?tag=v0.1.2)", diff --git a/Cargo.toml b/Cargo.toml index 3e97eeaf9..542716fc7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,6 +61,7 @@ serde_json_pythonic = { git = "https://github.com/xJonathanLEI/serde_json_python [dev-dependencies] assert_matches = "1.5.0" coverage-helper = "0.1.0" +pretty_assertions_sorted = "1.2.3" [[bench]] path = "bench/internals.rs" diff --git a/cli/src/main.rs b/cli/src/main.rs index 1248123dd..a9371b08c 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -27,7 +27,7 @@ use starknet_in_rust::{ compiled_class::CompiledClass, deprecated_contract_class::ContractClass, }, state::{cached_state::CachedState, state_api::State}, - state::{in_memory_state_reader::InMemoryStateReader, ExecutionResourcesManager}, + state::{in_memory_state_reader::InMemoryStateReader, ExecutionResourcesManager, StateDiff}, transaction::{error::TransactionError, InvokeFunction}, utils::{felt_to_hash, string_to_hash, Address}, }; @@ -200,7 +200,9 @@ fn invoke_parser( Some(Felt252::zero()), transaction_hash.unwrap(), )?; - let _tx_info = internal_invoke.apply(cached_state, &BlockContext::default(), 0)?; + let mut transactional_state = cached_state.create_transactional(); + let _tx_info = internal_invoke.apply(&mut transactional_state, &BlockContext::default(), 0)?; + cached_state.apply_state_update(&StateDiff::from_cached_state(transactional_state)?)?; let tx_hash = calculate_transaction_hash_common( TransactionHashPrefix::Invoke, diff --git a/rpc_state_reader/tests/blockifier_tests.rs b/rpc_state_reader/tests/blockifier_tests.rs index 4c7578987..a32139934 100644 --- a/rpc_state_reader/tests/blockifier_tests.rs +++ b/rpc_state_reader/tests/blockifier_tests.rs @@ -331,3 +331,29 @@ fn blockifier_test_case_tx(hash: &str, block_number: u64, chain: RpcChain) { .len() ); } + +#[test_case( + "0x00b6d59c19d5178886b4c939656167db0660fe325345138025a3cc4175b21897", + 200303, // real block 200304 + RpcChain::MainNet +)] +#[test_case( + "0x02b28b4846a756e0cec6385d6d13f811e745a88c7e75a3ebc5fead5b4af152a3", + 200302, // real block 200304 + RpcChain::MainNet + => ignore["broken on both due to a cairo-vm error"] +)] +fn blockifier_test_case_reverted_tx(hash: &str, block_number: u64, chain: RpcChain) { + let (tx_info, trace, receipt) = execute_tx(hash, chain, BlockNumber(block_number)); + + assert_eq!(tx_info.revert_error.is_some(), trace.revert_error.is_some()); + + let diff = 100 * receipt.actual_fee.abs_diff(tx_info.actual_fee.0) / receipt.actual_fee; + + if diff >= 5 { + assert_eq!( + tx_info.actual_fee.0, receipt.actual_fee, + "actual_fee mismatch differs from the baseline by more than 5% ({diff}%)", + ); + } +} diff --git a/rpc_state_reader/tests/sir_tests.rs b/rpc_state_reader/tests/sir_tests.rs index 4c33dc95a..4550f202e 100644 --- a/rpc_state_reader/tests/sir_tests.rs +++ b/rpc_state_reader/tests/sir_tests.rs @@ -293,3 +293,29 @@ fn starknet_in_rust_test_case_tx(hash: &str, block_number: u64, chain: RpcChain) } } } + +#[test_case( + "0x00b6d59c19d5178886b4c939656167db0660fe325345138025a3cc4175b21897", + 200303, // real block 200304 + RpcChain::MainNet +)] +#[test_case( + "0x02b28b4846a756e0cec6385d6d13f811e745a88c7e75a3ebc5fead5b4af152a3", + 200302, // real block 200304 + RpcChain::MainNet + => ignore["broken on both due to a cairo-vm error"] +)] +fn starknet_in_rust_test_case_reverted_tx(hash: &str, block_number: u64, chain: RpcChain) { + let (tx_info, trace, receipt) = execute_tx(hash, chain, BlockNumber(block_number)); + + assert_eq!(tx_info.revert_error.is_some(), trace.revert_error.is_some()); + + let diff = 100 * receipt.actual_fee.abs_diff(tx_info.actual_fee) / receipt.actual_fee; + + if diff >= 5 { + assert_eq!( + tx_info.actual_fee, receipt.actual_fee, + "actual_fee mismatch differs from the baseline by more than 5% ({diff}%)", + ); + } +} diff --git a/src/execution/execution_entry_point.rs b/src/execution/execution_entry_point.rs index b16b500a9..771191767 100644 --- a/src/execution/execution_entry_point.rs +++ b/src/execution/execution_entry_point.rs @@ -4,7 +4,6 @@ use crate::services::api::contract_classes::deprecated_contract_class::{ ContractEntryPoint, EntryPointType, }; use crate::state::cached_state::CachedState; -use crate::state::StateDiff; use crate::{ definitions::{block_context::BlockContext, constants::DEFAULT_ENTRY_POINT_SELECTOR}, runner::StarknetRunner, @@ -128,12 +127,8 @@ impl ExecutionEntryPoint { }) } CompiledClass::Casm(contract_class) => { - let mut tmp_state = - CachedState::new(state.state_reader.clone(), state.contract_classes.clone()); - tmp_state.cache = state.cache.clone(); - match self._execute( - &mut tmp_state, + state, resources_manager, block_context, tx_execution_context, @@ -141,15 +136,11 @@ impl ExecutionEntryPoint { class_hash, support_reverted, ) { - Ok(call_info) => { - let state_diff = StateDiff::from_cached_state(tmp_state)?; - state.apply_state_update(&state_diff)?; - Ok(ExecutionResult { - call_info: Some(call_info), - revert_error: None, - n_reverted_steps: 0, - }) - } + Ok(call_info) => Ok(ExecutionResult { + call_info: Some(call_info), + revert_error: None, + n_reverted_steps: 0, + }), Err(e) => { if !support_reverted { return Err(e); diff --git a/src/execution/mod.rs b/src/execution/mod.rs index 4acaf3fbe..8de60b7e2 100644 --- a/src/execution/mod.rs +++ b/src/execution/mod.rs @@ -609,6 +609,16 @@ impl TransactionExecutionInfo { Ok(sorted_messages) } + + pub fn to_revert_error(self, revert_error: &str) -> Self { + TransactionExecutionInfo { + validate_info: None, + call_info: None, + revert_error: Some(revert_error.to_string()), + fee_transfer_info: None, + ..self + } + } } // -------------------- diff --git a/src/lib.rs b/src/lib.rs index 79e01117e..d5878d3d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -249,6 +249,7 @@ mod test { use crate::services::api::contract_classes::compiled_class::CompiledClass; use lazy_static::lazy_static; + use pretty_assertions_sorted::assert_eq; lazy_static! { // include_str! doesn't seem to work in CI diff --git a/src/state/cached_state.rs b/src/state/cached_state.rs index d44361ea3..dfa8f7efc 100644 --- a/src/state/cached_state.rs +++ b/src/state/cached_state.rs @@ -99,6 +99,19 @@ impl CachedState { self.contract_classes = contract_classes; Ok(()) } + + /// Creates a copy of this state with an empty cache for saving changes and applying them + /// later. + pub fn create_transactional(&self) -> TransactionalCachedState { + let state_reader = Arc::new(TransactionalCachedStateReader::new(self)); + CachedState { + state_reader, + cache: self.cache.clone(), + contract_classes: self.contract_classes.clone(), + cache_hits: 0, + cache_misses: 0, + } + } } impl StateReader for CachedState { @@ -134,19 +147,13 @@ impl StateReader for CachedState { // TODO: check if that the proper way to store it (converting hash to address) /// Returned the compiled class hash for a given class hash. fn get_compiled_class_hash(&self, class_hash: &ClassHash) -> Result { - if self - .cache - .class_hash_to_compiled_class_hash - .get(class_hash) - .is_none() + if let Some(compiled_class_hash) = + self.cache.class_hash_to_compiled_class_hash.get(class_hash) { - return self.state_reader.get_compiled_class_hash(class_hash); + Ok(*compiled_class_hash) + } else { + self.state_reader.get_compiled_class_hash(class_hash) } - self.cache - .class_hash_to_compiled_class_hash - .get(class_hash) - .ok_or_else(|| StateError::NoneCompiledClass(*class_hash)) - .cloned() } /// Returns the contract class for a given class hash. @@ -438,6 +445,114 @@ impl State for CachedState { } } +/// A CachedState which has access to another, "parent" state, used for executing transactions +/// without commiting changes to the parent. +pub type TransactionalCachedState<'a, T> = CachedState>; + +/// State reader used for transactional states which allows to check the parent state's cache and +/// state reader if a transactional cache miss happens. +/// +/// In practice this will act as a way to access the parent state's cache and other fields, +/// without referencing the whole parent state, so there's no need to adapt state-modifying +/// functions in the case that a transactional state is needed. +#[derive(Debug, MutGetters, Getters, PartialEq, Clone)] +pub struct TransactionalCachedStateReader<'a, T: StateReader> { + /// The parent state's state_reader + #[get(get = "pub")] + pub(crate) state_reader: Arc, + /// The parent state's cache + #[get(get = "pub")] + pub(crate) cache: &'a StateCache, + /// The parent state's contract_classes + #[get(get = "pub")] + pub(crate) contract_classes: ContractClassCache, +} + +impl<'a, T: StateReader> TransactionalCachedStateReader<'a, T> { + fn new(state: &'a CachedState) -> Self { + Self { + state_reader: state.state_reader.clone(), + cache: &state.cache, + contract_classes: state.contract_classes.clone(), + } + } +} + +impl<'a, T: StateReader> StateReader for TransactionalCachedStateReader<'a, T> { + /// Returns the class hash for a given contract address. + /// Returns zero as default value if missing + fn get_class_hash_at(&self, contract_address: &Address) -> Result { + self.cache + .get_class_hash(contract_address) + .map(|a| Ok(*a)) + .unwrap_or_else(|| self.state_reader.get_class_hash_at(contract_address)) + } + + /// Returns the nonce for a given contract address. + fn get_nonce_at(&self, contract_address: &Address) -> Result { + if self.cache.get_nonce(contract_address).is_none() { + return self.state_reader.get_nonce_at(contract_address); + } + self.cache + .get_nonce(contract_address) + .ok_or_else(|| StateError::NoneNonce(contract_address.clone())) + .cloned() + } + + /// Returns storage data for a given storage entry. + /// Returns zero as default value if missing + fn get_storage_at(&self, storage_entry: &StorageEntry) -> Result { + self.cache + .get_storage(storage_entry) + .map(|v| Ok(v.clone())) + .unwrap_or_else(|| self.state_reader.get_storage_at(storage_entry)) + } + + // TODO: check if that the proper way to store it (converting hash to address) + /// Returned the compiled class hash for a given class hash. + fn get_compiled_class_hash(&self, class_hash: &ClassHash) -> Result { + if self + .cache + .class_hash_to_compiled_class_hash + .get(class_hash) + .is_none() + { + return self.state_reader.get_compiled_class_hash(class_hash); + } + self.cache + .class_hash_to_compiled_class_hash + .get(class_hash) + .ok_or_else(|| StateError::NoneCompiledClass(*class_hash)) + .cloned() + } + + /// Returns the contract class for a given class hash. + fn get_contract_class(&self, class_hash: &ClassHash) -> Result { + // This method can receive both compiled_class_hash & class_hash and return both casm and deprecated contract classes + //, which can be on the cache or on the state_reader, different cases will be described below: + if class_hash == UNINITIALIZED_CLASS_HASH { + return Err(StateError::UninitiaizedClassHash); + } + + // I: FETCHING FROM CACHE + if let Some(compiled_class) = self.contract_classes.get(class_hash) { + return Ok(compiled_class.clone()); + } + + // I: CASM CONTRACT CLASS : CLASS_HASH + if let Some(compiled_class_hash) = + self.cache.class_hash_to_compiled_class_hash.get(class_hash) + { + if let Some(casm_class) = self.contract_classes.get(compiled_class_hash) { + return Ok(casm_class.clone()); + } + } + + // II: FETCHING FROM STATE_READER + self.state_reader.get_contract_class(class_hash) + } +} + impl CachedState { // Updates the cache's storage_initial_values according to those in storage_writes // If a key is present in the storage_writes but not in storage_initial_values, diff --git a/src/state/in_memory_state_reader.rs b/src/state/in_memory_state_reader.rs index ce223c830..8e316e42b 100644 --- a/src/state/in_memory_state_reader.rs +++ b/src/state/in_memory_state_reader.rs @@ -25,7 +25,7 @@ pub struct InMemoryStateReader { #[getset(get_mut = "pub")] pub class_hash_to_compiled_class: HashMap, #[getset(get_mut = "pub")] - pub(crate) class_hash_to_compiled_class_hash: HashMap, + pub class_hash_to_compiled_class_hash: HashMap, } impl InMemoryStateReader { diff --git a/src/state/mod.rs b/src/state/mod.rs index f61470ed3..8bee53a5d 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -7,9 +7,7 @@ pub mod state_cache; use crate::{ core::errors::state_errors::StateError, services::api::contract_classes::compiled_class::CompiledClass, - utils::{ - get_keys, subtract_mappings, to_cache_state_storage_mapping, to_state_diff_storage_mapping, - }, + utils::{get_keys, to_cache_state_storage_mapping, to_state_diff_storage_mapping}, }; use cairo_vm::{felt::Felt252, vm::runners::cairo_runner::ExecutionResources}; use getset::Getters; @@ -133,25 +131,12 @@ impl StateDiff { { let state_cache = cached_state.cache().to_owned(); - let substracted_maps = subtract_mappings( - &state_cache.storage_writes, - &state_cache.storage_initial_values, - ); - + let substracted_maps = state_cache.storage_writes; let storage_updates = to_state_diff_storage_mapping(substracted_maps); - let address_to_nonce = - subtract_mappings(&state_cache.nonce_writes, &state_cache.nonce_initial_values); - - let class_hash_to_compiled_class = subtract_mappings( - &state_cache.compiled_class_hash_writes, - &state_cache.compiled_class_hash_initial_values, - ); - - let address_to_class_hash = subtract_mappings( - &state_cache.class_hash_writes, - &state_cache.class_hash_initial_values, - ); + let address_to_nonce = state_cache.nonce_writes; + let class_hash_to_compiled_class = state_cache.compiled_class_hash_writes; + let address_to_class_hash = state_cache.class_hash_writes; Ok(StateDiff { address_to_class_hash, diff --git a/src/state/state_cache.rs b/src/state/state_cache.rs index 2b5876015..6238c258d 100644 --- a/src/state/state_cache.rs +++ b/src/state/state_cache.rs @@ -21,7 +21,7 @@ pub struct StateCache { pub(crate) compiled_class_hash_initial_values: HashMap, #[getset(get = "pub", get_mut = "pub")] pub(crate) nonce_initial_values: HashMap, - #[get_mut = "pub"] + #[getset(get = "pub", get_mut = "pub")] pub(crate) storage_initial_values: HashMap, // Writer's cached information. diff --git a/src/syscalls/deprecated_syscall_handler.rs b/src/syscalls/deprecated_syscall_handler.rs index 7ee047b76..eb6a214e9 100644 --- a/src/syscalls/deprecated_syscall_handler.rs +++ b/src/syscalls/deprecated_syscall_handler.rs @@ -229,6 +229,7 @@ mod tests { use super::*; use crate::services::api::contract_classes::compiled_class::CompiledClass; use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; + use crate::state::StateDiff; use crate::{ add_segments, allocate_selector, any_box, definitions::{ @@ -1195,9 +1196,14 @@ mod tests { ) .unwrap(); + let mut transactional = state.create_transactional(); // Invoke result let result = internal_invoke_function - .apply(&mut state, &BlockContext::default(), 0) + .apply(&mut transactional, &BlockContext::default(), 0) + .unwrap(); + + state + .apply_state_update(&StateDiff::from_cached_state(transactional).unwrap()) .unwrap(); let result_call_info = result.call_info.unwrap(); diff --git a/src/testing/erc20.rs b/src/testing/erc20.rs index 97dbf7cb8..f29f94b0b 100644 --- a/src/testing/erc20.rs +++ b/src/testing/erc20.rs @@ -147,6 +147,9 @@ fn test_erc20_cairo2() { &CompiledClass::Casm(Arc::new(contract_class_account)), ) .unwrap(); + state + .set_compiled_class_hash(&felt_str!("1"), &Felt252::from_bytes_be(&class_hash)) + .unwrap(); let contract_address_salt = felt_str!("2669425616857739096022668060305620640217901643963991674344872184515580705509"); @@ -172,9 +175,9 @@ fn test_erc20_cairo2() { let account_address_1 = internal_deploy_account .execute(&mut state, &Default::default()) - .unwrap() + .expect("failed to execute internal_deploy_account") .validate_info - .unwrap() + .expect("validate_info missing") .contract_address; // ACCOUNT 2 @@ -189,6 +192,9 @@ fn test_erc20_cairo2() { &CompiledClass::Casm(Arc::new(contract_class_account)), ) .unwrap(); + state + .set_compiled_class_hash(&felt_str!("1"), &Felt252::from_bytes_be(&class_hash)) + .unwrap(); let contract_address_salt = felt_str!("123123123123123"); diff --git a/src/testing/state.rs b/src/testing/state.rs index 82ea3a199..2fbbaec87 100644 --- a/src/testing/state.rs +++ b/src/testing/state.rs @@ -324,6 +324,7 @@ mod tests { use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use num_traits::Num; + use pretty_assertions_sorted::assert_eq_sorted; use super::*; use crate::{ @@ -613,7 +614,7 @@ mod tests { ..Default::default() }; - assert_eq!(tx_info, expected_info); + assert_eq_sorted!(tx_info, expected_info); } #[test] diff --git a/src/transaction/declare_v2.rs b/src/transaction/declare_v2.rs index bad0d4ac8..cfc400186 100644 --- a/src/transaction/declare_v2.rs +++ b/src/transaction/declare_v2.rs @@ -375,6 +375,9 @@ impl DeclareV2 { )); } state.set_compiled_class_hash(&self.sierra_class_hash, &self.compiled_class_hash)?; + // theorically class_hash == compiled_class_hash in v2, so this is like setting class_hash -> compiled_class_hash + // which is needed for get_compiled_class_hash later to work. + state.set_compiled_class_hash(&self.compiled_class_hash, &self.compiled_class_hash)?; state.set_contract_class( &self.compiled_class_hash.to_be_bytes(), &CompiledClass::Casm(Arc::new(casm_class)), diff --git a/src/transaction/deploy_account.rs b/src/transaction/deploy_account.rs index bc8fe3ef8..673aa2053 100644 --- a/src/transaction/deploy_account.rs +++ b/src/transaction/deploy_account.rs @@ -1,9 +1,10 @@ -use super::fee::charge_fee; +use super::fee::{calculate_tx_fee, charge_fee}; use super::{invoke_function::verify_no_calls_to_other_contracts, Transaction}; use crate::definitions::constants::QUERY_VERSION_BASE; use crate::execution::execution_entry_point::ExecutionResult; use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; use crate::state::cached_state::CachedState; +use crate::state::StateDiff; use crate::{ core::{ errors::state_errors::StateError, @@ -156,22 +157,46 @@ impl DeployAccount { block_context: &BlockContext, ) -> Result { self.handle_nonce(state)?; - let mut tx_info = self.apply(state, block_context)?; + + let mut transactional_state = state.create_transactional(); + let mut tx_exec_info = self.apply(&mut transactional_state, block_context)?; + + let actual_fee = calculate_tx_fee( + &tx_exec_info.actual_resources, + block_context.starknet_os_config.gas_price, + block_context, + )?; + + if let Some(revert_error) = tx_exec_info.revert_error.clone() { + // execution error + tx_exec_info = tx_exec_info.to_revert_error(&revert_error); + } else if actual_fee > self.max_fee { + // max_fee exceeded + tx_exec_info = tx_exec_info.to_revert_error( + format!( + "Calculated fee ({}) exceeds max fee ({})", + actual_fee, self.max_fee + ) + .as_str(), + ); + } else { + state.apply_state_update(&StateDiff::from_cached_state(transactional_state)?)?; + } let mut tx_execution_context = self.get_execution_context(block_context.invoke_tx_max_n_steps); let (fee_transfer_info, actual_fee) = charge_fee( state, - &tx_info.actual_resources, + &tx_exec_info.actual_resources, block_context, self.max_fee, &mut tx_execution_context, self.skip_fee_transfer, )?; - tx_info.set_fee_info(actual_fee, fee_transfer_info); + tx_exec_info.set_fee_info(actual_fee, fee_transfer_info); - Ok(tx_info) + Ok(tx_exec_info) } fn constructor_entry_points_empty( diff --git a/src/transaction/fee.rs b/src/transaction/fee.rs index 818c62a54..b9437e130 100644 --- a/src/transaction/fee.rs +++ b/src/transaction/fee.rs @@ -17,7 +17,6 @@ use crate::{ }; use cairo_vm::felt::Felt252; use num_traits::{ToPrimitive, Zero}; -use std::cmp::min; use std::collections::HashMap; // second element is the actual fee that the transaction uses @@ -154,19 +153,18 @@ pub fn charge_fee( block_context, )?; - if actual_fee > max_fee { - // TODO: Charge max_fee - return Err(TransactionError::ActualFeeExceedsMaxFee( - actual_fee, max_fee, - )); - } + let actual_fee = { + let version_0 = tx_execution_context.version == 0.into() + || tx_execution_context.version == *QUERY_VERSION_BASE; + let fee_exceeded_max = actual_fee > max_fee; - let actual_fee = if tx_execution_context.version != 0.into() - && tx_execution_context.version != *QUERY_VERSION_BASE - { - min(actual_fee, max_fee) * FEE_FACTOR - } else { - actual_fee + if version_0 && fee_exceeded_max { + 0 + } else if version_0 && !fee_exceeded_max { + actual_fee + } else { + actual_fee.min(max_fee) * FEE_FACTOR + } }; let fee_transfer_info = if skip_fee_transfer { @@ -190,13 +188,19 @@ mod tests { use crate::{ definitions::block_context::BlockContext, execution::TransactionExecutionContext, - state::{cached_state::CachedState, in_memory_state_reader::InMemoryStateReader}, - transaction::{error::TransactionError, fee::charge_fee}, + state::{ + cached_state::{CachedState, ContractClassCache}, + in_memory_state_reader::InMemoryStateReader, + }, + transaction::fee::charge_fee, }; #[test] - fn test_charge_fee_v0_actual_fee_exceeds_max_fee_should_return_error() { - let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), HashMap::new()); + fn charge_fee_v0_max_fee_exceeded_should_charge_nothing() { + let mut state = CachedState::new( + Arc::new(InMemoryStateReader::default()), + ContractClassCache::default(), + ); let mut tx_execution_context = TransactionExecutionContext::default(); let mut block_context = BlockContext::default(); block_context.starknet_os_config.gas_price = 1; @@ -215,14 +219,17 @@ mod tests { &mut tx_execution_context, skip_fee_transfer, ) - .unwrap_err(); + .unwrap(); - assert_matches!(result, TransactionError::ActualFeeExceedsMaxFee(_, _)); + assert_eq!(result.1, 0); } #[test] - fn test_charge_fee_v1_actual_fee_exceeds_max_fee_should_return_error() { - let mut state = CachedState::new(Arc::new(InMemoryStateReader::default()), HashMap::new()); + fn charge_fee_v1_max_fee_exceeded_should_charge_max_fee() { + let mut state = CachedState::new( + Arc::new(InMemoryStateReader::default()), + ContractClassCache::default(), + ); let mut tx_execution_context = TransactionExecutionContext { version: 1.into(), ..Default::default() @@ -244,8 +251,8 @@ mod tests { &mut tx_execution_context, skip_fee_transfer, ) - .unwrap_err(); + .unwrap(); - assert_matches!(result, TransactionError::ActualFeeExceedsMaxFee(_, _)); + assert_eq!(result.1, max_fee); } } diff --git a/src/transaction/invoke_function.rs b/src/transaction/invoke_function.rs index f05e3e942..15552844a 100644 --- a/src/transaction/invoke_function.rs +++ b/src/transaction/invoke_function.rs @@ -11,8 +11,14 @@ use crate::{ execution_entry_point::{ExecutionEntryPoint, ExecutionResult}, CallInfo, TransactionExecutionContext, TransactionExecutionInfo, }, - state::state_api::{State, StateReader}, - state::{cached_state::CachedState, ExecutionResourcesManager}, + state::{ + cached_state::{CachedState, TransactionalCachedState}, + ExecutionResourcesManager, + }, + state::{ + state_api::{State, StateReader}, + StateDiff, + }, transaction::error::TransactionError, utils::{calculate_tx_resources, Address}, }; @@ -22,7 +28,10 @@ use cairo_vm::felt::Felt252; use getset::Getters; use num_traits::Zero; -use super::{fee::charge_fee, Transaction}; +use super::{ + fee::{calculate_tx_fee, charge_fee}, + Transaction, +}; /// Represents an InvokeFunction transaction in the starknet network. #[derive(Debug, Getters, Clone)] @@ -234,7 +243,7 @@ impl InvokeFunction { /// - remaining_gas: The amount of gas that the transaction disposes. pub fn apply( &self, - state: &mut CachedState, + state: &mut TransactionalCachedState, block_context: &BlockContext, remaining_gas: u128, ) -> Result { @@ -293,7 +302,32 @@ impl InvokeFunction { if !self.skip_nonce_check { self.handle_nonce(state)?; } - let mut tx_exec_info = self.apply(state, block_context, remaining_gas)?; + + let mut transactional_state = state.create_transactional(); + let mut tx_exec_info = + self.apply(&mut transactional_state, block_context, remaining_gas)?; + + let actual_fee = calculate_tx_fee( + &tx_exec_info.actual_resources, + block_context.starknet_os_config.gas_price, + block_context, + )?; + + if let Some(revert_error) = tx_exec_info.revert_error.clone() { + // execution error + tx_exec_info = tx_exec_info.to_revert_error(&revert_error); + } else if actual_fee > self.max_fee { + // max_fee exceeded + tx_exec_info = tx_exec_info.to_revert_error( + format!( + "Calculated fee ({}) exceeds max fee ({})", + actual_fee, self.max_fee + ) + .as_str(), + ); + } else { + state.apply_state_update(&StateDiff::from_cached_state(transactional_state)?)?; + } let mut tx_execution_context = self.get_execution_context(block_context.invoke_tx_max_n_steps)?; @@ -500,6 +534,7 @@ mod tests { }; use cairo_lang_starknet::casm_contract_class::CasmContractClass; use num_traits::Num; + use pretty_assertions_sorted::{assert_eq, assert_eq_sorted}; use starknet_api::{ core::{ContractAddress, Nonce, PatriciaKey}, hash::{StarkFelt, StarkHash}, @@ -625,8 +660,13 @@ mod tests { ) .unwrap(); + let mut transactional = state.create_transactional(); + // Invoke result let result = internal_invoke_function - .apply(&mut state, &BlockContext::default(), 0) + .apply(&mut transactional, &BlockContext::default(), 0) + .unwrap(); + state + .apply_state_update(&StateDiff::from_cached_state(transactional).unwrap()) .unwrap(); assert_eq!(result.tx_type, Some(TransactionType::InvokeFunction)); @@ -765,8 +805,9 @@ mod tests { ) .unwrap(); + let mut transactional = state.create_transactional(); let expected_error = - internal_invoke_function.apply(&mut state, &BlockContext::default(), 0); + internal_invoke_function.apply(&mut transactional, &BlockContext::default(), 0); assert!(expected_error.is_err()); assert_matches!( @@ -827,8 +868,13 @@ mod tests { ) .unwrap(); + let mut transactional = state.create_transactional(); + // Invoke result let result = internal_invoke_function - .apply(&mut state, &BlockContext::default(), 0) + .apply(&mut transactional, &BlockContext::default(), 0) + .unwrap(); + state + .apply_state_update(&StateDiff::from_cached_state(transactional).unwrap()) .unwrap(); assert_eq!(result.tx_type, Some(TransactionType::InvokeFunction)); @@ -895,8 +941,10 @@ mod tests { ) .unwrap(); + let mut transactional = state.create_transactional(); + // Invoke result let expected_error = - internal_invoke_function.apply(&mut state, &BlockContext::default(), 0); + internal_invoke_function.apply(&mut transactional, &BlockContext::default(), 0); assert!(expected_error.is_err()); assert_matches!(expected_error.unwrap_err(), TransactionError::MissingNonce); @@ -1020,10 +1068,19 @@ mod tests { let mut block_context = BlockContext::default(); block_context.starknet_os_config.gas_price = 1; - let tx = internal_invoke_function + let tx_info = internal_invoke_function .execute(&mut state, &block_context, 0) - .unwrap_err(); - assert_matches!(tx, TransactionError::ActualFeeExceedsMaxFee(_, _)); + .unwrap(); + let expected_actual_fee = 2483; + let expected_tx_info = tx_info.clone().to_revert_error( + format!( + "Calculated fee ({}) exceeds max fee ({})", + expected_actual_fee, max_fee + ) + .as_str(), + ); + + assert_eq_sorted!(tx_info, expected_tx_info); } #[test] @@ -1273,6 +1330,10 @@ mod tests { state_reader .address_to_nonce .insert(contract_address, nonce); + state_reader + .class_hash_to_compiled_class_hash + .insert(class_hash, class_hash); + // last is necessary so the transactional state can cache the class let mut casm_contract_class_cache = HashMap::new(); @@ -1291,23 +1352,23 @@ mod tests { result.revert_error, Some("Requested entry point was not found".to_string()) ); - assert_eq!( + assert_eq_sorted!( state.cache.class_hash_writes, state_before_execution.cache.class_hash_writes ); - assert_eq!( + assert_eq_sorted!( state.cache.compiled_class_hash_writes, state_before_execution.cache.compiled_class_hash_writes ); - assert_eq!( + assert_eq_sorted!( state.cache.nonce_writes, state_before_execution.cache.nonce_writes ); - assert_eq!( + assert_eq_sorted!( state.cache.storage_writes, state_before_execution.cache.storage_writes ); - assert_eq!( + assert_eq_sorted!( state.cache.class_hash_to_compiled_class_hash, state_before_execution .cache diff --git a/tests/deploy_account.rs b/tests/deploy_account.rs index 70af6ea6d..fd4321a91 100644 --- a/tests/deploy_account.rs +++ b/tests/deploy_account.rs @@ -133,6 +133,12 @@ fn internal_deploy_account_cairo1() { &CompiledClass::Casm(Arc::new(contract_class)), ) .unwrap(); + state + .set_compiled_class_hash( + &TEST_ACCOUNT_COMPILED_CONTRACT_CLASS_HASH, + &TEST_ACCOUNT_COMPILED_CONTRACT_CLASS_HASH, + ) + .unwrap(); let contract_address_salt = felt_str!("2669425616857739096022668060305620640217901643963991674344872184515580705509"); diff --git a/tests/internals.rs b/tests/internals.rs index 3c0ff2d8c..fceccbbea 100644 --- a/tests/internals.rs +++ b/tests/internals.rs @@ -12,6 +12,7 @@ use cairo_vm::vm::{ use lazy_static::lazy_static; use num_bigint::BigUint; use num_traits::{FromPrimitive, Num, One, Zero}; +use pretty_assertions_sorted::{assert_eq, assert_eq_sorted}; use starknet_in_rust::core::contract_address::{ compute_casm_class_hash, compute_sierra_class_hash, }; @@ -239,20 +240,10 @@ fn expected_state_after_tx(fee: u128) -> CachedState { } fn state_cache_after_invoke_tx(fee: u128) -> StateCache { - let class_hash_initial_values = HashMap::from([ - ( - TEST_ACCOUNT_CONTRACT_ADDRESS.clone(), - felt_to_hash(&TEST_ACCOUNT_CONTRACT_CLASS_HASH.clone()), - ), - ( - TEST_CONTRACT_ADDRESS.clone(), - felt_to_hash(&TEST_CLASS_HASH.clone()), - ), - ( - TEST_ERC20_CONTRACT_ADDRESS.clone(), - felt_to_hash(&TEST_ERC20_CONTRACT_CLASS_HASH.clone()), - ), - ]); + let class_hash_initial_values = HashMap::from([( + TEST_ERC20_CONTRACT_ADDRESS.clone(), + felt_to_hash(&TEST_ERC20_CONTRACT_CLASS_HASH.clone()), + )]); let nonce_initial_values = HashMap::from([(TEST_ACCOUNT_CONTRACT_ADDRESS.clone(), Felt252::zero())]); @@ -592,11 +583,11 @@ fn test_create_account_tx_test_state() { // ); } -fn invoke_tx(calldata: Vec) -> InvokeFunction { +fn invoke_tx(calldata: Vec, max_fee: u128) -> InvokeFunction { InvokeFunction::new( TEST_ACCOUNT_CONTRACT_ADDRESS.clone(), EXECUTE_ENTRY_POINT_SELECTOR.clone(), - 50000000, + max_fee, TRANSACTION_VERSION.clone(), calldata, vec![], @@ -1295,13 +1286,60 @@ fn test_invoke_tx() { Felt252::from(1), // CONTRACT_CALLDATA LEN Felt252::from(2), // CONTRACT_CALLDATA ]; - let invoke_tx = invoke_tx(calldata); + let invoke_tx = invoke_tx(calldata, u128::MAX); // Extract invoke transaction fields for testing, as it is consumed when creating an account // transaction. let result = invoke_tx.execute(state, block_context, 0).unwrap(); let expected_execution_info = expected_transaction_execution_info(block_context); - assert_eq!(result, expected_execution_info); + + assert_eq_sorted!(result, expected_execution_info); +} + +#[test] +fn test_invoke_tx_exceeded_max_fee() { + let (block_context, state) = &mut create_account_tx_test_state().unwrap(); + let Address(test_contract_address) = TEST_CONTRACT_ADDRESS.clone(); + let calldata = vec![ + test_contract_address, // CONTRACT_ADDRESS + Felt252::from_bytes_be(&calculate_sn_keccak(b"return_result")), // CONTRACT FUNCTION SELECTOR + Felt252::from(1), // CONTRACT_CALLDATA LEN + Felt252::from(2), // CONTRACT_CALLDATA + ]; + let max_fee = 3; + let actual_fee = 2490; + let invoke_tx = invoke_tx(calldata, max_fee); + + // Extract invoke transaction fields for testing, as it is consumed when creating an account + // transaction. + let result = invoke_tx.execute(state, block_context, 0).unwrap(); + let mut expected_result = expected_transaction_execution_info(block_context).to_revert_error( + format!( + "Calculated fee ({}) exceeds max fee ({})", + actual_fee, max_fee + ) + .as_str(), + ); + expected_result.set_fee_info(max_fee, Some(expected_fee_transfer_info(max_fee))); + + assert_eq_sorted!(result, expected_result); + + // Check final balance + let test_erc20_address = block_context + .starknet_os_config() + .fee_token_address() + .clone(); + let test_erc20_account_balance_key = TEST_ERC20_ACCOUNT_BALANCE_KEY.clone(); + + let balance = state + .get_storage_at(&( + test_erc20_address, + felt_to_hash(&test_erc20_account_balance_key), + )) + .unwrap(); + let expected_balance = INITIAL_BALANCE.clone() - Felt252::from(max_fee); + + assert_eq!(balance, expected_balance); } #[test] @@ -1354,7 +1392,7 @@ fn test_invoke_tx_state() { Felt252::from(1), // CONTRACT_CALLDATA LEN Felt252::from(2), // CONTRACT_CALLDATA ]; - let invoke_tx = invoke_tx(calldata); + let invoke_tx = invoke_tx(calldata, u128::MAX); let result = invoke_tx .execute(state, starknet_general_context, 0) @@ -1437,7 +1475,7 @@ fn test_invoke_with_declarev2_tx() { Felt252::from(0), // b Felt252::from(0), // n ]; - let invoke_tx = invoke_tx(calldata); + let invoke_tx = invoke_tx(calldata, u128::MAX); let expected_gas_consumed = 4908; let result = invoke_tx @@ -1445,7 +1483,7 @@ fn test_invoke_with_declarev2_tx() { .unwrap(); let expected_execution_info = expected_fib_transaction_execution_info(block_context); - assert_eq!(result, expected_execution_info); + assert_eq_sorted!(result, expected_execution_info); } #[test] @@ -1486,7 +1524,8 @@ fn test_deploy_account() { .execute(&mut state, &block_context) .unwrap(); - assert_eq!(state.cache(), state_after.cache()); + use pretty_assertions_sorted::assert_eq_sorted; + assert_eq_sorted!(state.cache(), state_after.cache()); let expected_validate_call_info = expected_validate_call_info( VALIDATE_DEPLOY_ENTRY_POINT_SELECTOR.clone(), @@ -1557,6 +1596,155 @@ fn test_deploy_account() { assert_eq!(class_hash_from_state, *deploy_account_tx.class_hash()); } +#[test] +fn test_deploy_account_revert() { + let (block_context, mut state) = create_account_tx_test_state().unwrap(); + + let expected_fee = 1; + + let deploy_account_tx = DeployAccount::new( + felt_to_hash(&TEST_ACCOUNT_CONTRACT_CLASS_HASH), + 1, + TRANSACTION_VERSION.clone(), + Default::default(), + Default::default(), + Default::default(), + Default::default(), + StarknetChainId::TestNet.to_felt(), + ) + .unwrap(); + + state.set_storage_at( + &( + block_context + .starknet_os_config() + .fee_token_address() + .clone(), + felt_to_hash(&TEST_ERC20_DEPLOYED_ACCOUNT_BALANCE_KEY), + ), + INITIAL_BALANCE.clone(), + ); + + let (state_before, mut state_after) = expected_deploy_account_states(); + + assert_eq_sorted!(&state.cache(), &state_before.cache()); + assert_eq_sorted!(&state.contract_classes(), &state_before.contract_classes()); + assert!(&state.contract_classes().is_empty()); + + let tx_info = deploy_account_tx + .execute(&mut state, &block_context) + .unwrap(); + + assert!(tx_info.revert_error.is_some()); + + let mut state_reverted = state_before; + + // Add initial writes (these 'bypass' the transactional state because it's a state reader and + // it will cache initial values when looking for them). + state_reverted + .cache_mut() + .class_hash_initial_values_mut() + .extend( + state_after + .cache_mut() + .class_hash_initial_values_mut() + .clone(), + ); + state_reverted + .cache_mut() + .nonce_initial_values_mut() + .extend(state_after.cache_mut().nonce_initial_values_mut().clone()); + state_reverted + .cache_mut() + .storage_initial_values_mut() + .extend(state_after.cache_mut().storage_initial_values_mut().clone()); + state_reverted + .cache_mut() + .storage_initial_values_mut() + .extend(state_after.cache_mut().storage_initial_values_mut().clone()); + + // Set contract class cache + state_reverted + .set_contract_classes(state_after.contract_classes().clone()) + .unwrap(); + + // Set storage writes related to the fee transfer + state_reverted + .cache_mut() + .storage_writes_mut() + .extend(state_after.cache_mut().storage_writes().clone()); + state_reverted.set_storage_at( + &( + Address(0x1001.into()), + felt_to_hash(&TEST_ERC20_DEPLOYED_ACCOUNT_BALANCE_KEY), + ), + INITIAL_BALANCE.clone() - Felt252::one(), // minus the max fee that will be transfered + ); + state_reverted.cache_mut().storage_writes_mut().insert( + ( + Address(0x1001.into()), + felt_to_hash(&TEST_ERC20_SEQUENCER_BALANCE_KEY), + ), + Felt252::one(), // the max fee received by the sequencer + ); + + // Set nonce + state_reverted + .cache_mut() + .nonce_writes_mut() + .extend(state_after.cache_mut().nonce_writes_mut().clone()); + + assert_eq_sorted!(state.cache(), state_reverted.cache()); + + let expected_fee_transfer_call_info = expected_fee_transfer_call_info( + &block_context, + deploy_account_tx.contract_address(), + expected_fee, + ); + + let resources = HashMap::from([ + ("n_steps".to_string(), 3625), + ("range_check_builtin".to_string(), 83), + ("pedersen_builtin".to_string(), 23), + ("l1_gas_usage".to_string(), 3672), + ]); + + let fee = calculate_tx_fee(&resources, *GAS_PRICE, &block_context).unwrap(); + + assert_eq!(fee, 3709); + + let mut expected_execution_info = TransactionExecutionInfo::new( + None, + None, + None, + None, + expected_fee, + // Entry **not** in blockifier. + // Default::default(), + resources, + TransactionType::DeployAccount.into(), + ) + .to_revert_error(format!("Calculated fee ({}) exceeds max fee ({})", fee, 1).as_str()); + + expected_execution_info.set_fee_info(expected_fee, expected_fee_transfer_call_info.into()); + + assert_eq_sorted!(tx_info, expected_execution_info); + + let nonce_from_state = state + .get_nonce_at(deploy_account_tx.contract_address()) + .unwrap(); + assert_eq!(nonce_from_state, Felt252::one()); + + let hash = TEST_ERC20_DEPLOYED_ACCOUNT_BALANCE_KEY.to_be_bytes(); + + validate_final_balances(&mut state, &block_context, &hash, expected_fee); + + let class_hash_from_state = state + .get_class_hash_at(deploy_account_tx.contract_address()) + .unwrap(); + assert_eq!(class_hash_from_state, [0; 32]); +} + fn expected_deploy_account_states() -> ( CachedState, CachedState, @@ -1623,15 +1811,6 @@ fn expected_deploy_account_states() -> ( .cache_mut() .class_hash_initial_values_mut() .insert(Address(0x1001.into()), felt_to_hash(&0x1010.into())); - state_after - .cache_mut() - .class_hash_initial_values_mut() - .insert( - Address(felt_str!( - "386181506763903095743576862849245034886954647214831045800703908858571591162" - )), - [0; 32], - ); state_after.cache_mut().storage_initial_values_mut().insert( ( Address(0x1001.into()), @@ -1655,13 +1834,7 @@ fn expected_deploy_account_states() -> ( ), Felt252::zero(), ); - state_after.cache_mut().storage_initial_values_mut().insert( - ( - Address(0x1001.into()), - felt_to_hash(&TEST_ERC20_DEPLOYED_ACCOUNT_BALANCE_KEY), - ), - Felt252::zero(), - ); + state_after.cache_mut().nonce_writes_mut().insert( Address(felt_str!( "386181506763903095743576862849245034886954647214831045800703908858571591162" @@ -1917,7 +2090,7 @@ fn test_invoke_tx_wrong_call_data() { Felt252::from(1), // CONTRACT_CALLDATA LEN // CONTRACT_CALLDATA ]; - let invoke_tx = invoke_tx(calldata); + let invoke_tx = invoke_tx(calldata, u128::MAX); // Execute transaction let result = invoke_tx.execute(state, starknet_general_context, 0); From bdaaa956b7acc8ac3395885fddd480b3bbdb6375 Mon Sep 17 00:00:00 2001 From: Juan Bono Date: Wed, 13 Sep 2023 14:55:39 -0300 Subject: [PATCH 33/44] fix get_sorted_events issue (#1024) * add failing test that reproduce the issue * fix the bug * fix test since now 2 events with the same order are ok * handle multiple events * fix comments * cargo fmt --- rpc_state_reader/tests/sir_tests.rs | 35 ++++++++++++++ src/execution/mod.rs | 74 ++++++++++++++++++----------- 2 files changed, 81 insertions(+), 28 deletions(-) diff --git a/rpc_state_reader/tests/sir_tests.rs b/rpc_state_reader/tests/sir_tests.rs index 4550f202e..d8eadde65 100644 --- a/rpc_state_reader/tests/sir_tests.rs +++ b/rpc_state_reader/tests/sir_tests.rs @@ -262,6 +262,7 @@ fn starknet_in_rust_test_case_tx(hash: &str, block_number: u64, chain: RpcChain) .. } = call_info.unwrap(); + // check Cairo VM execution resources assert_eq_sorted!( execution_resources, trace @@ -271,6 +272,8 @@ fn starknet_in_rust_test_case_tx(hash: &str, block_number: u64, chain: RpcChain) .execution_resources, "execution resources mismatch" ); + + // check amount of internal calls assert_eq!( internal_calls.len(), trace @@ -282,6 +285,7 @@ fn starknet_in_rust_test_case_tx(hash: &str, block_number: u64, chain: RpcChain) "internal calls length mismatch" ); + // check actual fee calculation if receipt.actual_fee != actual_fee { let diff = 100 * receipt.actual_fee.abs_diff(actual_fee) / receipt.actual_fee; @@ -294,6 +298,37 @@ fn starknet_in_rust_test_case_tx(hash: &str, block_number: u64, chain: RpcChain) } } +#[test_case( + "0x01e91fa12be4424264c8cad29f481a67d5d8e23f7abf94add734d64b91c90021", + RpcChain::MainNet, + 219797, + 7 +)] +#[test_case( + "0x03ec45f8369513b0f48db25f2cf18c70c50e7d3119505ab15e39ae4ca2eb06cf", + RpcChain::MainNet, + 219764, + 7 +)] +#[test_case( + "0x00164bfc80755f62de97ae7c98c9d67c1767259427bcf4ccfcc9683d44d54676", + RpcChain::MainNet, + 197000, + 3 +)] +fn test_sorted_events( + tx_hash: &str, + chain: RpcChain, + block_number: u64, + expected_amount_of_events: usize, +) { + let (tx_info, _trace, _receipt) = execute_tx(tx_hash, chain, BlockNumber(block_number)); + + let events_len = tx_info.get_sorted_events().unwrap().len(); + + assert_eq!(expected_amount_of_events, events_len); +} + #[test_case( "0x00b6d59c19d5178886b4c939656167db0660fe325345138025a3cc4175b21897", 200303, // real block 200304 diff --git a/src/execution/mod.rs b/src/execution/mod.rs index 8de60b7e2..9fed18a67 100644 --- a/src/execution/mod.rs +++ b/src/execution/mod.rs @@ -104,48 +104,64 @@ impl CallInfo { ) } - /// Yields the contract calls in DFS (preorder). + /// Returns the contract calls in DFS (preorder). pub fn gen_call_topology(&self) -> Vec { let mut calls = Vec::new(); - if self.internal_calls.is_empty() { - calls.push(self.clone()) - } else { - calls.push(self.clone()); - for call_info in self.internal_calls.clone() { - calls.extend(call_info.gen_call_topology()); + // add the current call + calls.push(self.clone()); + + // if it has internal calls we need to add them too. + if !self.internal_calls.is_empty() { + for inner_call in self.internal_calls.clone() { + calls.extend(inner_call.gen_call_topology()); } } + calls } - /// Returns a list of Starknet Event objects collected during the execution, sorted by the order + /// Returns a list of [`Event`] objects collected during the execution, sorted by the order /// in which they were emitted. pub fn get_sorted_events(&self) -> Result, TransactionError> { + // collect a vector of the full call topology (all the internal + // calls performed during the current call) let calls = self.gen_call_topology(); - let n_events = calls.iter().fold(0, |acc, c| acc + c.events.len()); - - let mut starknet_events: Vec> = (0..n_events).map(|_| None).collect(); - - for call in calls { - for ordered_event in call.events { - let event = Event::new(ordered_event.clone(), call.contract_address.clone()); - starknet_events.remove((ordered_event.order as isize - 1).max(0) as usize); - starknet_events.insert( - (ordered_event.order as isize - 1).max(0) as usize, - Some(event), - ); + let mut collected_events = Vec::new(); + + // for each call, collect its ordered events + for c in calls { + collected_events.extend( + c.events + .iter() + .map(|oe| (oe.clone(), c.contract_address.clone())), + ); + } + // sort the collected events using the ordering given by the order + collected_events.sort_by_key(|(oe, _)| oe.order); + + // check that there is no holes. + // since it is already sorted, we only need to check for continuity + let mut i = 0; + for (oe, _) in collected_events.iter() { + if i == oe.order { + continue; + } + i += 1; + if i != oe.order { + return Err(TransactionError::UnexpectedHolesInEventOrder); } } - let are_all_some = starknet_events.iter().all(|e| e.is_some()); - - if !are_all_some { - return Err(TransactionError::UnexpectedHolesInEventOrder); - } - Ok(starknet_events.into_iter().flatten().collect()) + // now that it is ordered and without holes, we can discard the order and + // convert each [`OrderedEvent`] to the underlying [`Event`]. + let collected_events = collected_events + .into_iter() + .map(|(oe, ca)| Event::new(oe, ca)) + .collect(); + Ok(collected_events) } - /// Returns a list of Starknet L2ToL1MessageInfo objects collected during the execution, sorted + /// Returns a list of L2ToL1MessageInfo objects collected during the execution, sorted /// by the order in which they were sent. pub fn get_sorted_l2_to_l1_messages(&self) -> Result, TransactionError> { let calls = self.gen_call_topology(); @@ -586,6 +602,8 @@ impl TransactionExecutionInfo { }) } + /// Returns an ordered vector with all the event emitted during the transaction. + /// Including the ones emitted by internal calls. pub fn get_sorted_events(&self) -> Result, TransactionError> { let calls = self.non_optional_calls(); let mut sorted_events: Vec = Vec::new(); @@ -838,7 +856,7 @@ mod tests { call_root.internal_calls = [child1, child2].to_vec(); - assert!(call_root.get_sorted_events().is_err()) + assert!(call_root.get_sorted_events().is_ok()) } #[test] From 941a899ea315141b63b719cf63d49f5777462e45 Mon Sep 17 00:00:00 2001 From: Juan Bono Date: Wed, 13 Sep 2023 16:34:51 -0300 Subject: [PATCH 34/44] pin version (#1026) --- Cargo.lock | 14 ++------------ Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7b32171e6..da862e6b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3422,16 +3422,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_json_pythonic" -version = "0.1.2" -source = "git+https://github.com/xJonathanLEI/serde_json_pythonic?tag=v0.1.2#4e4b08bab95309be8672b4efd346bea900040e15" -dependencies = [ - "itoa", - "ryu", - "serde", -] - [[package]] name = "serde_spanned" version = "0.6.3" @@ -3673,7 +3663,7 @@ dependencies = [ "hex", "serde", "serde_json", - "serde_json_pythonic 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json_pythonic", "serde_with 2.3.3", "sha3", "starknet-crypto 0.6.0", @@ -3871,7 +3861,7 @@ dependencies = [ "pretty_assertions_sorted", "serde", "serde_json", - "serde_json_pythonic 0.1.2 (git+https://github.com/xJonathanLEI/serde_json_pythonic?tag=v0.1.2)", + "serde_json_pythonic", "sha3", "starknet", "starknet-crypto 0.5.1", diff --git a/Cargo.toml b/Cargo.toml index 542716fc7..cd74f9316 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,7 @@ once_cell = "1.17.1" starknet = { workspace = true } base64 = { version = "0.21.0", default-features = false, features = ["alloc"] } flate2 = "1.0.25" -serde_json_pythonic = { git = "https://github.com/xJonathanLEI/serde_json_pythonic", tag = "v0.1.2"} +serde_json_pythonic = "0.1.2" [dev-dependencies] assert_matches = "1.5.0" From 2e7ee5253cbdb482353827b6336b855d430284d2 Mon Sep 17 00:00:00 2001 From: Juan Bono Date: Wed, 13 Sep 2023 17:42:33 -0300 Subject: [PATCH 35/44] update version (#1028) --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- cli/Cargo.toml | 4 ++-- fuzzer/Cargo.toml | 4 ++-- rpc_state_reader/Cargo.toml | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index da862e6b4..9cc3dedf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1899,7 +1899,7 @@ dependencies = [ [[package]] name = "fuzzer" -version = "0.3.1" +version = "0.4.0" dependencies = [ "cairo-vm", "honggfuzz", @@ -3159,7 +3159,7 @@ dependencies = [ [[package]] name = "rpc_state_reader" -version = "0.3.1" +version = "0.4.0" dependencies = [ "blockifier", "cairo-lang-starknet", @@ -3786,7 +3786,7 @@ dependencies = [ [[package]] name = "starknet-rs-cli" -version = "0.3.1" +version = "0.4.0" dependencies = [ "actix-web", "assert_matches", @@ -3836,7 +3836,7 @@ dependencies = [ [[package]] name = "starknet_in_rust" -version = "0.3.1" +version = "0.4.0" dependencies = [ "anyhow", "assert_matches", diff --git a/Cargo.toml b/Cargo.toml index cd74f9316..9de35d9a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet_in_rust" -version = "0.3.1" +version = "0.4.0" edition = "2021" description = "A Rust implementation of Starknet execution logic" license = "Apache-2.0" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 2f4c631d3..cd1114021 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-rs-cli" -version = "0.3.1" +version = "0.4.0" edition = "2021" [features] @@ -8,7 +8,7 @@ default = ["with_mimalloc"] with_mimalloc = ["dep:mimalloc"] [dependencies] -starknet_in_rust = { path = "../", version = "0.3.1" } +starknet_in_rust = { path = "../", version = "0.4.0" } num-traits = "0.2.15" serde = { version = "1.0.152", features = ["derive"] } cairo-vm = { workspace = true, features = ["cairo-1-hints"] } diff --git a/fuzzer/Cargo.toml b/fuzzer/Cargo.toml index ea96a2b30..32cc2fd6f 100644 --- a/fuzzer/Cargo.toml +++ b/fuzzer/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "fuzzer" -version = "0.3.1" +version = "0.4.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] honggfuzz = "0.5.55" -starknet_in_rust = { path = "../", version = "0.3.1" } +starknet_in_rust = { path = "../", version = "0.4.0" } num-traits = { workspace = true } starknet_api = { workspace = true } serde_json = { version = "1.0", features = ["arbitrary_precision"] } diff --git a/rpc_state_reader/Cargo.toml b/rpc_state_reader/Cargo.toml index e539d89c5..370ee93d4 100644 --- a/rpc_state_reader/Cargo.toml +++ b/rpc_state_reader/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rpc_state_reader" -version = "0.3.1" +version = "0.4.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -22,7 +22,7 @@ serde_with = "3.0.0" dotenv = "0.15.0" cairo-vm = "0.8.5" blockifier = "0.2.0-rc0" -starknet_in_rust = { path = "../", version = "0.3.1" } +starknet_in_rust = { path = "../", version = "0.4.0" } [dev-dependencies] pretty_assertions_sorted = "1.2.3" From b8640a0cb0faac0a4b4ec9eef7f6d75da4aaffbc Mon Sep 17 00:00:00 2001 From: MrAzteca Date: Mon, 18 Sep 2023 18:20:13 +0200 Subject: [PATCH 36/44] Fix coverage control mechanism. (#1035) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- cli/Cargo.toml | 2 +- src/lib.rs | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9cc3dedf9..6be0d80bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1426,9 +1426,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "coverage-helper" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9db510e477cf3c14a6c56aa2ed28e499f1e27e01c17723b41ece793d11cf3fe" +checksum = "3036399e8abfc9d696c1ee94f7677f9704e903d96299b0026e339eed6055dcaf" [[package]] name = "cpufeatures" diff --git a/Cargo.toml b/Cargo.toml index 9de35d9a5..aa277e89c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,7 +60,7 @@ serde_json_pythonic = "0.1.2" [dev-dependencies] assert_matches = "1.5.0" -coverage-helper = "0.1.0" +coverage-helper = "0.2.0" pretty_assertions_sorted = "1.2.3" [[bench]] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index cd1114021..221de3cb5 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -19,4 +19,4 @@ mimalloc = { version = "0.1.29", default-features = false, optional = true } [dev-dependencies] assert_matches = "1.5.0" -coverage-helper = "0.1.0" +coverage-helper = "0.2.0" diff --git a/src/lib.rs b/src/lib.rs index d5878d3d0..6af73ef40 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![deny(warnings)] #![forbid(unsafe_code)] -#![cfg_attr(coverage_nightly, feature(no_coverage))] +#![cfg_attr(coverage_nightly, feature(coverage_attribute))] + use std::{collections::HashMap, sync::Arc}; use crate::{ From 4eef09bf8662c3953e22c788a0d96c855285d864 Mon Sep 17 00:00:00 2001 From: Juan Bono Date: Mon, 18 Sep 2023 15:02:47 -0300 Subject: [PATCH 37/44] Fix SIR RPC get compiled class hash (#1032) * update version * fix get_compiled_hash * cargo clippy --- rpc_state_reader/src/rpc_state.rs | 3 ++- rpc_state_reader/tests/sir_tests.rs | 14 +++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/rpc_state_reader/src/rpc_state.rs b/rpc_state_reader/src/rpc_state.rs index b2d0f8149..3ff561339 100644 --- a/rpc_state_reader/src/rpc_state.rs +++ b/rpc_state_reader/src/rpc_state.rs @@ -284,7 +284,8 @@ impl RpcState { "params": params, "id": 1 }); - Self::deserialize_call(self.rpc_call_no_deserialize(&payload)?.into_json().unwrap()) + let response = self.rpc_call_no_deserialize(&payload)?.into_json().unwrap(); + Self::deserialize_call(response) } fn rpc_call_no_deserialize( diff --git a/rpc_state_reader/tests/sir_tests.rs b/rpc_state_reader/tests/sir_tests.rs index d8eadde65..75e75595b 100644 --- a/rpc_state_reader/tests/sir_tests.rs +++ b/rpc_state_reader/tests/sir_tests.rs @@ -66,6 +66,7 @@ impl StateReader for RpcStateReader { let nonce = self.0.get_nonce_at(&address); Ok(Felt252::from_bytes_be(nonce.bytes())) } + fn get_storage_at(&self, storage_entry: &StorageEntry) -> Result { let (contract_address, key) = storage_entry; let address = ContractAddress( @@ -78,12 +79,9 @@ impl StateReader for RpcStateReader { let value = self.0.get_storage_at(&address, &key); Ok(Felt252::from_bytes_be(value.bytes())) } + fn get_compiled_class_hash(&self, class_hash: &ClassHash) -> Result<[u8; 32], StateError> { - let address = - ContractAddress(PatriciaKey::try_from(StarkHash::new(*class_hash).unwrap()).unwrap()); - let mut bytes = [0u8; 32]; - bytes.copy_from_slice(self.0.get_class_hash_at(&address).0.bytes()); - Ok(bytes) + Ok(*class_hash) } } @@ -298,6 +296,12 @@ fn starknet_in_rust_test_case_tx(hash: &str, block_number: u64, chain: RpcChain) } } +#[test_case( + "0x05b4665a81d89d00e529d2e298fce6606750c4f67faf43aafc893c0fc0f9d425", + RpcChain::MainNet, + 222090, + 4 +)] #[test_case( "0x01e91fa12be4424264c8cad29f481a67d5d8e23f7abf94add734d64b91c90021", RpcChain::MainNet, From 62c3b20e9e4e701f88b8238735c118c4bb4c7261 Mon Sep 17 00:00:00 2001 From: Edgar Date: Mon, 18 Sep 2023 20:02:59 +0200 Subject: [PATCH 38/44] remove unneeded added set_compiled_class_hash (#1031) Co-authored-by: Juan Bono --- src/transaction/declare_v2.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/transaction/declare_v2.rs b/src/transaction/declare_v2.rs index cfc400186..0faa548b8 100644 --- a/src/transaction/declare_v2.rs +++ b/src/transaction/declare_v2.rs @@ -375,9 +375,7 @@ impl DeclareV2 { )); } state.set_compiled_class_hash(&self.sierra_class_hash, &self.compiled_class_hash)?; - // theorically class_hash == compiled_class_hash in v2, so this is like setting class_hash -> compiled_class_hash - // which is needed for get_compiled_class_hash later to work. - state.set_compiled_class_hash(&self.compiled_class_hash, &self.compiled_class_hash)?; + state.set_contract_class( &self.compiled_class_hash.to_be_bytes(), &CompiledClass::Casm(Arc::new(casm_class)), From d4fcd9d4ab8c5615e9224152e53fcef0e0f5e492 Mon Sep 17 00:00:00 2001 From: Edgar Date: Mon, 18 Sep 2023 20:08:30 +0200 Subject: [PATCH 39/44] Fix missing events (#1034) * remove unneeded added set_compiled_class_hash * fix missing events when using deprecated business syscall handler --------- Co-authored-by: Juan Bono --- .../deprecated_business_logic_syscall_handler.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/syscalls/deprecated_business_logic_syscall_handler.rs b/src/syscalls/deprecated_business_logic_syscall_handler.rs index 6f8108de4..8b1ae1d36 100644 --- a/src/syscalls/deprecated_business_logic_syscall_handler.rs +++ b/src/syscalls/deprecated_business_logic_syscall_handler.rs @@ -244,6 +244,8 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { ); self.internal_calls.push(call_info); + // Empty call info doesn't have events, so there is no need to push them here to `self.events` + return Ok(()); } @@ -258,7 +260,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { INITIAL_GAS_COST, ); - let _call_info = call + let call_info = call .execute( self.starknet_storage_state.state, &self.block_context, @@ -268,6 +270,11 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { self.block_context.invoke_tx_max_n_steps, ) .map_err(|_| StateError::ExecutionEntryPoint())?; + + if let Some(call_info) = call_info.call_info { + self.events.extend(call_info.events); + } + Ok(()) } } From 7ec549434edab5f171e6036a9c69bbcd8cc4e475 Mon Sep 17 00:00:00 2001 From: Edgar Date: Wed, 20 Sep 2023 15:35:27 +0200 Subject: [PATCH 40/44] fix wrong from_address in deprecated execute_constructor_entry_point (#1041) * fix wrong from_address in deprecated execute_constructor_entry_point * fix test * fix another test --- ...precated_business_logic_syscall_handler.rs | 2 +- tests/syscalls.rs | 202 +++++++++++------- 2 files changed, 129 insertions(+), 75 deletions(-) diff --git a/src/syscalls/deprecated_business_logic_syscall_handler.rs b/src/syscalls/deprecated_business_logic_syscall_handler.rs index 8b1ae1d36..a8857addd 100644 --- a/src/syscalls/deprecated_business_logic_syscall_handler.rs +++ b/src/syscalls/deprecated_business_logic_syscall_handler.rs @@ -272,7 +272,7 @@ impl<'a, S: StateReader> DeprecatedBLSyscallHandler<'a, S> { .map_err(|_| StateError::ExecutionEntryPoint())?; if let Some(call_info) = call_info.call_info { - self.events.extend(call_info.events); + self.internal_calls.push(call_info); } Ok(()) diff --git a/tests/syscalls.rs b/tests/syscalls.rs index 6672c7d5e..17fbda146 100644 --- a/tests/syscalls.rs +++ b/tests/syscalls.rs @@ -10,6 +10,7 @@ use cairo_vm::{ }, }; use num_traits::{Num, One, Zero}; +use pretty_assertions_sorted::{assert_eq, assert_eq_sorted}; use starknet_in_rust::{ definitions::{ block_context::{BlockContext, StarknetChainId}, @@ -170,8 +171,8 @@ fn test_contract<'a>( accessed_storage_keys.collect() ); assert_eq!(result.calldata, calldata); - assert_eq!(result.retdata, return_data.into()); - assert_eq!(result.internal_calls, internal_calls.into()); + assert_eq_sorted!(result.retdata, return_data.into()); + assert_eq_sorted!(result.internal_calls, internal_calls.into()); assert_eq!(result.execution_resources, execution_resources); assert_eq!(result.gas_consumed, 0); @@ -906,13 +907,20 @@ fn deploy_with_constructor_syscall() { 10, ) .unwrap(); + let entry_point_selector = Felt252::from_str_radix( + "1159040026212278395030414237414753050475174923702621880048416706425641521556", + 10, + ) + .unwrap(); let deploy_class_hash = [2u8; 32]; + let caller_address = Address(11111.into()); + test_contract( "starknet_programs/syscalls.json", "test_deploy_with_constructor", [1; 32], - Address(11111.into()), + caller_address.clone(), Address(0.into()), BlockContext::default(), None, @@ -931,7 +939,26 @@ fn deploy_with_constructor_syscall() { 0.into(), 550.into(), ], - [], + [CallInfo { + caller_address, + call_type: Some(CallType::Call), + contract_address: Address(deploy_address.clone()), + class_hash: Some(deploy_class_hash), + entry_point_selector: Some(entry_point_selector), + entry_point_type: Some(EntryPointType::Constructor), + calldata: [550.into()].to_vec(), + execution_resources: ExecutionResources { + n_steps: 40, + n_memory_holes: 0, + ..Default::default() + }, + accessed_storage_keys: HashSet::<[u8; 32]>::from([[ + 2, 63, 76, 85, 114, 157, 43, 172, 36, 175, 107, 126, 158, 121, 114, 77, 194, 27, + 162, 147, 169, 199, 107, 53, 94, 246, 206, 221, 169, 114, 215, 255, + ]]), + storage_read_values: [0.into()].to_vec(), + ..Default::default() + }], [deploy_address], ExecutionResources { n_steps: 84, @@ -982,86 +1009,113 @@ fn test_deploy_and_call_contract_syscall() { new_constant.clone(), ], [ - // Invoke storage_var_and_constructor.cairo mult_constant function - CallInfo { - caller_address: Address(11111.into()), - call_type: Some(CallType::Call), - contract_address: deploy_address.clone(), - code_address: None, - class_hash: Some(deploy_class_hash), - entry_point_selector: Some( - Felt252::from_str_radix( - "1576037374104670872807053137865113122553607263175471701007015754752102201893", - 10, - ) - .unwrap(), - ), - entry_point_type: Some(EntryPointType::External), - calldata: vec![4.into()], - retdata: vec![(constructor_constant.clone() * Felt252::new(4))], - storage_read_values: vec![constructor_constant.clone()], - accessed_storage_keys: HashSet::from([constant_storage_key]), - execution_resources: ExecutionResources { - n_steps: 52, + // constructor + CallInfo { + caller_address: Address(11111.into()), + call_type: Some(CallType::Call), + contract_address: deploy_address.clone(), + code_address: None, + class_hash: Some(deploy_class_hash), + entry_point_selector: Some( + Felt252::from_str_radix( + "1159040026212278395030414237414753050475174923702621880048416706425641521556", + 10, + ) + .unwrap(), + ), + entry_point_type: Some(EntryPointType::Constructor), + calldata: vec![550.into()], + retdata: vec![], + storage_read_values: vec![0.into()], + accessed_storage_keys: HashSet::from([constant_storage_key]), + execution_resources: ExecutionResources { + n_steps: 40, + ..Default::default() + }, ..Default::default() }, - ..Default::default() - }, - // Invoke storage_var_and_constructor.cairo set_constant function - CallInfo { - caller_address: Address(11111.into()), - call_type: Some(CallType::Call), - contract_address: deploy_address.clone(), - code_address: None, - class_hash: Some(deploy_class_hash), - entry_point_selector: Some( - Felt252::from_str_radix( - "1201037417712951658445715615949920673423990292207294106968654696818998525373", - 10, - ) - .unwrap(), - ), - entry_point_type: Some(EntryPointType::External), - calldata: vec![new_constant.clone()], - retdata: vec![], - storage_read_values: vec![constructor_constant], - accessed_storage_keys: HashSet::from([constant_storage_key]), - execution_resources: ExecutionResources { - n_steps: 40, + // Invoke storage_var_and_constructor.cairo mult_constant function + CallInfo { + caller_address: Address(11111.into()), + call_type: Some(CallType::Call), + contract_address: deploy_address.clone(), + code_address: None, + class_hash: Some(deploy_class_hash), + entry_point_selector: Some( + Felt252::from_str_radix( + "1576037374104670872807053137865113122553607263175471701007015754752102201893", + 10, + ) + .unwrap(), + ), + entry_point_type: Some(EntryPointType::External), + calldata: vec![4.into()], + retdata: vec![(constructor_constant.clone() * Felt252::new(4))], + storage_read_values: vec![constructor_constant.clone()], + accessed_storage_keys: HashSet::from([constant_storage_key]), + execution_resources: ExecutionResources { + n_steps: 52, + ..Default::default() + }, ..Default::default() }, - ..Default::default() - }, - // Invoke storage_var_and_constructor.cairo get_constant function - CallInfo { - caller_address: Address(11111.into()), - call_type: Some(CallType::Call), - contract_address: deploy_address, - code_address: None, - class_hash: Some(deploy_class_hash), - entry_point_selector: Some( - Felt252::from_str_radix( - "915547745133109687566886827729966789818200062539892992518817034473866315209", - 10, - ) - .unwrap(), - ), - entry_point_type: Some(EntryPointType::External), - calldata: vec![], - retdata: vec![new_constant.clone()], - storage_read_values: vec![new_constant.clone()], - accessed_storage_keys: HashSet::from([constant_storage_key]), - execution_resources: ExecutionResources { - n_steps: 46, + // Invoke storage_var_and_constructor.cairo set_constant function + CallInfo { + caller_address: Address(11111.into()), + call_type: Some(CallType::Call), + contract_address: deploy_address.clone(), + code_address: None, + class_hash: Some(deploy_class_hash), + entry_point_selector: Some( + Felt252::from_str_radix( + "1201037417712951658445715615949920673423990292207294106968654696818998525373", + 10, + ) + .unwrap(), + ), + entry_point_type: Some(EntryPointType::External), + calldata: vec![new_constant.clone()], + retdata: vec![], + storage_read_values: vec![constructor_constant], + accessed_storage_keys: HashSet::from([constant_storage_key]), + execution_resources: ExecutionResources { + n_steps: 40, + ..Default::default() + }, ..Default::default() }, - ..Default::default() - } ], + // Invoke storage_var_and_constructor.cairo get_constant function + CallInfo { + caller_address: Address(11111.into()), + call_type: Some(CallType::Call), + contract_address: deploy_address, + code_address: None, + class_hash: Some(deploy_class_hash), + entry_point_selector: Some( + Felt252::from_str_radix( + "915547745133109687566886827729966789818200062539892992518817034473866315209", + 10, + ) + .unwrap(), + ), + entry_point_type: Some(EntryPointType::External), + calldata: vec![], + retdata: vec![new_constant.clone()], + storage_read_values: vec![new_constant.clone()], + accessed_storage_keys: HashSet::from([constant_storage_key]), + execution_resources: ExecutionResources { + n_steps: 46, + ..Default::default() + }, + ..Default::default() + } + ], [new_constant], ExecutionResources { n_steps: 325, n_memory_holes: 2, - builtin_instance_counter: HashMap::default()}, + builtin_instance_counter: HashMap::default() + }, ); } From 7c1c1e608e8126535f1d4f4297f2392184ebf22f Mon Sep 17 00:00:00 2001 From: Edgar Date: Thu, 21 Sep 2023 18:06:18 +0200 Subject: [PATCH 41/44] remove testing, move erc20 test, update fibonacci bin (#1038) Co-authored-by: Juan Bono --- examples/contract_execution/main.rs | 100 ++- src/bin/deploy.rs | 42 +- src/bin/deploy_invoke.rs | 109 ++- src/bin/fibonacci.rs | 145 ++-- src/bin/invoke.rs | 93 +-- src/lib.rs | 9 +- ...ch_integration.cpython-39-pytest-7.2.1.pyc | Bin 936 -> 0 bytes src/testing/bench_integration.rs | 101 --- src/testing/mod.rs | 165 ---- src/testing/state.rs | 733 ------------------ src/testing/state_error.rs | 20 - src/testing/type_utils.rs | 25 - src/utils.rs | 164 ++++ .../complex_contracts}/erc20.rs | 44 +- tests/complex_contracts/mod.rs | 1 + 15 files changed, 498 insertions(+), 1253 deletions(-) delete mode 100644 src/testing/__pycache__/bench_integration.cpython-39-pytest-7.2.1.pyc delete mode 100644 src/testing/bench_integration.rs delete mode 100644 src/testing/mod.rs delete mode 100644 src/testing/state.rs delete mode 100644 src/testing/state_error.rs delete mode 100644 src/testing/type_utils.rs rename {src/testing => tests/complex_contracts}/erc20.rs (85%) diff --git a/examples/contract_execution/main.rs b/examples/contract_execution/main.rs index b735362d4..2e6e21086 100644 --- a/examples/contract_execution/main.rs +++ b/examples/contract_execution/main.rs @@ -11,18 +11,24 @@ use cairo_vm::felt::Felt252; use starknet_in_rust::{ - services::api::contract_classes::deprecated_contract_class::ContractClass, - testing::state::StarknetState, + definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, + state::{ + cached_state::CachedState, in_memory_state_reader::InMemoryStateReader, state_api::State, + }, + transaction::{Declare, Deploy, InvokeFunction, Transaction}, utils::{calculate_sn_keccak, Address}, }; -use std::path::Path; +use std::{collections::HashMap, path::Path, sync::Arc}; fn main() { // replace this with the path to your compiled contract - let contract_path = "starknet_programs/factorial.json"; + let contract_path = "starknet_programs/fibonacci.json"; // replace this with the name of your entrypoint - let entry_point: &str = "factorial"; + let entry_point: &str = "fib"; // replace this with the arguments for the entrypoint let calldata: Vec = [1.into(), 1.into(), 10.into()].to_vec(); @@ -42,12 +48,21 @@ fn main() { fn test_contract( contract_path: impl AsRef, entry_point: &str, - calldata: Vec, + call_data: Vec, ) -> Vec { + //* -------------------------------------------- + //* Initialize needed variables + //* -------------------------------------------- + let block_context = BlockContext::default(); + let chain_id = block_context.starknet_os_config().chain_id().clone(); + let sender_address = Address(1.into()); + let signature = vec![]; + //* -------------------------------------------- //* Initialize state //* -------------------------------------------- - let mut state = StarknetState::new(None); + let state_reader = Arc::new(InMemoryStateReader::default()); + let mut state = CachedState::new(state_reader, HashMap::new()); //* -------------------------------------------- //* Read contract from file @@ -58,37 +73,74 @@ fn test_contract( //* -------------------------------------------- //* Declare new contract class //* -------------------------------------------- - state - .declare(contract_class.clone()) - .expect("Could not declare the contract class"); + let declare_tx = Declare::new( + contract_class.clone(), + chain_id.clone(), + sender_address, + 0, // max fee + 0.into(), + signature.clone(), + 0.into(), // nonce + ) + .expect("couldn't create declare transaction"); + + declare_tx + .execute(&mut state, &block_context) + .expect("could not declare the contract class"); //* -------------------------------------------- //* Deploy new contract class instance //* -------------------------------------------- - let (contract_address, _) = state - .deploy(contract_class, vec![], Default::default(), None, 0) - .expect("Could not deploy contract"); + + let deploy = Deploy::new( + Default::default(), // salt + contract_class.clone(), + vec![], // call data + block_context.starknet_os_config().chain_id().clone(), + TRANSACTION_VERSION.clone(), + ) + .unwrap(); + + state + .set_contract_class( + &deploy.contract_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) + .unwrap(); + let contract_address = deploy.contract_address.clone(); + + let tx = Transaction::Deploy(deploy); + + tx.execute(&mut state, &block_context, 0) + .expect("could not deploy contract"); //* -------------------------------------------- //* Execute contract entrypoint //* -------------------------------------------- let entry_point_selector = Felt252::from_bytes_be(&calculate_sn_keccak(entry_point.as_bytes())); - let caller_address = Address::default(); - - let callinfo = state - .execute_entry_point_raw( - contract_address, - entry_point_selector, - calldata, - caller_address, - ) - .expect("Could not execute entry point"); + let invoke_tx = InvokeFunction::new( + contract_address, + entry_point_selector, + 0, + TRANSACTION_VERSION.clone(), + call_data, + signature, + chain_id, + Some(0.into()), + ) + .unwrap(); + + let tx = Transaction::InvokeFunction(invoke_tx); + let tx_exec_info = tx.execute(&mut state, &block_context, 0).unwrap(); //* -------------------------------------------- //* Extract return values //* -------------------------------------------- - callinfo.retdata + tx_exec_info + .call_info + .expect("call info should exist") + .retdata } #[test] diff --git a/src/bin/deploy.rs b/src/bin/deploy.rs index 1b58d386a..f8ac4e455 100644 --- a/src/bin/deploy.rs +++ b/src/bin/deploy.rs @@ -1,7 +1,15 @@ +use std::{collections::HashMap, sync::Arc}; + use lazy_static::lazy_static; use starknet_in_rust::{ - services::api::contract_classes::deprecated_contract_class::ContractClass, - testing::state::StarknetState, + definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, + state::{ + cached_state::CachedState, in_memory_state_reader::InMemoryStateReader, state_api::State, + }, + transaction::{Deploy, Transaction}, }; #[cfg(feature = "with_mimalloc")] @@ -20,19 +28,33 @@ lazy_static! { fn main() { const RUNS: usize = 100; - let mut starknet_state = StarknetState::new(None); + + let block_context = BlockContext::default(); + let state_reader = Arc::new(InMemoryStateReader::default()); + + let mut state = CachedState::new(state_reader, HashMap::new()); + let call_data = vec![]; for n in 0..RUNS { let contract_address_salt = n.into(); - starknet_state - .deploy( - CONTRACT_CLASS.clone(), - vec![], - contract_address_salt, - None, - 0, + let deploy = Deploy::new( + contract_address_salt, + CONTRACT_CLASS.clone(), + call_data.clone(), + block_context.starknet_os_config().chain_id().clone(), + TRANSACTION_VERSION.clone(), + ) + .unwrap(); + + state + .set_contract_class( + &deploy.contract_hash, + &CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), ) .unwrap(); + let tx = Transaction::Deploy(deploy); + + tx.execute(&mut state, &block_context, 0).unwrap(); } } diff --git a/src/bin/deploy_invoke.rs b/src/bin/deploy_invoke.rs index 1036a6496..b35da65f9 100644 --- a/src/bin/deploy_invoke.rs +++ b/src/bin/deploy_invoke.rs @@ -1,11 +1,18 @@ -use std::path::PathBuf; +use std::{collections::HashMap, path::PathBuf, sync::Arc}; use cairo_vm::felt::{felt_str, Felt252}; use num_traits::Zero; use starknet_in_rust::{ - services::api::contract_classes::deprecated_contract_class::ContractClass, - testing::state::StarknetState, utils::Address, + definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, + state::{ + cached_state::CachedState, in_memory_state_reader::InMemoryStateReader, state_api::State, + }, + transaction::{Deploy, InvokeFunction, Transaction}, + utils::Address, }; use lazy_static::lazy_static; @@ -36,52 +43,76 @@ lazy_static! { fn main() { const RUNS: usize = 10000; - let mut starknet_state = StarknetState::new(None); - let contract_address_salt = 1.into(); - let (contract_address, _exec_info) = starknet_state - .deploy( - CONTRACT_CLASS.to_owned(), - vec![], - contract_address_salt, - None, - 0, + let block_context = BlockContext::default(); + let state_reader = Arc::new(InMemoryStateReader::default()); + let mut state = CachedState::new(state_reader, HashMap::new()); + + let call_data = vec![]; + let contract_address_salt = 1.into(); + let chain_id = block_context.starknet_os_config().chain_id().clone(); + + let deploy = Deploy::new( + contract_address_salt, + CONTRACT_CLASS.clone(), + call_data, + block_context.starknet_os_config().chain_id().clone(), + TRANSACTION_VERSION.clone(), + ) + .unwrap(); + + let contract_address = deploy.contract_address.clone(); + state + .set_contract_class( + &deploy.contract_hash, + &CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), ) .unwrap(); + let deploy_tx = Transaction::Deploy(deploy); + + let _tx_exec_info = deploy_tx.execute(&mut state, &block_context, 0).unwrap(); + + let signature = Vec::new(); // Statement **not** in blockifier. - starknet_state - .state + state .cache_mut() .nonce_initial_values_mut() .insert(contract_address.clone(), Felt252::zero()); for i in 0..RUNS { - starknet_state - .invoke_raw( - contract_address.clone(), - INCREASE_BALANCE_SELECTOR.clone(), - vec![1000.into()], - 0, - Some(Vec::new()), - Some(Felt252::from(i * 2)), - None, - 0, - ) - .unwrap(); - - let tx_exec_info = starknet_state - .invoke_raw( - contract_address.clone(), - GET_BALANCE_SELECTOR.clone(), - vec![], - 0, - Some(Vec::new()), - Some(Felt252::from((i * 2) + 1)), - None, - 0, - ) - .unwrap(); + let nonce_first = Felt252::from(i * 2); + let nonce_second = Felt252::from((i * 2) + 1); + + let invoke_first = InvokeFunction::new( + contract_address.clone(), + INCREASE_BALANCE_SELECTOR.clone(), + 0, + TRANSACTION_VERSION.clone(), + vec![1000.into()], + signature.clone(), + chain_id.clone(), + Some(nonce_first), + ) + .unwrap(); + + let tx = Transaction::InvokeFunction(invoke_first); + tx.execute(&mut state, &block_context, 0).unwrap(); + + let invoke_second = InvokeFunction::new( + contract_address.clone(), + GET_BALANCE_SELECTOR.clone(), + 0, + TRANSACTION_VERSION.clone(), + vec![], + signature.clone(), + chain_id.clone(), + Some(nonce_second), + ) + .unwrap(); + + let tx = Transaction::InvokeFunction(invoke_second); + let tx_exec_info = tx.execute(&mut state, &block_context, 0).unwrap(); assert_eq!( tx_exec_info.call_info.unwrap().retdata, diff --git a/src/bin/fibonacci.rs b/src/bin/fibonacci.rs index df61410cf..6017bfc8a 100644 --- a/src/bin/fibonacci.rs +++ b/src/bin/fibonacci.rs @@ -5,13 +5,17 @@ use num_traits::Zero; use lazy_static::lazy_static; use starknet_in_rust::{ + definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, + execution::{ + execution_entry_point::ExecutionEntryPoint, CallType, TransactionExecutionContext, + }, services::api::contract_classes::{ compiled_class::CompiledClass, deprecated_contract_class::ContractClass, }, state::cached_state::CachedState, - state::in_memory_state_reader::InMemoryStateReader, - testing::state::StarknetState, + state::{in_memory_state_reader::InMemoryStateReader, ExecutionResourcesManager}, utils::Address, + EntryPointType, }; #[cfg(feature = "with_mimalloc")] @@ -40,60 +44,97 @@ lazy_static! { fn main() { const RUNS: usize = 1000; - let cached_state = create_initial_state(); - - let mut starknet_state = StarknetState::new_with_states(Default::default(), cached_state); - - starknet_state - .state - .cache_mut() - .nonce_initial_values_mut() - .insert(CONTRACT_ADDRESS.clone(), Felt252::zero()); - - for i in 0..RUNS { - let tx_exec_info = starknet_state - .invoke_raw( - CONTRACT_ADDRESS.clone(), - FIB_SELECTOR.clone(), - [1.into(), 1.into(), 1000.into()].into(), - 0, - Some(Vec::new()), - Some(Felt252::from(i)), - None, - 0, + + let contract_class = ContractClass::from_path(&*CONTRACT_PATH).unwrap(); + let entry_points_by_type = contract_class.entry_points_by_type().clone(); + + let fib_entrypoint_selector = entry_points_by_type + .get(&EntryPointType::External) + .unwrap() + .get(0) + .unwrap() + .selector() + .clone(); + + //* -------------------------------------------- + //* Create state reader with class hash data + //* -------------------------------------------- + + let mut contract_class_cache = HashMap::new(); + + // ------------ contract data -------------------- + + let contract_address = CONTRACT_ADDRESS.clone(); + let class_hash = *CONTRACT_CLASS_HASH; + let nonce = Felt252::zero(); + + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); + let mut state_reader = InMemoryStateReader::default(); + state_reader + .address_to_class_hash_mut() + .insert(contract_address.clone(), class_hash); + state_reader + .address_to_nonce_mut() + .insert(contract_address.clone(), nonce); + + //* --------------------------------------- + //* Create state with previous data + //* --------------------------------------- + + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); + + //* ------------------------------------ + //* Create execution entry point + //* ------------------------------------ + + let calldata = [1.into(), 1.into(), 1000.into()].to_vec(); + let caller_address = Address(0000.into()); + let entry_point_type = EntryPointType::External; + + for nonce in 0..RUNS { + let exec_entry_point = ExecutionEntryPoint::new( + contract_address.clone(), + calldata.clone(), + fib_entrypoint_selector.clone(), + caller_address.clone(), + entry_point_type, + Some(CallType::Delegate), + Some(class_hash), + 0, + ); + + //* -------------------- + //* Execute contract + //* --------------------- + let block_context = BlockContext::default(); + let mut tx_execution_context = TransactionExecutionContext::new( + Address(0.into()), + Felt252::zero(), + Vec::new(), + 0, + nonce.into(), + block_context.invoke_tx_max_n_steps(), + TRANSACTION_VERSION.clone(), + ); + let mut resources_manager = ExecutionResourcesManager::default(); + + let tx_exec_result = exec_entry_point + .execute( + &mut state, + &block_context, + &mut resources_manager, + &mut tx_execution_context, + false, + block_context.invoke_tx_max_n_steps(), ) .unwrap(); assert_eq!( - tx_exec_info.call_info.unwrap().retdata, + tx_exec_result.call_info.unwrap().retdata, vec![EXPECTED_RES.clone()] - ) + ); } } - -fn create_initial_state() -> CachedState { - let cached_state = CachedState::new( - { - let mut state_reader = InMemoryStateReader::default(); - state_reader - .address_to_class_hash_mut() - .insert(CONTRACT_ADDRESS.clone(), *CONTRACT_CLASS_HASH); - - state_reader - .address_to_nonce_mut() - .insert(CONTRACT_ADDRESS.clone(), Felt252::zero()); - state_reader.class_hash_to_compiled_class_mut().insert( - *CONTRACT_CLASS_HASH, - CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), - ); - - state_reader - .address_to_storage_mut() - .insert((CONTRACT_ADDRESS.clone(), [0; 32]), Felt252::zero()); - Arc::new(state_reader) - }, - HashMap::new(), - ); - - cached_state -} diff --git a/src/bin/invoke.rs b/src/bin/invoke.rs index f29a78ad0..c98649987 100644 --- a/src/bin/invoke.rs +++ b/src/bin/invoke.rs @@ -4,12 +4,13 @@ use cairo_vm::felt::{felt_str, Felt252}; use num_traits::Zero; use starknet_in_rust::{ + definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, services::api::contract_classes::{ compiled_class::CompiledClass, deprecated_contract_class::ContractClass, }, state::cached_state::CachedState, state::in_memory_state_reader::InMemoryStateReader, - testing::state::StarknetState, + transaction::{InvokeFunction, Transaction}, utils::Address, }; @@ -41,52 +42,10 @@ lazy_static! { fn main() { const RUNS: usize = 10000; - let cached_state = create_initial_state(); - let mut starknet_state = StarknetState::new_with_states(Default::default(), cached_state); + let block_context = BlockContext::default(); - starknet_state - .state - .cache_mut() - .nonce_initial_values_mut() - .insert(CONTRACT_ADDRESS.clone(), Felt252::zero()); - - for i in 0..RUNS { - starknet_state - .invoke_raw( - CONTRACT_ADDRESS.clone(), - INCREASE_BALANCE_SELECTOR.clone(), - vec![1000.into()], - 0, - Some(Vec::new()), - Some(Felt252::from(i * 2)), - None, - 0, - ) - .unwrap(); - - let tx_exec_info = starknet_state - .invoke_raw( - CONTRACT_ADDRESS.clone(), - GET_BALANCE_SELECTOR.clone(), - vec![], - 0, - Some(Vec::new()), - Some(Felt252::from((i * 2) + 1)), - None, - 0, - ) - .unwrap(); - - assert_eq!( - tx_exec_info.call_info.unwrap().retdata, - vec![((1000 * i) + 1000).into()] - ); - } -} - -fn create_initial_state() -> CachedState { - let cached_state = CachedState::new( + let mut state = CachedState::new( { let mut state_reader = InMemoryStateReader::default(); state_reader @@ -108,6 +67,48 @@ fn create_initial_state() -> CachedState { }, HashMap::new(), ); + let chain_id = block_context.starknet_os_config().chain_id().clone(); + let signature = Vec::new(); + + state + .cache_mut() + .nonce_initial_values_mut() + .insert(CONTRACT_ADDRESS.clone(), Felt252::zero()); + + for i in 0..RUNS { + let invoke_first = InvokeFunction::new( + CONTRACT_ADDRESS.clone(), + INCREASE_BALANCE_SELECTOR.clone(), + 0, + TRANSACTION_VERSION.clone(), + vec![1000.into()], + signature.clone(), + chain_id.clone(), + Some(Felt252::from(i * 2)), + ) + .unwrap(); + + let tx = Transaction::InvokeFunction(invoke_first); + tx.execute(&mut state, &block_context, 0).unwrap(); + + let invoke_second = InvokeFunction::new( + CONTRACT_ADDRESS.clone(), + GET_BALANCE_SELECTOR.clone(), + 0, + TRANSACTION_VERSION.clone(), + vec![], + signature.clone(), + chain_id.clone(), + Some(Felt252::from((i * 2) + 1)), + ) + .unwrap(); + + let tx = Transaction::InvokeFunction(invoke_second); + let tx_exec_info = tx.execute(&mut state, &block_context, 0).unwrap(); - cached_state + assert_eq!( + tx_exec_info.call_info.unwrap().retdata, + vec![((1000 * i) + 1000).into()] + ); + } } diff --git a/src/lib.rs b/src/lib.rs index 6af73ef40..fd8747a73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,6 @@ pub mod serde_structs; pub mod services; pub mod state; pub mod syscalls; -pub mod testing; pub mod transaction; pub mod utils; @@ -224,14 +223,14 @@ mod test { use crate::services::api::contract_classes::deprecated_contract_class::ContractClass; use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; use crate::state::state_api::State; - use crate::testing::{ - create_account_tx_test_state, TEST_ACCOUNT_CONTRACT_ADDRESS, TEST_CONTRACT_ADDRESS, - TEST_CONTRACT_PATH, TEST_FIB_COMPILED_CONTRACT_CLASS_HASH, - }; use crate::transaction::{ Declare, DeclareV2, Deploy, DeployAccount, InvokeFunction, L1Handler, Transaction, }; use crate::utils::felt_to_hash; + use crate::utils::test_utils::{ + create_account_tx_test_state, TEST_ACCOUNT_CONTRACT_ADDRESS, TEST_CONTRACT_ADDRESS, + TEST_CONTRACT_PATH, TEST_FIB_COMPILED_CONTRACT_CLASS_HASH, + }; use cairo_lang_starknet::casm_contract_class::CasmContractClass; use cairo_lang_starknet::contract_class::ContractClass as SierraContractClass; use cairo_vm::felt::{felt_str, Felt252}; diff --git a/src/testing/__pycache__/bench_integration.cpython-39-pytest-7.2.1.pyc b/src/testing/__pycache__/bench_integration.cpython-39-pytest-7.2.1.pyc deleted file mode 100644 index d856d68e7a2d0edecef1a5bafa5a5ef66abcb2c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 936 zcmaJ+o$=bB*22A1#hf!%t{=hU14G@#ikl46Hg2;=#;x2K5?J$bE6I}Nn z+9SV%f8i?^_zRqPNt>|~R{Wgr^Lx+leKs8odI-jo{av5T-U@7-Bd> zF>Y3pcL>5Lcj7Ky?YObq?0B))tbXjnO0tc-7xx;UPS($ZIKYUz)4^ic*iAlKV&*JK zyv4og_Vga>GWQ$$isSnXpQ5q%8%{K6(mH259Qdi{519Hr7>2KrK?}S@$I#hJbdBeDN=%258@y(S zapq9tGxTonx-%!!F6%Jo1~1$;2BSGycuRDb`MAdrbksc&qg{lcdRG^fO1b#eSwWf? zl{8~t0YCsv8;`r5b+f`Ifcsvp^Rh(*`oYRcTlv|H~ z=4oZP?N7LA*|B3CRY@KDtw7dqC9yd9j?^X``R5>dtGUvVrqYOiS_+w{N}EWlG%{Qp zAt%u}m+6N@NW(#9BMKRoGuy9sf&5fl@_sF600t2U5Aik*@D5g6fX5H4e_n|U@@N|z zmb2s*Jxt13og<_g3Te_Rex(GovvEsVujP6W+#E@jC55)`3ff^y>zPbN5kGFazM_hU zZU5oAk+79P!TU%5^=v~|*W;Abe6Y^65Yl=~C`of}{Uo^%8BY@BLpJN=@M5h;S7kKK hH$vYrquS5k&kI&%`~U;eLoknsk9`v0fb0+#{{;#y4-)_Y diff --git a/src/testing/bench_integration.rs b/src/testing/bench_integration.rs deleted file mode 100644 index dcdbf6479..000000000 --- a/src/testing/bench_integration.rs +++ /dev/null @@ -1,101 +0,0 @@ -use std::{collections::HashMap, path::PathBuf}; - -use felt::{felt_str, Felt}; -use num_traits::Zero; - -use crate::{ - services::api::contract_classes::deprecated_contract_class::ContractClass, - state::cached_state::CachedState, state::in_memory_state_reader::InMemoryStateReader, - testing::starknet_state::StarknetState, utils::Address, -}; - -use lazy_static::lazy_static; - -lazy_static! { - // include_str! doesn't seem to work in CI - static ref CONTRACT_CLASS: ContractClass = ContractClass::new_from_path( - "starknet_programs/first_contract.json", - ).unwrap(); - - static ref CONTRACT_PATH: PathBuf = PathBuf::from("starknet_programs/first_contract.json"); - - static ref CONTRACT_CLASS_HASH: [u8; 32] = [1; 32]; - - static ref CONTRACT_ADDRESS: Address = Address(1.into()); - - static ref INCREASE_BALANCE_SELECTOR: Felt = felt_str!("1530486729947006463063166157847785599120665941190480211966374137237989315360"); - - static ref GET_BALANCE_SELECTOR: Felt = felt_str!("1636223440827086009537493065587328807418413867743950350615962740049133672085"); -} - -#[test] -fn main() { - const RUNS: usize = 1000; - let cached_state = create_initial_state(); - - let mut starknet_state = StarknetState { - state: cached_state, - ..Default::default() - }; - - starknet_state - .state - .cache_mut() - .nonce_initial_values_mut() - .insert(CONTRACT_ADDRESS.clone(), Felt::zero()); - - for i in 0..RUNS { - starknet_state - .invoke_raw( - CONTRACT_ADDRESS.clone(), - INCREASE_BALANCE_SELECTOR.clone(), - vec![1000.into()], - 0, - Some(Vec::new()), - Some(Felt::from(i * 2)), - ) - .unwrap(); - - let tx_exec_info = starknet_state - .invoke_raw( - CONTRACT_ADDRESS.clone(), - GET_BALANCE_SELECTOR.clone(), - vec![], - 0, - Some(Vec::new()), - Some(Felt::from((i * 2) + 1)), - ) - .unwrap(); - - assert_eq!( - tx_exec_info.call_info.unwrap().retdata, - vec![((1000 * i) + 1000).into()] - ); - } -} - -fn create_initial_state() -> CachedState { - let cached_state = CachedState::new( - { - let mut state_reader = InMemoryStateReader::default(); - state_reader - .address_to_class_hash_mut() - .insert(CONTRACT_ADDRESS.clone(), CONTRACT_CLASS_HASH.clone()); - - state_reader - .address_to_nonce_mut() - .insert(CONTRACT_ADDRESS.clone(), Felt::zero()); - state_reader - .class_hash_to_contract_class_mut() - .insert(CONTRACT_CLASS_HASH.clone(), CONTRACT_CLASS.clone()); - - state_reader - .address_to_storage_mut() - .insert((CONTRACT_ADDRESS.clone(), [0; 32]), Felt::zero()); - state_reader - }, - Some(HashMap::new()), - ); - - cached_state -} diff --git a/src/testing/mod.rs b/src/testing/mod.rs deleted file mode 100644 index 018082643..000000000 --- a/src/testing/mod.rs +++ /dev/null @@ -1,165 +0,0 @@ -pub mod erc20; -pub mod state; -pub mod state_error; -pub mod type_utils; - -use std::{collections::HashMap, sync::Arc}; - -use cairo_vm::felt::{felt_str, Felt252}; -use lazy_static::lazy_static; -use num_traits::Zero; - -use crate::{ - definitions::{ - block_context::{BlockContext, StarknetChainId, StarknetOsConfig}, - constants::DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS, - }, - services::api::contract_classes::{ - compiled_class::CompiledClass, deprecated_contract_class::ContractClass, - }, - state::{ - cached_state::CachedState, in_memory_state_reader::InMemoryStateReader, - state_cache::StorageEntry, BlockInfo, - }, - utils::{felt_to_hash, Address, ClassHash}, -}; - -pub const ACCOUNT_CONTRACT_PATH: &str = "starknet_programs/account_without_validation.json"; -pub const ERC20_CONTRACT_PATH: &str = "starknet_programs/ERC20.json"; -pub const TEST_CONTRACT_PATH: &str = "starknet_programs/fibonacci.json"; - -lazy_static! { - // Addresses. - pub static ref TEST_ACCOUNT_CONTRACT_ADDRESS: Address = Address(felt_str!("257")); - pub static ref TEST_CONTRACT_ADDRESS: Address = Address(felt_str!("256")); - pub static ref TEST_SEQUENCER_ADDRESS: Address = - Address(felt_str!("4096")); - pub static ref TEST_ERC20_CONTRACT_ADDRESS: Address = - Address(felt_str!("4097")); - - - // Class hashes. - pub static ref TEST_ACCOUNT_CONTRACT_CLASS_HASH: Felt252 = felt_str!("273"); - pub static ref TEST_CLASS_HASH: Felt252 = felt_str!("272"); - pub static ref TEST_EMPTY_CONTRACT_CLASS_HASH: Felt252 = felt_str!("274"); - pub static ref TEST_ERC20_CONTRACT_CLASS_HASH: Felt252 = felt_str!("4112"); - pub static ref TEST_FIB_COMPILED_CONTRACT_CLASS_HASH: Felt252 = felt_str!("1948962768849191111780391610229754715773924969841143100991524171924131413970"); - - // Storage keys. - pub static ref TEST_ERC20_ACCOUNT_BALANCE_KEY: Felt252 = - felt_str!("1192211877881866289306604115402199097887041303917861778777990838480655617515"); - pub static ref TEST_ERC20_SEQUENCER_BALANCE_KEY: Felt252 = - felt_str!("3229073099929281304021185011369329892856197542079132996799046100564060768274"); - pub static ref TEST_ERC20_BALANCE_KEY_1: Felt252 = - felt_str!("1192211877881866289306604115402199097887041303917861778777990838480655617516"); - pub static ref TEST_ERC20_BALANCE_KEY_2: Felt252 = - felt_str!("3229073099929281304021185011369329892856197542079132996799046100564060768275"); - - pub static ref TEST_ERC20_DEPLOYED_ACCOUNT_BALANCE_KEY: Felt252 = - felt_str!("2542253978940891427830343982984992363331567580652119103860970381451088310289"); - - // Others. - // Blockifier had this value hardcoded to 2. - pub static ref ACTUAL_FEE: Felt252 = Felt252::from(10000000); -} - -pub fn new_starknet_block_context_for_testing() -> BlockContext { - BlockContext::new( - StarknetOsConfig::new( - StarknetChainId::TestNet.to_felt(), - TEST_ERC20_CONTRACT_ADDRESS.clone(), - 1, - ), - 0, - 0, - DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS.clone(), - 1_000_000, - 0, - BlockInfo::empty(TEST_SEQUENCER_ADDRESS.clone()), - HashMap::default(), - true, - ) -} - -pub fn create_account_tx_test_state( -) -> Result<(BlockContext, CachedState), Box> { - let block_context = new_starknet_block_context_for_testing(); - - let test_contract_class_hash = felt_to_hash(&TEST_CLASS_HASH.clone()); - let test_account_contract_class_hash = felt_to_hash(&TEST_ACCOUNT_CONTRACT_CLASS_HASH.clone()); - let test_erc20_class_hash = felt_to_hash(&TEST_ERC20_CONTRACT_CLASS_HASH.clone()); - let class_hash_to_class = HashMap::from([ - ( - test_account_contract_class_hash, - ContractClass::from_path(ACCOUNT_CONTRACT_PATH)?, - ), - ( - test_contract_class_hash, - ContractClass::from_path(TEST_CONTRACT_PATH)?, - ), - ( - test_erc20_class_hash, - ContractClass::from_path(ERC20_CONTRACT_PATH)?, - ), - ]); - - let test_contract_address = TEST_CONTRACT_ADDRESS.clone(); - let test_account_contract_address = TEST_ACCOUNT_CONTRACT_ADDRESS.clone(); - let test_erc20_address = block_context - .starknet_os_config() - .fee_token_address() - .clone(); - let address_to_class_hash = HashMap::from([ - (test_contract_address, test_contract_class_hash), - ( - test_account_contract_address, - test_account_contract_class_hash, - ), - (test_erc20_address.clone(), test_erc20_class_hash), - ]); - - let test_erc20_account_balance_key = TEST_ERC20_ACCOUNT_BALANCE_KEY.clone(); - - let storage_view = HashMap::from([( - (test_erc20_address, test_erc20_account_balance_key), - ACTUAL_FEE.clone(), - )]); - - let cached_state = CachedState::new( - { - let mut state_reader = InMemoryStateReader::default(); - for (contract_address, class_hash) in address_to_class_hash { - let storage_keys: HashMap<(Address, ClassHash), Felt252> = storage_view - .iter() - .filter_map(|((address, storage_key), storage_value)| { - (address == &contract_address).then_some(( - (address.clone(), felt_to_hash(storage_key)), - storage_value.clone(), - )) - }) - .collect(); - - let stored: HashMap = storage_keys; - - state_reader - .address_to_class_hash_mut() - .insert(contract_address.clone(), class_hash); - - state_reader - .address_to_nonce_mut() - .insert(contract_address.clone(), Felt252::zero()); - state_reader.address_to_storage_mut().extend(stored); - } - for (class_hash, contract_class) in class_hash_to_class { - state_reader.class_hash_to_compiled_class_mut().insert( - class_hash, - CompiledClass::Deprecated(Arc::new(contract_class)), - ); - } - Arc::new(state_reader) - }, - HashMap::new(), - ); - - Ok((block_context, cached_state)) -} diff --git a/src/testing/state.rs b/src/testing/state.rs deleted file mode 100644 index 2fbbaec87..000000000 --- a/src/testing/state.rs +++ /dev/null @@ -1,733 +0,0 @@ -use super::{state_error::StarknetStateError, type_utils::ExecutionInfo}; -use crate::execution::execution_entry_point::ExecutionResult; -use crate::services::api::contract_classes::compiled_class::CompiledClass; -use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; -use crate::{ - definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, - execution::{ - execution_entry_point::ExecutionEntryPoint, CallInfo, Event, TransactionExecutionContext, - TransactionExecutionInfo, - }, - services::api::{ - contract_classes::deprecated_contract_class::ContractClass, messages::StarknetMessageToL1, - }, - state::{ - cached_state::CachedState, - state_api::{State, StateReader}, - }, - state::{in_memory_state_reader::InMemoryStateReader, ExecutionResourcesManager}, - transaction::{ - error::TransactionError, invoke_function::InvokeFunction, Declare, Deploy, Transaction, - }, - utils::{Address, ClassHash}, -}; -use cairo_vm::felt::Felt252; -use num_traits::{One, Zero}; -use std::collections::HashMap; -use std::sync::Arc; - -// --------------------------------------------------------------------- -/// StarkNet testing object. Represents a state of a StarkNet network. -pub struct StarknetState { - pub state: CachedState, - pub(crate) block_context: BlockContext, - l2_to_l1_messages: HashMap, usize>, - l2_to_l1_messages_log: Vec, - events: Vec, -} - -impl StarknetState { - pub fn new(context: Option) -> Self { - let block_context = context.unwrap_or_default(); - let state_reader = Arc::new(InMemoryStateReader::default()); - - let state = CachedState::new(state_reader, HashMap::new()); - - let l2_to_l1_messages = HashMap::new(); - let l2_to_l1_messages_log = Vec::new(); - - let events = Vec::new(); - StarknetState { - state, - block_context, - l2_to_l1_messages, - l2_to_l1_messages_log, - events, - } - } - - pub fn new_with_states( - block_context: Option, - state: CachedState, - ) -> Self { - let block_context = block_context.unwrap_or_default(); - let l2_to_l1_messages = HashMap::new(); - let l2_to_l1_messages_log = Vec::new(); - - let events = Vec::new(); - StarknetState { - state, - block_context, - l2_to_l1_messages, - l2_to_l1_messages_log, - events, - } - } - - // ------------------------------------------------------------------------------------ - /// Declares a contract class. - /// Returns the class hash and the execution info. - /// Args: - /// contract_class - a compiled StarkNet contract - pub fn declare( - &mut self, - contract_class: ContractClass, - ) -> Result<(ClassHash, TransactionExecutionInfo), TransactionError> { - let tx = Declare::new( - contract_class, - self.chain_id(), - Address(Felt252::one()), - 0, - 0.into(), - Vec::new(), - 0.into(), - )?; - - let tx_execution_info = tx.execute(&mut self.state, &self.block_context)?; - - Ok((tx.class_hash, tx_execution_info)) - } - - /// Invokes a contract function. Returns the execution info. - - #[allow(clippy::too_many_arguments)] - pub fn invoke_raw( - &mut self, - contract_address: Address, - selector: Felt252, - calldata: Vec, - max_fee: u128, - signature: Option>, - nonce: Option, - hash_value: Option, - remaining_gas: u128, - ) -> Result { - let tx = self.create_invoke_function( - contract_address, - selector, - calldata, - max_fee, - signature, - nonce, - hash_value, - )?; - - let mut tx = Transaction::InvokeFunction(tx); - self.execute_tx(&mut tx, remaining_gas) - } - - /// Builds the transaction execution context and executes the entry point. - /// Returns the CallInfo. - pub fn execute_entry_point_raw( - &mut self, - contract_address: Address, - entry_point_selector: Felt252, - calldata: Vec, - caller_address: Address, - ) -> Result { - let call = ExecutionEntryPoint::new( - contract_address, - calldata, - entry_point_selector, - caller_address, - EntryPointType::External, - None, - None, - 0, - ); - - let mut resources_manager = ExecutionResourcesManager::default(); - - let mut tx_execution_context = TransactionExecutionContext::default(); - let ExecutionResult { call_info, .. } = call.execute( - &mut self.state, - &self.block_context, - &mut resources_manager, - &mut tx_execution_context, - false, - self.block_context.invoke_tx_max_n_steps, - )?; - - let call_info = call_info.ok_or(StarknetStateError::Transaction( - TransactionError::CallInfoIsNone, - ))?; - - let exec_info = ExecutionInfo::Call(Box::new(call_info.clone())); - self.add_messages_and_events(&exec_info)?; - - Ok(call_info) - } - - /// Deploys a contract. Returns the contract address and the execution info. - /// Args: - /// contract_class - a compiled StarkNet contract - /// contract_address_salt - /// the salt to use for deploying. Otherwise, the salt is randomized. - pub fn deploy( - &mut self, - contract_class: ContractClass, - constructor_calldata: Vec, - contract_address_salt: Felt252, - hash_value: Option, - remaining_gas: u128, - ) -> Result<(Address, TransactionExecutionInfo), StarknetStateError> { - let chain_id = self.block_context.starknet_os_config.chain_id.clone(); - let deploy = match hash_value { - None => Deploy::new( - contract_address_salt, - contract_class.clone(), - constructor_calldata, - chain_id, - TRANSACTION_VERSION.clone(), - )?, - Some(hash_value) => Deploy::new_with_tx_hash( - contract_address_salt, - contract_class.clone(), - constructor_calldata, - TRANSACTION_VERSION.clone(), - hash_value, - )?, - }; - let contract_address = deploy.contract_address.clone(); - let contract_hash = deploy.contract_hash; - let mut tx = Transaction::Deploy(deploy); - - self.state.set_contract_class( - &contract_hash, - &CompiledClass::Deprecated(Arc::new(contract_class)), - )?; - - let tx_execution_info = self.execute_tx(&mut tx, remaining_gas)?; - Ok((contract_address, tx_execution_info)) - } - - pub fn execute_tx( - &mut self, - tx: &mut Transaction, - remaining_gas: u128, - ) -> Result { - let tx = tx.execute(&mut self.state, &self.block_context, remaining_gas)?; - let tx_execution_info = ExecutionInfo::Transaction(Box::new(tx.clone())); - self.add_messages_and_events(&tx_execution_info)?; - Ok(tx) - } - - pub fn add_messages_and_events( - &mut self, - exec_info: &ExecutionInfo, - ) -> Result<(), StarknetStateError> { - for msg in exec_info.get_sorted_l2_to_l1_messages()? { - let starknet_message = - StarknetMessageToL1::new(msg.from_address, msg.to_address, msg.payload); - - self.l2_to_l1_messages_log.push(starknet_message.clone()); - let message_hash = starknet_message.get_hash(); - - if self.l2_to_l1_messages.contains_key(&message_hash) { - let val = self.l2_to_l1_messages.get(&message_hash).unwrap(); - self.l2_to_l1_messages.insert(message_hash, val + 1); - } else { - self.l2_to_l1_messages.insert(message_hash, 1); - } - } - - let mut events = exec_info.get_sorted_events()?; - self.events.append(&mut events); - Ok(()) - } - - /// Consumes the given message hash. - pub fn consume_message_hash( - &mut self, - message_hash: Vec, - ) -> Result<(), StarknetStateError> { - let val = self - .l2_to_l1_messages - .get(&message_hash) - .ok_or(StarknetStateError::InvalidMessageHash)?; - - if val.is_zero() { - Err(StarknetStateError::InvalidMessageHash) - } else { - self.l2_to_l1_messages.insert(message_hash, val - 1); - Ok(()) - } - } - - // ------------------------ - // Private functions - // ------------------------ - - fn chain_id(&self) -> Felt252 { - self.block_context.starknet_os_config.chain_id.clone() - } - - #[allow(clippy::too_many_arguments)] - fn create_invoke_function( - &mut self, - contract_address: Address, - entry_point_selector: Felt252, - calldata: Vec, - max_fee: u128, - signature: Option>, - nonce: Option, - hash_value: Option, - ) -> Result { - let signature = match signature { - Some(sign) => sign, - None => Vec::new(), - }; - - let nonce = match nonce { - Some(n) => n, - None => self.state.get_nonce_at(&contract_address)?, - }; - - match hash_value { - None => InvokeFunction::new( - contract_address, - entry_point_selector, - max_fee, - TRANSACTION_VERSION.clone(), - calldata, - signature, - self.chain_id(), - Some(nonce), - ), - Some(hash_value) => InvokeFunction::new_with_tx_hash( - contract_address, - entry_point_selector, - max_fee, - TRANSACTION_VERSION.clone(), - calldata, - signature, - Some(nonce), - hash_value, - ), - } - } -} - -#[cfg(test)] -mod tests { - use std::path::PathBuf; - - use cairo_vm::vm::runners::cairo_runner::ExecutionResources; - use num_traits::Num; - use pretty_assertions_sorted::assert_eq_sorted; - - use super::*; - use crate::{ - core::contract_address::compute_deprecated_class_hash, - definitions::{ - constants::CONSTRUCTOR_ENTRY_POINT_SELECTOR, transaction_type::TransactionType, - }, - execution::{CallType, OrderedL2ToL1Message}, - hash_utils::calculate_contract_address, - services::api::contract_classes::compiled_class::CompiledClass, - state::state_cache::StorageEntry, - utils::{calculate_sn_keccak, felt_to_hash}, - }; - - #[test] - fn test_deploy() { - let mut starknet_state = StarknetState::new(None); - - let contract_class = ContractClass::from_path("starknet_programs/fibonacci.json").unwrap(); - - let contract_address_salt: Felt252 = 1.into(); - - // expected results - - // ----- calculate fib class hash --------- - let hash = compute_deprecated_class_hash(&contract_class).unwrap(); - let class_hash = felt_to_hash(&hash); - - let address = calculate_contract_address( - &contract_address_salt, - &hash, - &[], - Address(Felt252::zero()), - ) - .unwrap(); - - let mut actual_resources = HashMap::new(); - actual_resources.insert("l1_gas_usage".to_string(), 2448); - actual_resources.insert("n_steps".to_string(), 0); - - let transaction_exec_info = TransactionExecutionInfo { - validate_info: None, - call_info: Some(CallInfo { - caller_address: Address(0.into()), - call_type: Some(CallType::Call), - contract_address: Address(address.clone()), - code_address: None, - class_hash: Some(class_hash), - entry_point_selector: Some(CONSTRUCTOR_ENTRY_POINT_SELECTOR.clone()), - entry_point_type: Some(EntryPointType::Constructor), - ..Default::default() - }), - revert_error: None, - fee_transfer_info: None, - actual_fee: 0, - actual_resources, - tx_type: Some(TransactionType::Deploy), - }; - - // check result is correct - let exec = (Address(address), transaction_exec_info); - assert_eq!( - starknet_state - .deploy( - contract_class.clone(), - vec![], - contract_address_salt, - None, - 0 - ) - .unwrap(), - exec - ); - - // check that properly stored contract class - assert_eq!( - starknet_state - .state - .contract_classes - .get(&class_hash) - .unwrap() - .to_owned(), - CompiledClass::Deprecated(Arc::new(contract_class)) - ); - } - - #[test] - fn test_declare() { - let path = PathBuf::from("starknet_programs/account_without_validation.json"); - let contract_class = ContractClass::from_path(path).unwrap(); - - // Instantiate CachedState - let mut contract_class_cache = HashMap::new(); - - // ------------ contract data -------------------- - // hack store account contract - let hash = compute_deprecated_class_hash(&contract_class).unwrap(); - let class_hash = felt_to_hash(&hash); - contract_class_cache.insert( - class_hash, - CompiledClass::Deprecated(Arc::new(contract_class.clone())), - ); - - // store sender_address - let sender_address = Address(1.into()); - // this is not conceptually correct as the sender address would be an - // Account contract (not the contract that we are currently declaring) - // but for testing reasons its ok - let nonce = Felt252::zero(); - let storage_entry: StorageEntry = (sender_address.clone(), [19; 32]); - let storage = Felt252::zero(); - - let mut state_reader = InMemoryStateReader::default(); - state_reader - .address_to_class_hash_mut() - .insert(sender_address.clone(), class_hash); - state_reader - .address_to_nonce_mut() - .insert(sender_address.clone(), nonce.clone()); - state_reader - .address_to_storage_mut() - .insert(storage_entry.clone(), storage.clone()); - state_reader.class_hash_to_compiled_class_mut().insert( - class_hash, - CompiledClass::Deprecated(Arc::new(contract_class.clone())), - ); - - let state = CachedState::new(Arc::new(state_reader), contract_class_cache); - - //* -------------------------------------------- - //* Create starknet state with previous data - //* -------------------------------------------- - - let mut starknet_state = StarknetState::new(None); - - starknet_state.state = state; - starknet_state - .state - .set_class_hash_at(sender_address.clone(), class_hash) - .unwrap(); - - starknet_state - .state - .cache - .nonce_writes - .insert(sender_address.clone(), nonce); - - starknet_state.state.set_storage_at(&storage_entry, storage); - - starknet_state - .state - .set_contract_class( - &class_hash, - &CompiledClass::Deprecated(Arc::new(contract_class)), - ) - .unwrap(); - - // -------------------------------------------- - // Test declare with starknet state - // -------------------------------------------- - let fib_contract_class = - ContractClass::from_path("starknet_programs/fibonacci.json").unwrap(); - - let (ret_class_hash, _exec_info) = - starknet_state.declare(fib_contract_class.clone()).unwrap(); - - //* --------------------------------------- - // Expected result - //* --------------------------------------- - - // ----- calculate fib class hash --------- - let hash = compute_deprecated_class_hash(&fib_contract_class).unwrap(); - let fib_class_hash = felt_to_hash(&hash); - - // check that it return the correct clash hash - assert_eq!(ret_class_hash, fib_class_hash); - - // check that state has store has store accounts class hash - assert_eq!( - starknet_state - .state - .get_class_hash_at(&sender_address) - .unwrap() - .to_owned(), - class_hash - ); - // check that state has store fib class hash - assert_eq!( - TryInto::::try_into( - starknet_state - .state - .get_contract_class(&fib_class_hash) - .unwrap() - ) - .unwrap(), - fib_contract_class - ); - } - - #[test] - fn test_invoke() { - // 1) deploy fibonacci - // 2) invoke call over fibonacci - - let mut starknet_state = StarknetState::new(None); - let contract_class = ContractClass::from_path("starknet_programs/fibonacci.json").unwrap(); - let calldata = [1.into(), 1.into(), 10.into()].to_vec(); - let contract_address_salt: Felt252 = 1.into(); - - let (contract_address, _exec_info) = starknet_state - .deploy( - contract_class.clone(), - vec![], - contract_address_salt.clone(), - None, - 0, - ) - .unwrap(); - - // fibonacci selector - let selector = Felt252::from_str_radix( - "112e35f48499939272000bd72eb840e502ca4c3aefa8800992e8defb746e0c9", - 16, - ) - .unwrap(); - - // Statement **not** in blockifier. - starknet_state - .state - .cache_mut() - .nonce_initial_values_mut() - .insert(contract_address.clone(), Felt252::zero()); - - let tx_info = starknet_state - .invoke_raw( - contract_address, - selector.clone(), - calldata, - 0, - Some(Vec::new()), - Some(Felt252::zero()), - None, - 0, - ) - .unwrap(); - - // expected result - // ----- calculate fib class hash --------- - let hash = compute_deprecated_class_hash(&contract_class).unwrap(); - let fib_class_hash = felt_to_hash(&hash); - - let address = calculate_contract_address( - &contract_address_salt, - &hash, - &[], - Address(Felt252::zero()), - ) - .unwrap(); - let actual_resources = HashMap::from([ - ("n_steps".to_string(), 3457), - ("l1_gas_usage".to_string(), 2448), - ("range_check_builtin".to_string(), 80), - ("pedersen_builtin".to_string(), 16), - ]); - - let expected_info = TransactionExecutionInfo { - validate_info: None, - call_info: Some(CallInfo { - caller_address: Address(Felt252::zero()), - call_type: Some(CallType::Call), - contract_address: Address(address), - code_address: None, - class_hash: Some(fib_class_hash), - entry_point_selector: Some(selector), - entry_point_type: Some(EntryPointType::External), - calldata: vec![1.into(), 1.into(), 10.into()], - retdata: vec![144.into()], - execution_resources: ExecutionResources { - n_steps: 94, - n_memory_holes: 0, - builtin_instance_counter: HashMap::default(), - }, - ..Default::default() - }), - actual_resources, - tx_type: Some(TransactionType::InvokeFunction), - ..Default::default() - }; - - assert_eq_sorted!(tx_info, expected_info); - } - - #[test] - fn test_execute_entry_point_raw() { - let mut starknet_state = StarknetState::new(None); - let path = PathBuf::from("starknet_programs/fibonacci.json"); - let contract_class = ContractClass::from_path(path).unwrap(); - let contract_address_salt = 1.into(); - - let (contract_address, _exec_info) = starknet_state - .deploy(contract_class, vec![], contract_address_salt, None, 0) - .unwrap(); - - // fibonacci selector - let entrypoint_selector = Felt252::from_bytes_be(&calculate_sn_keccak(b"fib")); - let result = starknet_state - .execute_entry_point_raw( - contract_address, - entrypoint_selector, - vec![1.into(), 1.into(), 10.into()], - Address(0.into()), - ) - .unwrap() - .retdata; - assert_eq!(result, vec![144.into()]); - } - - #[test] - fn test_add_messages_and_events() { - let mut starknet_state = StarknetState::new(None); - let test_msg_1 = OrderedL2ToL1Message { - order: 0, - to_address: Address(0.into()), - payload: vec![0.into()], - }; - let test_msg_2 = OrderedL2ToL1Message { - order: 1, - to_address: Address(0.into()), - payload: vec![0.into()], - }; - - let exec_info = ExecutionInfo::Call(Box::new(CallInfo { - l2_to_l1_messages: vec![test_msg_1, test_msg_2], - ..Default::default() - })); - - starknet_state.add_messages_and_events(&exec_info).unwrap(); - let msg_hash = - StarknetMessageToL1::new(Address(0.into()), Address(0.into()), vec![0.into()]) - .get_hash(); - - let messages = starknet_state.l2_to_l1_messages; - let mut expected_messages = HashMap::new(); - expected_messages.insert(msg_hash, 2); - assert_eq!(messages, expected_messages); - } - - #[test] - fn test_consume_message_hash() { - let mut starknet_state = StarknetState::new(None); - let test_msg_1 = OrderedL2ToL1Message { - order: 0, - to_address: Address(0.into()), - payload: vec![0.into()], - }; - let test_msg_2 = OrderedL2ToL1Message { - order: 1, - to_address: Address(0.into()), - payload: vec![0.into()], - }; - - let exec_info = ExecutionInfo::Call(Box::new(CallInfo { - l2_to_l1_messages: vec![test_msg_1, test_msg_2], - ..Default::default() - })); - - starknet_state.add_messages_and_events(&exec_info).unwrap(); - let msg_hash = - StarknetMessageToL1::new(Address(0.into()), Address(0.into()), vec![0.into()]) - .get_hash(); - - starknet_state - .consume_message_hash(msg_hash.clone()) - .unwrap(); - let messages = starknet_state.l2_to_l1_messages; - let mut expected_messages = HashMap::new(); - expected_messages.insert(msg_hash, 1); - assert_eq!(messages, expected_messages); - } - - #[test] - fn test_consume_message_hash_twice_should_fail() { - let mut starknet_state = StarknetState::new(None); - let test_msg = OrderedL2ToL1Message { - order: 0, - to_address: Address(0.into()), - payload: vec![0.into()], - }; - - let exec_info = ExecutionInfo::Call(Box::new(CallInfo { - l2_to_l1_messages: vec![test_msg], - ..Default::default() - })); - - starknet_state.add_messages_and_events(&exec_info).unwrap(); - let msg_hash = - StarknetMessageToL1::new(Address(0.into()), Address(0.into()), vec![0.into()]) - .get_hash(); - - starknet_state - .consume_message_hash(msg_hash.clone()) - .unwrap(); - let err = starknet_state.consume_message_hash(msg_hash).unwrap_err(); - assert_matches!(err, StarknetStateError::InvalidMessageHash); - } -} diff --git a/src/testing/state_error.rs b/src/testing/state_error.rs deleted file mode 100644 index c2e8ec705..000000000 --- a/src/testing/state_error.rs +++ /dev/null @@ -1,20 +0,0 @@ -use thiserror::Error; - -use crate::{ - core::errors::hash_errors::HashError, core::errors::state_errors::StateError, - syscalls::syscall_handler_errors::SyscallHandlerError, transaction::error::TransactionError, -}; - -#[derive(Debug, Error)] -pub enum StarknetStateError { - #[error("Invalid message hash key passed to l2 messages")] - InvalidMessageHash, - #[error(transparent)] - Syscall(#[from] SyscallHandlerError), - #[error(transparent)] - State(#[from] StateError), - #[error(transparent)] - Transaction(#[from] TransactionError), - #[error(transparent)] - HashError(#[from] HashError), -} diff --git a/src/testing/type_utils.rs b/src/testing/type_utils.rs deleted file mode 100644 index 488212c2e..000000000 --- a/src/testing/type_utils.rs +++ /dev/null @@ -1,25 +0,0 @@ -use crate::{ - execution::{CallInfo, Event, L2toL1MessageInfo, TransactionExecutionInfo}, - transaction::error::TransactionError, -}; - -pub enum ExecutionInfo { - Transaction(Box), - Call(Box), -} - -impl ExecutionInfo { - pub fn get_sorted_l2_to_l1_messages(&self) -> Result, TransactionError> { - match self { - ExecutionInfo::Transaction(tx) => tx.get_sorted_l2_to_l1_messages(), - ExecutionInfo::Call(call) => call.get_sorted_l2_to_l1_messages(), - } - } - - pub fn get_sorted_events(&self) -> Result, TransactionError> { - match self { - ExecutionInfo::Transaction(tx) => tx.get_sorted_events(), - ExecutionInfo::Call(call) => call.get_sorted_events(), - } - } -} diff --git a/src/utils.rs b/src/utils.rs index 15b70cbf9..9e12b47ae 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -436,12 +436,33 @@ pub fn parse_felt_array(felt_strings: &[Value]) -> Vec { pub mod test_utils { #![allow(unused_imports)] + use crate::{ + definitions::{ + block_context::{BlockContext, StarknetChainId, StarknetOsConfig}, + constants::DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS, + }, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, + state::{ + cached_state::CachedState, in_memory_state_reader::InMemoryStateReader, + state_cache::StorageEntry, BlockInfo, + }, + utils::Address, + }; + use cairo_vm::felt::{felt_str, Felt252}; + use num_traits::Zero; + use std::{collections::HashMap, sync::Arc}; + + use super::{felt_to_hash, ClassHash}; + #[macro_export] macro_rules! any_box { ($val : expr) => { Box::new($val) as Box }; } + pub(crate) use any_box; macro_rules! references { @@ -461,6 +482,7 @@ pub mod test_utils { references }}; } + pub(crate) use references; macro_rules! ids_data { @@ -617,6 +639,148 @@ pub mod test_utils { }}; } pub(crate) use run_syscall_hint; + + pub(crate) const ACCOUNT_CONTRACT_PATH: &str = + "starknet_programs/account_without_validation.json"; + pub(crate) const ERC20_CONTRACT_PATH: &str = "starknet_programs/ERC20.json"; + pub(crate) const TEST_CONTRACT_PATH: &str = "starknet_programs/fibonacci.json"; + + lazy_static::lazy_static! { + // Addresses. + pub(crate) static ref TEST_ACCOUNT_CONTRACT_ADDRESS: Address = Address(felt_str!("257")); + pub(crate) static ref TEST_CONTRACT_ADDRESS: Address = Address(felt_str!("256")); + pub(crate) static ref TEST_SEQUENCER_ADDRESS: Address = + Address(felt_str!("4096")); + pub(crate) static ref TEST_ERC20_CONTRACT_ADDRESS: Address = + Address(felt_str!("4097")); + + + // Class hashes. + pub(crate) static ref TEST_ACCOUNT_CONTRACT_CLASS_HASH: Felt252 = felt_str!("273"); + pub(crate) static ref TEST_CLASS_HASH: Felt252 = felt_str!("272"); + pub(crate) static ref TEST_EMPTY_CONTRACT_CLASS_HASH: Felt252 = felt_str!("274"); + pub(crate) static ref TEST_ERC20_CONTRACT_CLASS_HASH: Felt252 = felt_str!("4112"); + pub(crate) static ref TEST_FIB_COMPILED_CONTRACT_CLASS_HASH: Felt252 = felt_str!("1948962768849191111780391610229754715773924969841143100991524171924131413970"); + + // Storage keys. + pub(crate) static ref TEST_ERC20_ACCOUNT_BALANCE_KEY: Felt252 = + felt_str!("1192211877881866289306604115402199097887041303917861778777990838480655617515"); + pub(crate) static ref TEST_ERC20_SEQUENCER_BALANCE_KEY: Felt252 = + felt_str!("3229073099929281304021185011369329892856197542079132996799046100564060768274"); + pub(crate) static ref TEST_ERC20_BALANCE_KEY_1: Felt252 = + felt_str!("1192211877881866289306604115402199097887041303917861778777990838480655617516"); + pub(crate) static ref TEST_ERC20_BALANCE_KEY_2: Felt252 = + felt_str!("3229073099929281304021185011369329892856197542079132996799046100564060768275"); + + pub(crate) static ref TEST_ERC20_DEPLOYED_ACCOUNT_BALANCE_KEY: Felt252 = + felt_str!("2542253978940891427830343982984992363331567580652119103860970381451088310289"); + + // Others. + // Blockifier had this value hardcoded to 2. + pub(crate) static ref ACTUAL_FEE: Felt252 = Felt252::from(10000000); + } + + pub(crate) fn new_starknet_block_context_for_testing() -> BlockContext { + BlockContext::new( + StarknetOsConfig::new( + StarknetChainId::TestNet.to_felt(), + TEST_ERC20_CONTRACT_ADDRESS.clone(), + 1, + ), + 0, + 0, + DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS.clone(), + 1_000_000, + 0, + BlockInfo::empty(TEST_SEQUENCER_ADDRESS.clone()), + HashMap::default(), + true, + ) + } + + pub(crate) fn create_account_tx_test_state( + ) -> Result<(BlockContext, CachedState), Box> { + let block_context = new_starknet_block_context_for_testing(); + + let test_contract_class_hash = felt_to_hash(&TEST_CLASS_HASH.clone()); + let test_account_contract_class_hash = + felt_to_hash(&TEST_ACCOUNT_CONTRACT_CLASS_HASH.clone()); + let test_erc20_class_hash = felt_to_hash(&TEST_ERC20_CONTRACT_CLASS_HASH.clone()); + let class_hash_to_class = HashMap::from([ + ( + test_account_contract_class_hash, + ContractClass::from_path(ACCOUNT_CONTRACT_PATH)?, + ), + ( + test_contract_class_hash, + ContractClass::from_path(TEST_CONTRACT_PATH)?, + ), + ( + test_erc20_class_hash, + ContractClass::from_path(ERC20_CONTRACT_PATH)?, + ), + ]); + + let test_contract_address = TEST_CONTRACT_ADDRESS.clone(); + let test_account_contract_address = TEST_ACCOUNT_CONTRACT_ADDRESS.clone(); + let test_erc20_address = block_context + .starknet_os_config() + .fee_token_address() + .clone(); + let address_to_class_hash = HashMap::from([ + (test_contract_address, test_contract_class_hash), + ( + test_account_contract_address, + test_account_contract_class_hash, + ), + (test_erc20_address.clone(), test_erc20_class_hash), + ]); + + let test_erc20_account_balance_key = TEST_ERC20_ACCOUNT_BALANCE_KEY.clone(); + + let storage_view = HashMap::from([( + (test_erc20_address, test_erc20_account_balance_key), + ACTUAL_FEE.clone(), + )]); + + let cached_state = CachedState::new( + { + let mut state_reader = InMemoryStateReader::default(); + for (contract_address, class_hash) in address_to_class_hash { + let storage_keys: HashMap<(Address, ClassHash), Felt252> = storage_view + .iter() + .filter_map(|((address, storage_key), storage_value)| { + (address == &contract_address).then_some(( + (address.clone(), felt_to_hash(storage_key)), + storage_value.clone(), + )) + }) + .collect(); + + let stored: HashMap = storage_keys; + + state_reader + .address_to_class_hash_mut() + .insert(contract_address.clone(), class_hash); + + state_reader + .address_to_nonce_mut() + .insert(contract_address.clone(), Felt252::zero()); + state_reader.address_to_storage_mut().extend(stored); + } + for (class_hash, contract_class) in class_hash_to_class { + state_reader.class_hash_to_compiled_class_mut().insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); + } + Arc::new(state_reader) + }, + HashMap::new(), + ); + + Ok((block_context, cached_state)) + } } #[cfg(test)] diff --git a/src/testing/erc20.rs b/tests/complex_contracts/erc20.rs similarity index 85% rename from src/testing/erc20.rs rename to tests/complex_contracts/erc20.rs index f29f94b0b..dc249032a 100644 --- a/src/testing/erc20.rs +++ b/tests/complex_contracts/erc20.rs @@ -1,43 +1,21 @@ -#![allow(unused_imports)] -use std::{collections::HashMap, io::Bytes, path::Path, sync::Arc}; +use std::{collections::HashMap, sync::Arc}; -use crate::{ +use cairo_vm::felt::{felt_str, Felt252}; +use num_traits::Zero; +use starknet_in_rust::{ call_contract, - definitions::{ - block_context::{BlockContext, StarknetChainId}, - constants::CONSTRUCTOR_ENTRY_POINT_SELECTOR, - }, + definitions::block_context::{BlockContext, StarknetChainId}, execution::{ execution_entry_point::ExecutionEntryPoint, CallType, TransactionExecutionContext, }, - services::api::contract_classes::{ - compiled_class::CompiledClass, deprecated_contract_class::ContractClass, - }, + services::api::contract_classes::compiled_class::CompiledClass, state::{ - cached_state::CachedState, - in_memory_state_reader::InMemoryStateReader, - state_api::{State, StateReader}, + cached_state::CachedState, in_memory_state_reader::InMemoryStateReader, state_api::State, ExecutionResourcesManager, }, - transaction::{error::TransactionError, DeployAccount, InvokeFunction}, - utils::calculate_sn_keccak, - EntryPointType, Felt252, -}; -use cairo_lang_starknet::casm_contract_class::CasmContractClass; -use cairo_vm::felt::felt_str; -use lazy_static::lazy_static; -use num_traits::Zero; -pub const ERC20_CONTRACT_PATH: &str = "starknet_programs/cairo2/ERC20.casm"; -use crate::{ - state::state_cache::StorageEntry, - utils::{felt_to_hash, Address, ClassHash}, -}; - -use super::{ - new_starknet_block_context_for_testing, ACCOUNT_CONTRACT_PATH, ACTUAL_FEE, - TEST_ACCOUNT_CONTRACT_ADDRESS, TEST_ACCOUNT_CONTRACT_CLASS_HASH, TEST_CLASS_HASH, - TEST_CONTRACT_ADDRESS, TEST_CONTRACT_PATH, TEST_ERC20_ACCOUNT_BALANCE_KEY, - TEST_ERC20_CONTRACT_CLASS_HASH, + transaction::DeployAccount, + utils::{calculate_sn_keccak, Address, ClassHash}, + CasmContractClass, EntryPointType, }; #[test] @@ -130,7 +108,7 @@ fn test_erc20_cairo2() { &mut resources_manager, &mut tx_execution_context, false, - block_context.invoke_tx_max_n_steps, + block_context.invoke_tx_max_n_steps(), ) .unwrap(); let erc20_address = call_info.call_info.unwrap().retdata.get(0).unwrap().clone(); diff --git a/tests/complex_contracts/mod.rs b/tests/complex_contracts/mod.rs index c6000a3a9..1131126f3 100644 --- a/tests/complex_contracts/mod.rs +++ b/tests/complex_contracts/mod.rs @@ -1,3 +1,4 @@ pub mod amm_contracts; +pub mod erc20; pub mod nft; pub mod utils; From 21dab2c5bf81cadf4642d4023d266cead6942e49 Mon Sep 17 00:00:00 2001 From: MrAzteca Date: Tue, 26 Sep 2023 16:25:51 +0200 Subject: [PATCH 42/44] Remove `serde_json_pythonic`. (#1047) * Remove `serde_json_pythonic`. * Fix JSON formatter on `deprecated_contract_class.rs`. * Fix hash JSON formatter (non-ascii support). * Add unwrap reasoning comment. --- Cargo.lock | 1 - Cargo.toml | 1 - .../deprecated_contract_address.rs | 2 +- .../sierra_contract_address.rs | 74 +++++++++++++++++-- 4 files changed, 70 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6be0d80bf..e32e2df26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3861,7 +3861,6 @@ dependencies = [ "pretty_assertions_sorted", "serde", "serde_json", - "serde_json_pythonic", "sha3", "starknet", "starknet-crypto 0.5.1", diff --git a/Cargo.toml b/Cargo.toml index aa277e89c..0277940d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,6 @@ once_cell = "1.17.1" starknet = { workspace = true } base64 = { version = "0.21.0", default-features = false, features = ["alloc"] } flate2 = "1.0.25" -serde_json_pythonic = "0.1.2" [dev-dependencies] assert_matches = "1.5.0" diff --git a/src/core/contract_address/deprecated_contract_address.rs b/src/core/contract_address/deprecated_contract_address.rs index 325902d45..07e7e2911 100644 --- a/src/core/contract_address/deprecated_contract_address.rs +++ b/src/core/contract_address/deprecated_contract_address.rs @@ -158,7 +158,7 @@ impl serde_json::ser::Formatter for PythonDefaultFormatter { } else { let buf = c.encode_utf16(&mut buf); for i in buf { - write!(writer, r"\u{:4x}", i)?; + write!(writer, r"\u{:04x}", i)?; } } } diff --git a/src/core/contract_address/sierra_contract_address.rs b/src/core/contract_address/sierra_contract_address.rs index 1bbcfb1e9..6cef44199 100644 --- a/src/core/contract_address/sierra_contract_address.rs +++ b/src/core/contract_address/sierra_contract_address.rs @@ -4,7 +4,10 @@ use cairo_lang_starknet::{ contract_class::{ContractClass as SierraContractClass, ContractEntryPoint}, }; use cairo_vm::felt::Felt252; +use serde::Serialize; +use serde_json::ser::Formatter; use starknet_crypto::{poseidon_hash_many, FieldElement, PoseidonHasher}; +use std::io::{self, Cursor}; const CONTRACT_CLASS_VERSION: &[u8] = b"CONTRACT_CLASS_V0.1.0"; @@ -60,14 +63,22 @@ pub fn compute_sierra_class_hash( hasher.update(constructors); // Hash abi - let abi = serde_json_pythonic::to_string_pythonic( - &contract_class + let abi = { + let mut buf = Cursor::new(Vec::new()); + let mut fmt = serde_json::Serializer::with_formatter(&mut buf, PythonJsonFormatter); + + contract_class .abi .as_ref() .ok_or(ContractAddressError::MissingAbi)? - .items, - ) - .map_err(|_| ContractAddressError::MissingAbi)?; + .items + .serialize(&mut fmt) + .map_err(|_| ContractAddressError::MissingAbi)?; + + // Note: The following unwrap should never be triggered as long as serde_json generates + // UTF-8 encoded data, which in practice means it should never panic. + String::from_utf8(buf.into_inner()).unwrap() + }; let abi_hash = FieldElement::from_byte_slice_be(&starknet_keccak(abi.as_bytes()).to_bytes_be()) .map_err(|_err| { @@ -142,3 +153,56 @@ mod tests { ) } } + +struct PythonJsonFormatter; + +impl Formatter for PythonJsonFormatter { + fn begin_array_value(&mut self, writer: &mut W, first: bool) -> io::Result<()> + where + W: ?Sized + io::Write, + { + if first { + Ok(()) + } else { + writer.write_all(b", ") + } + } + + fn begin_object_key(&mut self, writer: &mut W, first: bool) -> io::Result<()> + where + W: ?Sized + io::Write, + { + if first { + Ok(()) + } else { + writer.write_all(b", ") + } + } + + fn begin_object_value(&mut self, writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + writer.write_all(b": ") + } + + fn write_string_fragment(&mut self, writer: &mut W, fragment: &str) -> io::Result<()> + where + W: ?Sized + io::Write, + { + let mut buf = [0, 0]; + + for c in fragment.chars() { + if c.is_ascii() { + writer.write_all(&[c as u8])?; + } else { + let buf = c.encode_utf16(&mut buf); + for i in buf { + write!(writer, r"\u{i:04x}")?; + } + } + } + + Ok(()) + } +} From 9c92f9942b63d2b97e694663b94e45773d8781b7 Mon Sep 17 00:00:00 2001 From: MrAzteca Date: Tue, 26 Sep 2023 17:26:49 +0200 Subject: [PATCH 43/44] Add debug logging. (#1018) * Add `tracing` and update dependencies. * Configure the example to use tracing logging (and make it work again). * Add tracing logging. * Add error logging. * Fix error logging. * Reduce the amount of spam logged. * Update `README.md`. * Fix `Makefile` dependencies. * Remove `Debug` trait dependency. * Update `Cargo.lock` after merge. * Fix warnings. * Fix formatting. --------- Co-authored-by: Esteve Soler Arderiu --- Cargo.lock | 244 +++++++++++++++++++++------- Cargo.toml | 37 +++-- Makefile | 8 +- README.md | 11 +- examples/contract_execution/main.rs | 10 +- rpc_state_reader/tests/sir_tests.rs | 1 + src/lib.rs | 88 +++++----- src/state/cached_state.rs | 2 +- src/transaction/declare.rs | 9 + src/transaction/declare_v2.rs | 10 ++ src/transaction/deploy.rs | 9 + src/transaction/deploy_account.rs | 10 ++ src/transaction/invoke_function.rs | 26 +-- src/transaction/l1_handler.rs | 28 ++-- src/transaction/mod.rs | 1 + 15 files changed, 339 insertions(+), 155 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e32e2df26..7aa1e70ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,7 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -198,7 +198,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -512,7 +512,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -737,9 +737,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "bytestring" @@ -983,7 +983,7 @@ checksum = "170838817fc33ddb65e0a9480526df0b226b148a0fca0a5cd7071be4c6683157" dependencies = [ "cairo-lang-debug", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -1308,9 +1308,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.28" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ed24df0632f708f5f6d8082675bef2596f7084dee3dd55f632290bf35bfe0f" +checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1360,7 +1360,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -1465,9 +1465,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" +checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" dependencies = [ "generic-array", "subtle", @@ -1491,7 +1491,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f34ba9a9bcb8645379e9de8cb3ecfcf4d1c85ba66d90deb3259206fa5aa193b" dependencies = [ "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -1548,7 +1548,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -1570,7 +1570,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core 0.20.3", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -1867,7 +1867,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -2385,7 +2385,7 @@ dependencies = [ "petgraph", "pico-args", "regex", - "regex-syntax", + "regex-syntax 0.7.5", "string_cache", "term", "tiny-keccak", @@ -2481,6 +2481,15 @@ dependencies = [ "hashbrown 0.12.3", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "matrixmultiply" version = "0.2.4" @@ -2492,9 +2501,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.2" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "memmap2" @@ -2586,6 +2595,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.4" @@ -2666,9 +2685,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] @@ -2694,6 +2713,12 @@ dependencies = [ "num-traits 0.2.16", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parity-scale-codec" version = "3.6.4" @@ -2710,9 +2735,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.5" +version = "3.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" +checksum = "7ac464815d51fff2f64d690bf6ea4442d365e53495d50737685cfecfa3dd3f62" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2835,7 +2860,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -3050,27 +3075,42 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" +checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.3.8", + "regex-syntax 0.7.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] name = "regex-automata" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.7.5", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.7.5" @@ -3386,7 +3426,7 @@ checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -3485,7 +3525,7 @@ dependencies = [ "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -3497,7 +3537,7 @@ dependencies = [ "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -3532,6 +3572,15 @@ dependencies = [ "keccak", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -3616,7 +3665,7 @@ checksum = "8fcb61961b91757a9bc2d11549067445b2f921bd957f53710db35449767a1ba3" dependencies = [ "starknet-accounts", "starknet-contract", - "starknet-core", + "starknet-core 0.5.1", "starknet-crypto 0.6.0", "starknet-ff", "starknet-macros", @@ -3631,7 +3680,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "111ed887e4db14f0df1f909905e7737e4730770c8ed70997b58a71d5d940daac" dependencies = [ "async-trait", - "starknet-core", + "starknet-core 0.5.1", "starknet-providers", "starknet-signers", "thiserror", @@ -3647,7 +3696,7 @@ dependencies = [ "serde_json", "serde_with 2.3.3", "starknet-accounts", - "starknet-core", + "starknet-core 0.5.1", "starknet-providers", "thiserror", ] @@ -3670,6 +3719,24 @@ dependencies = [ "starknet-ff", ] +[[package]] +name = "starknet-core" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b796a32a7400f7d85e95d3900b5cee7a392b2adbf7ad16093ed45ec6f8d85de6" +dependencies = [ + "base64 0.21.3", + "flate2", + "hex", + "serde", + "serde_json", + "serde_json_pythonic", + "serde_with 2.3.3", + "sha3", + "starknet-crypto 0.6.0", + "starknet-ff", +] + [[package]] name = "starknet-crypto" version = "0.5.1" @@ -3718,7 +3785,7 @@ checksum = "af6527b845423542c8a16e060ea1bc43f67229848e7cd4c4d80be994a84220ce" dependencies = [ "starknet-curve 0.4.0", "starknet-ff", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -3756,12 +3823,12 @@ dependencies = [ [[package]] name = "starknet-macros" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a5865ee0ed22ade86bdf45e7c09c5641f1c59ccae12c21ecde535b2b6bf64a" +checksum = "ef846b6bb48fc8c3e9a2aa9b5b037414f04a908d9db56493a3ae69a857eb2506" dependencies = [ - "starknet-core", - "syn 2.0.29", + "starknet-core 0.6.0", + "syn 2.0.31", ] [[package]] @@ -3779,7 +3846,7 @@ dependencies = [ "serde", "serde_json", "serde_with 2.3.3", - "starknet-core", + "starknet-core 0.5.1", "thiserror", "url", ] @@ -3811,7 +3878,7 @@ dependencies = [ "crypto-bigint", "eth-keystore", "rand", - "starknet-core", + "starknet-core 0.5.1", "starknet-crypto 0.6.0", "thiserror", ] @@ -3861,11 +3928,14 @@ dependencies = [ "pretty_assertions_sorted", "serde", "serde_json", + "serde_json_pythonic", "sha3", "starknet", "starknet-crypto 0.5.1", "starknet_api", "thiserror", + "tracing", + "tracing-subscriber", ] [[package]] @@ -3931,9 +4001,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.29" +version = "2.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" dependencies = [ "proc-macro2", "quote", @@ -4007,22 +4077,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" +checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" +checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -4045,6 +4115,16 @@ dependencies = [ "thiserror-impl-no-std", ] +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "time" version = "0.3.26" @@ -4123,7 +4203,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -4152,9 +4232,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +checksum = "de0a3ab2091e52d7299a39d098e200114a972df0a7724add02a273aa9aada592" dependencies = [ "serde", "serde_spanned", @@ -4173,9 +4253,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.14" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.0.0", "serde", @@ -4199,9 +4279,21 @@ dependencies = [ "cfg-if", "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.31", +] + [[package]] name = "tracing-core" version = "0.1.31" @@ -4209,6 +4301,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] @@ -4334,6 +4456,12 @@ dependencies = [ "serde", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "version_check" version = "0.9.4" @@ -4376,7 +4504,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", "wasm-bindgen-shared", ] @@ -4410,7 +4538,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4609,7 +4737,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0277940d5..a4eef6dd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,52 +15,55 @@ metrics = [] members = ["cli", "fuzzer", "rpc_state_reader"] [workspace.dependencies] -cairo-vm = { version = "0.8.5", features = ["cairo-1-hints"] } -starknet_api = "0.4.1" -num-traits = "0.2.15" -starknet = "0.5.0" -thiserror = "1.0.32" -cairo-lang-starknet = "2.1.0-rc4" cairo-lang-casm = "2.1.0-rc4" cairo-lang-runner = "2.1.0-rc4" cairo-lang-sierra = "2.1.0-rc4" +cairo-lang-starknet = "2.1.0-rc4" cairo-lang-utils = "2.1.0-rc4" +cairo-vm = { version = "0.8.5", features = ["cairo-1-hints"] } +num-traits = "0.2.15" +starknet = "0.5.0" +starknet_api = "0.4.1" +thiserror = "1.0.32" [dependencies] -cairo-lang-starknet = { workspace = true } +anyhow = "1.0.66" +base64 = { version = "0.21.0", default-features = false, features = ["alloc"] } cairo-lang-casm = { workspace = true } cairo-lang-runner = { workspace = true } cairo-lang-sierra = { workspace = true } +cairo-lang-starknet = { workspace = true } cairo-lang-utils = { workspace = true } cairo-vm = { workspace = true, features = ["cairo-1-hints"] } +flate2 = "1.0.25" getset = "0.1.2" +hex = "0.4.3" +# TODO: Replace with sha3. We should look how to integrate it correctly to calculate sn_keccak +keccak = "0.1.3" lazy_static = "1.4.0" +mimalloc = { version = "0.1.29", default-features = false, optional = true } num-bigint = { version = "0.4", features = ["serde"] } num-integer = "0.1.45" num-traits = { workspace = true } +once_cell = "1.17.1" +sha3 = "0.10.1" serde = { version = "1.0.152", features = ["derive"] } serde_json = { version = "1.0", features = [ "arbitrary_precision", "raw_value", ] } -sha3 = "0.10.1" -# TODO: Replace with sha3. We should look how to integrate it correctly to calculate sn_keccak -keccak = "0.1.3" +serde_json_pythonic = "0.1.2" +starknet = { workspace = true } starknet_api = { workspace = true } starknet-crypto = "0.5.1" thiserror = { workspace = true } -mimalloc = { version = "0.1.29", default-features = false, optional = true } -hex = "0.4.3" -anyhow = "1.0.66" -once_cell = "1.17.1" -starknet = { workspace = true } -base64 = { version = "0.21.0", default-features = false, features = ["alloc"] } -flate2 = "1.0.25" +tracing = "0.1.37" [dev-dependencies] assert_matches = "1.5.0" coverage-helper = "0.2.0" pretty_assertions_sorted = "1.2.3" +tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } [[bench]] path = "bench/internals.rs" diff --git a/Makefile b/Makefile index 689a4695b..2d90d94cf 100644 --- a/Makefile +++ b/Makefile @@ -138,10 +138,10 @@ cairo-%.tar: # Normal rules. # ================= -build: compile-cairo compile-starknet +build: compile-cairo compile-starknet compile-cairo-1-casm compile-cairo-1-sierra compile-cairo-2-casm compile-cairo-2-sierra cargo build --release --workspace -check: compile-cairo compile-starknet +check: compile-cairo compile-starknet compile-cairo-1-casm compile-cairo-1-sierra compile-cairo-2-casm compile-cairo-2-sierra cargo check --workspace --all-targets deps: check-python-version build-cairo-2-compiler build-cairo-1-compiler @@ -183,10 +183,10 @@ test: compile-cairo compile-starknet compile-cairo-1-casm compile-cairo-1-sierra $(MAKE) test-cairo-2 test-cairo-1: - cargo nextest run --workspace --all-targets --features=cairo_1_tests + cargo nextest run --workspace --all-targets --features=cairo_1_tests,metrics test-cairo-2: - cargo nextest run --workspace --all-targets + cargo nextest run --workspace --all-targets --features=metrics test-doctests: cargo test --workspace --doc diff --git a/README.md b/README.md index 1b754db81..18929226d 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ It makes use of [cairo-vm](https://github.com/lambdaclass/cairo-vm), the Rust im ### Dependencies - Rust 1.70 - A working installation of cairo-lang 0.12 (for compiling the cairo files) -- [Optional, for testing purposes] Heaptrack +- [Optional, for testing purposes] Heaptrack ### Installation @@ -109,6 +109,13 @@ You can find a tutorial on running contracts [here](/examples/contract_execution ### Using the CLI You can find an example on how to use the CLI [here](/docs/CLI_USAGE_EXAMPLE.md) +### Customization + +#### Logging configuration + +This project uses the [`tracing`](https://crates.io/crates/tracing) crate as a library. Check out +its documentation for more information. + ### Testing [Add an Infura API key.](#rpc-state-reader) @@ -138,7 +145,7 @@ $ make benchmark ## 🛠 Contributing -The open source community is a fantastic place for learning, inspiration, and creation, and this is all thanks to contributions from people like you. Your contributions are **greatly appreciated**. +The open source community is a fantastic place for learning, inspiration, and creation, and this is all thanks to contributions from people like you. Your contributions are **greatly appreciated**. If you have any suggestions for how to improve the project, please feel free to fork the repo and create a pull request, or [open an issue](https://github.com/lambdaclass/starknet_in_rust/issues/new?labels=enhancement&title=feat%3A+) with the tag 'enhancement'. diff --git a/examples/contract_execution/main.rs b/examples/contract_execution/main.rs index 2e6e21086..a82aa4f9a 100644 --- a/examples/contract_execution/main.rs +++ b/examples/contract_execution/main.rs @@ -22,8 +22,16 @@ use starknet_in_rust::{ utils::{calculate_sn_keccak, Address}, }; use std::{collections::HashMap, path::Path, sync::Arc}; +use tracing_subscriber::EnvFilter; fn main() { + tracing::subscriber::set_global_default( + tracing_subscriber::FmtSubscriber::builder() + .with_env_filter(EnvFilter::from_default_env()) + .finish(), + ) + .unwrap(); + // replace this with the path to your compiled contract let contract_path = "starknet_programs/fibonacci.json"; @@ -31,7 +39,7 @@ fn main() { let entry_point: &str = "fib"; // replace this with the arguments for the entrypoint - let calldata: Vec = [1.into(), 1.into(), 10.into()].to_vec(); + let calldata: Vec = [10.into()].to_vec(); let retdata = test_contract(contract_path, entry_point, calldata); diff --git a/rpc_state_reader/tests/sir_tests.rs b/rpc_state_reader/tests/sir_tests.rs index 75e75595b..d9fba2df0 100644 --- a/rpc_state_reader/tests/sir_tests.rs +++ b/rpc_state_reader/tests/sir_tests.rs @@ -36,6 +36,7 @@ use test_case::test_case; use rpc_state_reader::rpc_state::*; +#[derive(Debug)] pub struct RpcStateReader(RpcState); impl StateReader for RpcStateReader { diff --git a/src/lib.rs b/src/lib.rs index fd8747a73..fd4c5538b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,26 +2,22 @@ #![forbid(unsafe_code)] #![cfg_attr(coverage_nightly, feature(coverage_attribute))] -use std::{collections::HashMap, sync::Arc}; - use crate::{ + definitions::block_context::BlockContext, execution::{ - execution_entry_point::ExecutionEntryPoint, CallType, TransactionExecutionContext, - TransactionExecutionInfo, + execution_entry_point::{ExecutionEntryPoint, ExecutionResult}, + CallType, TransactionExecutionContext, TransactionExecutionInfo, }, state::{ + cached_state::CachedState, state_api::{State, StateReader}, ExecutionResourcesManager, }, - transaction::{error::TransactionError, Transaction}, + transaction::{error::TransactionError, fee::calculate_tx_fee, L1Handler, Transaction}, + utils::Address, }; - use cairo_vm::felt::Felt252; -use definitions::block_context::BlockContext; -use execution::execution_entry_point::ExecutionResult; -use state::cached_state::CachedState; -use transaction::{fee::calculate_tx_fee, L1Handler}; -use utils::Address; +use std::{collections::HashMap, sync::Arc}; #[cfg(test)] #[macro_use] @@ -204,52 +200,48 @@ pub fn execute_transaction( #[cfg(test)] mod test { - use std::collections::HashMap; - use std::path::PathBuf; - use std::sync::Arc; - - use crate::core::contract_address::{compute_deprecated_class_hash, compute_sierra_class_hash}; - use crate::definitions::constants::INITIAL_GAS_COST; - use crate::definitions::{ - block_context::StarknetChainId, - constants::{ - EXECUTE_ENTRY_POINT_SELECTOR, VALIDATE_DECLARE_ENTRY_POINT_SELECTOR, - VALIDATE_ENTRY_POINT_SELECTOR, - }, - }; - use crate::estimate_fee; - use crate::estimate_message_fee; - use crate::hash_utils::calculate_contract_address; - use crate::services::api::contract_classes::deprecated_contract_class::ContractClass; - use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; - use crate::state::state_api::State; - use crate::transaction::{ - Declare, DeclareV2, Deploy, DeployAccount, InvokeFunction, L1Handler, Transaction, - }; - use crate::utils::felt_to_hash; - use crate::utils::test_utils::{ - create_account_tx_test_state, TEST_ACCOUNT_CONTRACT_ADDRESS, TEST_CONTRACT_ADDRESS, - TEST_CONTRACT_PATH, TEST_FIB_COMPILED_CONTRACT_CLASS_HASH, - }; - use cairo_lang_starknet::casm_contract_class::CasmContractClass; - use cairo_lang_starknet::contract_class::ContractClass as SierraContractClass; - use cairo_vm::felt::{felt_str, Felt252}; - use num_traits::{Num, One, Zero}; - use crate::{ call_contract, - definitions::block_context::BlockContext, + core::contract_address::{compute_deprecated_class_hash, compute_sierra_class_hash}, + definitions::{ + block_context::{BlockContext, StarknetChainId}, + constants::{ + EXECUTE_ENTRY_POINT_SELECTOR, INITIAL_GAS_COST, + VALIDATE_DECLARE_ENTRY_POINT_SELECTOR, VALIDATE_ENTRY_POINT_SELECTOR, + }, + }, + estimate_fee, estimate_message_fee, + hash_utils::calculate_contract_address, + services::api::contract_classes::{ + compiled_class::CompiledClass, + deprecated_contract_class::{ContractClass, EntryPointType}, + }, simulate_transaction, state::{ cached_state::CachedState, in_memory_state_reader::InMemoryStateReader, - ExecutionResourcesManager, + state_api::State, ExecutionResourcesManager, + }, + transaction::{ + Declare, DeclareV2, Deploy, DeployAccount, InvokeFunction, L1Handler, Transaction, + }, + utils::{ + felt_to_hash, + test_utils::{ + create_account_tx_test_state, TEST_ACCOUNT_CONTRACT_ADDRESS, TEST_CONTRACT_ADDRESS, + TEST_CONTRACT_PATH, TEST_FIB_COMPILED_CONTRACT_CLASS_HASH, + }, + Address, ClassHash, }, - utils::{Address, ClassHash}, }; - - use crate::services::api::contract_classes::compiled_class::CompiledClass; + use cairo_lang_starknet::{ + casm_contract_class::CasmContractClass, + contract_class::ContractClass as SierraContractClass, + }; + use cairo_vm::felt::{felt_str, Felt252}; use lazy_static::lazy_static; + use num_traits::{Num, One, Zero}; use pretty_assertions_sorted::assert_eq; + use std::{collections::HashMap, path::PathBuf, sync::Arc}; lazy_static! { // include_str! doesn't seem to work in CI diff --git a/src/state/cached_state.rs b/src/state/cached_state.rs index dfa8f7efc..bf286eac5 100644 --- a/src/state/cached_state.rs +++ b/src/state/cached_state.rs @@ -921,7 +921,7 @@ mod tests { #[test] fn test_cache_hit_miss_counter() { let state_reader = Arc::new(InMemoryStateReader::default()); - let mut cached_state = CachedState::new(state_reader, None, None); + let mut cached_state = CachedState::new(state_reader, HashMap::default()); let address = Address(1.into()); diff --git a/src/transaction/declare.rs b/src/transaction/declare.rs index f79005bab..c9b91857a 100644 --- a/src/transaction/declare.rs +++ b/src/transaction/declare.rs @@ -30,6 +30,7 @@ use num_traits::Zero; use super::fee::charge_fee; use super::{verify_version, Transaction}; use crate::services::api::contract_classes::compiled_class::CompiledClass; +use std::fmt::Debug; use std::sync::Arc; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -264,6 +265,14 @@ impl Declare { /// Calculates actual fee used by the transaction using the execution /// info returned by apply(), then updates the transaction execution info with the data of the fee. + #[tracing::instrument(level = "debug", ret, err, skip(self, state, block_context), fields( + tx_type = ?TransactionType::Declare, + self.version = ?self.version, + self.class_hash = ?self.class_hash, + self.hash_value = ?self.hash_value, + self.sender_address = ?self.sender_address, + self.nonce = ?self.nonce, + ))] pub fn execute( &self, state: &mut CachedState, diff --git a/src/transaction/declare_v2.rs b/src/transaction/declare_v2.rs index 0faa548b8..781b21194 100644 --- a/src/transaction/declare_v2.rs +++ b/src/transaction/declare_v2.rs @@ -27,6 +27,7 @@ use cairo_lang_starknet::casm_contract_class::CasmContractClass; use cairo_lang_starknet::contract_class::ContractClass as SierraContractClass; use cairo_vm::felt::Felt252; use num_traits::Zero; +use std::fmt::Debug; use std::sync::Arc; /// Represents a declare transaction in the starknet network. @@ -295,6 +296,15 @@ impl DeclareV2 { /// ## Parameter: /// - state: An state that implements the State and StateReader traits. /// - block_context: The block that contains the execution context + #[tracing::instrument(level = "debug", ret, err, skip(self, state, block_context), fields( + tx_type = ?TransactionType::Declare, + self.version = ?self.version, + self.sierra_class_hash = ?self.sierra_class_hash, + self.compiled_class_hash = ?self.compiled_class_hash, + self.hash_value = ?self.hash_value, + self.sender_address = ?self.sender_address, + self.nonce = ?self.nonce, + ))] pub fn execute( &self, state: &mut CachedState, diff --git a/src/transaction/deploy.rs b/src/transaction/deploy.rs index 3a2474319..d7debc943 100644 --- a/src/transaction/deploy.rs +++ b/src/transaction/deploy.rs @@ -32,6 +32,7 @@ use cairo_vm::felt::Felt252; use num_traits::Zero; use super::Transaction; +use std::fmt::Debug; /// Represents a Deploy Transaction in the starknet network #[derive(Debug, Clone)] @@ -266,6 +267,14 @@ impl Deploy { /// ## Parameters /// - state: A state that implements the [`State`] and [`StateReader`] traits. /// - block_context: The block's execution context. + #[tracing::instrument(level = "debug", ret, err, skip(self, state, block_context), fields( + tx_type = ?TransactionType::Deploy, + self.version = ?self.version, + self.contract_hash = ?self.contract_hash, + self.hash_value = ?self.hash_value, + self.contract_address = ?self.contract_address, + self.contract_address_salt = ?self.contract_address_salt, + ))] pub fn execute( &self, state: &mut CachedState, diff --git a/src/transaction/deploy_account.rs b/src/transaction/deploy_account.rs index 673aa2053..09ee5f1b9 100644 --- a/src/transaction/deploy_account.rs +++ b/src/transaction/deploy_account.rs @@ -35,6 +35,7 @@ use crate::{ use cairo_vm::felt::Felt252; use getset::Getters; use num_traits::Zero; +use std::fmt::Debug; #[derive(Clone, Debug, PartialEq, Eq)] pub struct StateSelector { @@ -151,6 +152,15 @@ impl DeployAccount { } } + #[tracing::instrument(level = "debug", ret, err, skip(self, state, block_context), fields( + tx_type = ?TransactionType::DeployAccount, + self.version = ?self.version, + self.class_hash = ?self.class_hash, + self.hash_value = ?self.hash_value, + self.contract_address = ?self.contract_address, + self.contract_address_salt = ?self.contract_address_salt, + self.nonce = ?self.nonce, + ))] pub fn execute( &self, state: &mut CachedState, diff --git a/src/transaction/invoke_function.rs b/src/transaction/invoke_function.rs index 15552844a..ba2933bb0 100644 --- a/src/transaction/invoke_function.rs +++ b/src/transaction/invoke_function.rs @@ -1,3 +1,7 @@ +use super::{ + fee::{calculate_tx_fee, charge_fee}, + Transaction, +}; use crate::{ core::transaction_hash::{calculate_transaction_hash_common, TransactionHashPrefix}, definitions::{ @@ -11,27 +15,19 @@ use crate::{ execution_entry_point::{ExecutionEntryPoint, ExecutionResult}, CallInfo, TransactionExecutionContext, TransactionExecutionInfo, }, + services::api::contract_classes::deprecated_contract_class::EntryPointType, state::{ cached_state::{CachedState, TransactionalCachedState}, - ExecutionResourcesManager, - }, - state::{ state_api::{State, StateReader}, - StateDiff, + ExecutionResourcesManager, StateDiff, }, transaction::error::TransactionError, utils::{calculate_tx_resources, Address}, }; - -use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; use cairo_vm::felt::Felt252; use getset::Getters; use num_traits::Zero; - -use super::{ - fee::{calculate_tx_fee, charge_fee}, - Transaction, -}; +use std::fmt::Debug; /// Represents an InvokeFunction transaction in the starknet network. #[derive(Debug, Getters, Clone)] @@ -293,6 +289,14 @@ impl InvokeFunction { /// - state: A state that implements the [`State`] and [`StateReader`] traits. /// - block_context: The block's execution context. /// - remaining_gas: The amount of gas that the transaction disposes. + #[tracing::instrument(level = "debug", ret, err, skip(self, state, block_context), fields( + tx_type = ?TransactionType::InvokeFunction, + self.version = ?self.version, + self.hash_value = ?self.hash_value, + self.contract_address = ?self.contract_address, + self.entry_point_selector = ?self.entry_point_selector, + self.entry_point_type = ?self.entry_point_type, + ))] pub fn execute( &self, state: &mut CachedState, diff --git a/src/transaction/l1_handler.rs b/src/transaction/l1_handler.rs index bf52864de..641a5aaf5 100644 --- a/src/transaction/l1_handler.rs +++ b/src/transaction/l1_handler.rs @@ -1,12 +1,4 @@ -use crate::{ - execution::execution_entry_point::ExecutionResult, - services::api::contract_classes::deprecated_contract_class::EntryPointType, - state::cached_state::CachedState, -}; -use cairo_vm::felt::Felt252; -use getset::Getters; -use num_traits::Zero; - +use super::Transaction; use crate::{ core::transaction_hash::{calculate_transaction_hash_common, TransactionHashPrefix}, definitions::{ @@ -14,18 +6,21 @@ use crate::{ transaction_type::TransactionType, }, execution::{ - execution_entry_point::ExecutionEntryPoint, TransactionExecutionContext, - TransactionExecutionInfo, + execution_entry_point::{ExecutionEntryPoint, ExecutionResult}, + TransactionExecutionContext, TransactionExecutionInfo, }, + services::api::contract_classes::deprecated_contract_class::EntryPointType, state::{ + cached_state::CachedState, state_api::{State, StateReader}, ExecutionResourcesManager, }, transaction::{error::TransactionError, fee::calculate_tx_fee}, utils::{calculate_tx_resources, Address}, }; - -use super::Transaction; +use cairo_vm::felt::Felt252; +use getset::Getters; +use num_traits::Zero; #[allow(dead_code)] #[derive(Debug, Getters, Clone)] @@ -93,6 +88,13 @@ impl L1Handler { } /// Applies self to 'state' by executing the L1-handler entry point. + #[tracing::instrument(level = "debug", ret, err, skip(self, state, block_context), fields( + tx_type = ?TransactionType::L1Handler, + self.hash_value = ?self.hash_value, + self.contract_address = ?self.contract_address, + self.entry_point_selector = ?self.entry_point_selector, + self.nonce = ?self.nonce, + ))] pub fn execute( &self, state: &mut CachedState, diff --git a/src/transaction/mod.rs b/src/transaction/mod.rs index 645a08b8f..0009c2245 100644 --- a/src/transaction/mod.rs +++ b/src/transaction/mod.rs @@ -81,6 +81,7 @@ impl Transaction { Transaction::L1Handler(tx) => tx.execute(state, block_context, remaining_gas), } } + /// It creates a new transaction structure modificating the skip flags. It is meant to be used only to run a simulation ///## Parameters: ///- skip_validate: the transaction will not be verified. From 9388df01fb135ed40463c1abc5adfc5c2f010ef2 Mon Sep 17 00:00:00 2001 From: Juan Bono Date: Fri, 29 Sep 2023 17:13:57 -0300 Subject: [PATCH 44/44] Fix skip validate (#1053) * update version * fix skip validation for invoke txs * run fmt * fix clippy suggestion * simplify a bit the execute_tx function variants --- rpc_state_reader/src/rpc_state.rs | 11 +++++++ rpc_state_reader/tests/sir_tests.rs | 50 ++++++++++++++++++++++++++--- src/transaction/invoke_function.rs | 8 +++-- 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/rpc_state_reader/src/rpc_state.rs b/rpc_state_reader/src/rpc_state.rs index 3ff561339..8401a897b 100644 --- a/rpc_state_reader/src/rpc_state.rs +++ b/rpc_state_reader/src/rpc_state.rs @@ -11,6 +11,7 @@ use starknet_api::{ state::StorageKey, transaction::{Transaction as SNTransaction, TransactionHash}, }; +use starknet_in_rust::definitions::block_context::StarknetChainId; use std::{collections::HashMap, env, fmt::Display}; use thiserror::Error; @@ -24,6 +25,16 @@ pub enum RpcChain { TestNet2, } +impl From for StarknetChainId { + fn from(network: RpcChain) -> StarknetChainId { + match network { + RpcChain::MainNet => StarknetChainId::MainNet, + RpcChain::TestNet => StarknetChainId::TestNet, + RpcChain::TestNet2 => StarknetChainId::TestNet2, + } + } +} + impl fmt::Display for RpcChain { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/rpc_state_reader/tests/sir_tests.rs b/rpc_state_reader/tests/sir_tests.rs index d9fba2df0..41a705553 100644 --- a/rpc_state_reader/tests/sir_tests.rs +++ b/rpc_state_reader/tests/sir_tests.rs @@ -28,7 +28,7 @@ use starknet_in_rust::{ state_cache::StorageEntry, BlockInfo, }, - transaction::{InvokeFunction, Transaction}, + transaction::InvokeFunction, utils::{Address, ClassHash}, }; @@ -87,10 +87,12 @@ impl StateReader for RpcStateReader { } #[allow(unused)] -pub fn execute_tx( +pub fn execute_tx_configurable( tx_hash: &str, network: RpcChain, block_number: BlockNumber, + skip_validate: bool, + skip_nonce_check: bool, ) -> ( TransactionExecutionInfo, TransactionTrace, @@ -138,9 +140,9 @@ pub fn execute_tx( // Get transaction before giving ownership of the reader let tx_hash = TransactionHash(stark_felt!(tx_hash)); let tx = match rpc_reader.0.get_transaction(&tx_hash) { - SNTransaction::Invoke(tx) => Transaction::InvokeFunction( - InvokeFunction::from_invoke_transaction(tx, chain_id).unwrap(), - ), + SNTransaction::Invoke(tx) => InvokeFunction::from_invoke_transaction(tx, chain_id) + .unwrap() + .create_for_simulation(skip_validate, false, false, false, skip_nonce_check), _ => unimplemented!(), }; @@ -169,6 +171,30 @@ pub fn execute_tx( ) } +pub fn execute_tx( + tx_hash: &str, + network: RpcChain, + block_number: BlockNumber, +) -> ( + TransactionExecutionInfo, + TransactionTrace, + RpcTransactionReceipt, +) { + execute_tx_configurable(tx_hash, network, block_number, false, false) +} + +pub fn execute_tx_without_validate( + tx_hash: &str, + network: RpcChain, + block_number: BlockNumber, +) -> ( + TransactionExecutionInfo, + TransactionTrace, + RpcTransactionReceipt, +) { + execute_tx_configurable(tx_hash, network, block_number, true, true) +} + #[test] fn test_get_transaction_try_from() { let rpc_state = RpcState::new_infura(RpcChain::MainNet, BlockTag::Latest.into()); @@ -359,3 +385,17 @@ fn starknet_in_rust_test_case_reverted_tx(hash: &str, block_number: u64, chain: ); } } + +#[test_case( + "0x038c307a0a324dc92778820f2c6317f40157c06b12a7e537f7a16b2c015f64e7", + 274333-1, + RpcChain::MainNet +)] +fn test_validate_fee(hash: &str, block_number: u64, chain: RpcChain) { + let (tx_info, _trace, receipt) = execute_tx(hash, chain, BlockNumber(block_number)); + let (tx_info_without_fee, _trace, _receipt) = + execute_tx_without_validate(hash, chain, BlockNumber(block_number)); + + assert_eq!(tx_info.actual_fee, receipt.actual_fee); + assert!(tx_info_without_fee.actual_fee < tx_info.actual_fee); +} diff --git a/src/transaction/invoke_function.rs b/src/transaction/invoke_function.rs index ba2933bb0..a9c762995 100644 --- a/src/transaction/invoke_function.rs +++ b/src/transaction/invoke_function.rs @@ -244,8 +244,12 @@ impl InvokeFunction { remaining_gas: u128, ) -> Result { let mut resources_manager = ExecutionResourcesManager::default(); - let validate_info = - self.run_validate_entrypoint(state, &mut resources_manager, block_context)?; + let validate_info = if self.skip_validation { + None + } else { + self.run_validate_entrypoint(state, &mut resources_manager, block_context)? + }; + // Execute transaction let ExecutionResult { call_info,