diff --git a/crates/blockifier/src/transaction/transactions.rs b/crates/blockifier/src/transaction/transactions.rs index d20abdf981b..c641a07ca14 100644 --- a/crates/blockifier/src/transaction/transactions.rs +++ b/crates/blockifier/src/transaction/transactions.rs @@ -3,6 +3,11 @@ use std::sync::Arc; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::deprecated_contract_class::EntryPointType; +use starknet_api::executable_transaction::{ + DeclareTransaction as StarknetApiDeclareTx, + DeployAccountTransaction as StarknetApiDeployAccountTx, + InvokeTransaction as StarknetApiInvokeTx, +}; use starknet_api::transaction::{ AccountDeploymentData, Calldata, @@ -639,3 +644,254 @@ impl TransactionInfoCreator for L1HandlerTransaction { }) } } + +impl Executable for StarknetApiDeclareTx { + fn run_execute( + &self, + state: &mut S, + _resources: &mut ExecutionResources, + context: &mut EntryPointExecutionContext, + _remaining_gas: &mut u64, + ) -> TransactionExecutionResult> { + let class_hash = self.class_hash(); + match &self.tx { + starknet_api::transaction::DeclareTransaction::V0(_) + | starknet_api::transaction::DeclareTransaction::V1(_) + => { + if context.tx_context.block_context.versioned_constants.disable_cairo0_redeclaration + { + try_declare(self, state, class_hash, None)? + } else { + // We allow redeclaration of the class for backward compatibility. + // In the past, we allowed redeclaration of Cairo 0 contracts since there was + // no class commitment (so no need to check if the class is already declared). + state.set_contract_class(class_hash, contract_class(self)?)?; + } + } + starknet_api::transaction::DeclareTransaction::V2(DeclareTransactionV2 { + compiled_class_hash, + .. + }) + | starknet_api::transaction::DeclareTransaction::V3(DeclareTransactionV3 { + compiled_class_hash, + .. + }) => try_declare(self, state, class_hash, Some(*compiled_class_hash))?, + } + Ok(None) + } +} + +impl TransactionInfoCreator for StarknetApiDeclareTx { + fn create_tx_info(&self) -> TransactionInfo { + // TODO(Nir, 01/11/2023): Consider to move this (from all get_tx_info methods). + let common_fields = CommonAccountFields { + transaction_hash: self.tx_hash, + version: self.version(), + signature: self.signature(), + nonce: self.nonce(), + sender_address: self.sender_address(), + only_query: false, //QUESTION(AvivG): should get only_query from some source? + }; + + match &self.tx { + starknet_api::transaction::DeclareTransaction::V0(tx) + | starknet_api::transaction::DeclareTransaction::V1(tx) => { + TransactionInfo::Deprecated(DeprecatedTransactionInfo { + common_fields, + max_fee: tx.max_fee, + }) + } + starknet_api::transaction::DeclareTransaction::V2(tx) => { + TransactionInfo::Deprecated(DeprecatedTransactionInfo { + common_fields, + max_fee: tx.max_fee, + }) + } + starknet_api::transaction::DeclareTransaction::V3(tx) => { + TransactionInfo::Current(CurrentTransactionInfo { + common_fields, + resource_bounds: tx.resource_bounds, + tip: tx.tip, + nonce_data_availability_mode: tx.nonce_data_availability_mode, + fee_data_availability_mode: tx.fee_data_availability_mode, + paymaster_data: tx.paymaster_data.clone(), + account_deployment_data: tx.account_deployment_data.clone(), + }) + } + } + } +} + +impl Executable for StarknetApiDeployAccountTx { + fn run_execute( + &self, + state: &mut S, + resources: &mut ExecutionResources, + context: &mut EntryPointExecutionContext, + remaining_gas: &mut u64, + ) -> TransactionExecutionResult> { + let class_hash = self.class_hash(); + let ctor_context = ConstructorContext { + class_hash, + code_address: None, + storage_address: self.contract_address(), + caller_address: ContractAddress::default(), + }; + let call_info = execute_deployment( + state, + resources, + context, + ctor_context, + self.constructor_calldata(), + *remaining_gas, + )?; + update_remaining_gas(remaining_gas, &call_info); + + Ok(Some(call_info)) + } +} + +impl TransactionInfoCreator for StarknetApiDeployAccountTx { + fn create_tx_info(&self) -> TransactionInfo { + let common_fields = CommonAccountFields { + transaction_hash: self.tx_hash(), + version: self.version(), + signature: self.signature(), + nonce: self.nonce(), + sender_address: self.contract_address(), + only_query: false, //QUESTION(AvivG): should get only_query from some source? + }; + + match &self.tx { + starknet_api::transaction::DeployAccountTransaction::V1(tx) => { + TransactionInfo::Deprecated(DeprecatedTransactionInfo { + common_fields, + max_fee: tx.max_fee, + }) + } + starknet_api::transaction::DeployAccountTransaction::V3(tx) => { + TransactionInfo::Current(CurrentTransactionInfo { + common_fields, + resource_bounds: tx.resource_bounds, + tip: tx.tip, + nonce_data_availability_mode: tx.nonce_data_availability_mode, + fee_data_availability_mode: tx.fee_data_availability_mode, + paymaster_data: tx.paymaster_data.clone(), + account_deployment_data: AccountDeploymentData::default(), + }) + } + } + } +} + +impl Executable for StarknetApiInvokeTx { + fn run_execute( + &self, + state: &mut S, + resources: &mut ExecutionResources, + context: &mut EntryPointExecutionContext, + remaining_gas: &mut u64, + ) -> TransactionExecutionResult> { + let entry_point_selector = match &self.tx { + starknet_api::transaction::InvokeTransaction::V0(tx) => tx.entry_point_selector, + starknet_api::transaction::InvokeTransaction::V1(_) + | starknet_api::transaction::InvokeTransaction::V3(_) => { + selector_from_name(constants::EXECUTE_ENTRY_POINT_NAME) + } + }; + let storage_address = context.tx_context.tx_info.sender_address(); + let class_hash = state.get_class_hash_at(storage_address)?; + let execute_call = CallEntryPoint { + entry_point_type: EntryPointType::External, + entry_point_selector, + calldata: self.calldata(), + class_hash: None, + code_address: None, + storage_address, + caller_address: ContractAddress::default(), + call_type: CallType::Call, + initial_gas: *remaining_gas, + }; + + let call_info = execute_call.execute(state, resources, context).map_err(|error| { + TransactionExecutionError::ExecutionError { + error, + class_hash, + storage_address, + selector: entry_point_selector, + } + })?; + update_remaining_gas(remaining_gas, &call_info); + + Ok(Some(call_info)) + } +} + +impl TransactionInfoCreator for StarknetApiInvokeTx { + fn create_tx_info(&self) -> TransactionInfo { + let common_fields = CommonAccountFields { + transaction_hash: self.tx_hash(), + version: self.version(), + signature: self.signature(), + nonce: self.nonce(), + sender_address: self.sender_address(), + only_query: false, //QUESTION(AvivG): should get only_query from some source? + }; + + match &self.tx() { + starknet_api::transaction::InvokeTransaction::V0(tx) => { + TransactionInfo::Deprecated(DeprecatedTransactionInfo { + common_fields, + max_fee: tx.max_fee, + }) + } + starknet_api::transaction::InvokeTransaction::V1(tx) => { + TransactionInfo::Deprecated(DeprecatedTransactionInfo { + common_fields, + max_fee: tx.max_fee, + }) + } + starknet_api::transaction::InvokeTransaction::V3(tx) => { + TransactionInfo::Current(CurrentTransactionInfo { + common_fields, + resource_bounds: tx.resource_bounds, + tip: tx.tip, + nonce_data_availability_mode: tx.nonce_data_availability_mode, + fee_data_availability_mode: tx.fee_data_availability_mode, + paymaster_data: tx.paymaster_data.clone(), + account_deployment_data: tx.account_deployment_data.clone(), + }) + } + } + } +} + + +fn try_declare( + tx: &StarknetApiDeclareTx, + state: &mut S, + class_hash: ClassHash, + compiled_class_hash: Option, +) -> TransactionExecutionResult<()> { + match state.get_compiled_contract_class(class_hash) { + Err(StateError::UndeclaredClassHash(_)) => { + // Class is undeclared; declare it. + let contract_class = contract_class(tx)?; + state.set_contract_class(class_hash, contract_class)?; + if let Some(compiled_class_hash) = compiled_class_hash { + state.set_compiled_class_hash(class_hash, compiled_class_hash)?; + } + Ok(()) + } + Err(error) => Err(error)?, + Ok(_) => { + // Class is already declared, cannot redeclare. + Err(TransactionExecutionError::DeclareTransactionError { class_hash }) + } + } +} + +fn contract_class(tx: &StarknetApiDeclareTx) -> Result { + let contract_class = ContractClass::try_from(tx.class_info.contract_class.clone())?; + Ok(contract_class) +} \ No newline at end of file diff --git a/crates/starknet_api/src/executable_transaction.rs b/crates/starknet_api/src/executable_transaction.rs index d88e8d0cfe8..0dcc89d9ee0 100644 --- a/crates/starknet_api/src/executable_transaction.rs +++ b/crates/starknet_api/src/executable_transaction.rs @@ -168,6 +168,14 @@ impl DeclareTransaction { compiled_class_hash == supplied_compiled_class_hash } + + implement_inner_tx_getter_calls!( + (class_hash, ClassHash), + (nonce, Nonce), + (sender_address, ContractAddress), + (signature, TransactionSignature), + (version, TransactionVersion) + ); } #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]