From 3df0a3d7cb41d4cf4e60b727aa1ce74e07d1515d Mon Sep 17 00:00:00 2001 From: Gilad Chase Date: Tue, 7 Nov 2023 23:37:53 +0200 Subject: [PATCH] Add pre-validation checks to `PyValidator` --- crates/native_blockifier/src/py_validator.rs | 49 +++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/crates/native_blockifier/src/py_validator.rs b/crates/native_blockifier/src/py_validator.rs index a49ca1ee79..5ea3a3f054 100644 --- a/crates/native_blockifier/src/py_validator.rs +++ b/crates/native_blockifier/src/py_validator.rs @@ -1,12 +1,18 @@ use blockifier::state::cached_state::GlobalContractCache; +use blockifier::state::state_api::StateReader; +use blockifier::transaction::transaction_execution::Transaction; use pyo3::prelude::*; +use starknet_api::core::Nonce; +use starknet_api::hash::StarkFelt; use crate::errors::NativeBlockifierResult; use crate::py_block_executor::PyGeneralConfig; use crate::py_state_diff::PyBlockInfo; +use crate::py_transaction::py_tx; use crate::py_transaction_execution_info::{ PyCallInfo, PyTransactionExecutionInfo, PyVmExecutionResources, }; +use crate::py_utils::{py_enum_name, PyFelt}; use crate::state_readers::py_state_reader::PyStateReader; use crate::transaction_executor::TransactionExecutor; @@ -15,6 +21,7 @@ use crate::transaction_executor::TransactionExecutor; pub struct PyValidator { pub general_config: PyGeneralConfig, pub max_recursion_depth: usize, + pub max_privileged_nonce: Nonce, pub tx_executor: Option>, pub global_contract_cache: GlobalContractCache, } @@ -22,12 +29,17 @@ pub struct PyValidator { #[pymethods] impl PyValidator { #[new] - #[pyo3(signature = (general_config, max_recursion_depth))] - pub fn create(general_config: PyGeneralConfig, max_recursion_depth: usize) -> Self { + #[pyo3(signature = (general_config, max_recursion_depth, max_privileged_nonce))] + pub fn create( + general_config: PyGeneralConfig, + max_recursion_depth: usize, + max_privileged_nonce: PyFelt, + ) -> Self { let tx_executor = None; let validator = Self { general_config, max_recursion_depth, + max_privileged_nonce: Nonce(max_privileged_nonce.0), tx_executor, global_contract_cache: GlobalContractCache::default(), }; @@ -78,6 +90,38 @@ impl PyValidator { self.tx_executor().execute(tx, raw_contract_class, limit_execution_steps_by_resource_bounds) } + #[pyo3(signature = (tx, raw_contract_class, deploy_account_tx_hash))] + pub fn pre_validation_checks( + &mut self, + tx: &PyAny, + raw_contract_class: Option<&str>, + deploy_account_tx_hash: Option, + ) -> NativeBlockifierResult { + let tx_type: String = py_enum_name(tx, "tx_type")?; + let Transaction::AccountTransaction(account_tx) = py_tx(&tx_type, tx, raw_contract_class)? + else { + panic!("L1 handlers should not be validated separately, only as part of execution") + }; + + let account_tx_context = account_tx.get_account_tx_context(); + let nonce = self.tx_executor().state.get_nonce_at(account_tx_context.sender_address())?; + let tx_nonce = account_tx_context.nonce(); + + if nonce == Nonce(StarkFelt::ZERO) + && Nonce(StarkFelt::ONE) <= tx_nonce + && tx_nonce <= self.max_privileged_nonce + { + // There is a reasonable gap; check if a deploy account transaction was sent and skip + // further validations if so, since it means that the deployed account class isn't + // reachable yet. + if deploy_account_tx_hash.is_some() { + return Ok(false); + } + } + + Ok(true) + } + #[pyo3(signature = (tx, remaining_gas, raw_contract_class))] pub fn validate( &mut self, @@ -102,6 +146,7 @@ impl PyValidator { Self { general_config, max_recursion_depth: 50, + max_privileged_nonce: Nonce(StarkFelt::ONE), tx_executor: None, global_contract_cache: GlobalContractCache::default(), }