Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

refactor(execution, native_blockifier): move pre_process_block to PyB… #1422

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 35 additions & 4 deletions crates/native_blockifier/src/py_block_executor.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use std::collections::HashMap;
use std::sync::Arc;

use blockifier::block::{BlockInfo, GasPrices};
use blockifier::block::{pre_process_block, BlockInfo, BlockNumberHashPair, GasPrices};
use blockifier::context::{BlockContext, ChainInfo, FeeTokenAddresses};
use blockifier::state::cached_state::{GlobalContractCache, GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST};
use blockifier::transaction::objects::TransactionExecutionInfo;
use blockifier::transaction::transaction_execution::Transaction;
use blockifier::versioned_constants::VersionedConstants;
use pyo3::prelude::*;
use serde::Serialize;
use starknet_api::block::{BlockNumber, BlockTimestamp};
use starknet_api::core::{ChainId, ContractAddress};
use starknet_api::hash::StarkFelt;
Expand All @@ -15,6 +18,7 @@ use crate::errors::{
NativeBlockifierResult,
};
use crate::py_state_diff::{PyBlockInfo, PyStateDiff};
use crate::py_transaction::py_tx;
use crate::py_transaction_execution_info::PyBouncerInfo;
use crate::py_utils::{int_to_chain_id, py_attr, versioned_constants_with_overrides, PyFelt};
use crate::state_readers::papyrus_state::PapyrusReader;
Expand All @@ -25,6 +29,14 @@ use crate::transaction_executor::{RawTransactionExecutionInfo, TransactionExecut
#[path = "py_block_executor_test.rs"]
mod py_block_executor_test;

#[pyclass]
#[derive(Debug, Serialize)]
pub(crate) struct TypedTransactionExecutionInfo {
#[serde(flatten)]
pub info: TransactionExecutionInfo,
pub tx_type: String,
}

#[pyclass]
pub struct PyBlockExecutor {
pub general_config: PyGeneralConfig,
Expand Down Expand Up @@ -95,14 +107,28 @@ impl PyBlockExecutor {
raw_contract_class: Option<&str>,
) -> NativeBlockifierResult<(RawTransactionExecutionInfo, PyBouncerInfo)> {
let charge_fee = true;
self.tx_executor().execute(tx, raw_contract_class, charge_fee)
let tx_type: &str = tx.getattr("tx_type")?.getattr("name")?.extract()?;
let tx: Transaction = py_tx(tx, raw_contract_class)?;
let (tx_execution_info, py_bouncer_info) = self.tx_executor().execute(tx, charge_fee)?;
let typed_tx_execution_info =
TypedTransactionExecutionInfo { info: tx_execution_info, tx_type: tx_type.to_string() };
let raw_tx_execution_info = serde_json::to_vec(&typed_tx_execution_info)?;

Ok((raw_tx_execution_info, py_bouncer_info))
}

/// Returns the state diff and a list of contract class hash with the corresponding list of
/// visited PC values.
pub fn finalize(&mut self, is_pending_block: bool) -> (PyStateDiff, Vec<(PyFelt, Vec<usize>)>) {
log::debug!("Finalizing execution...");
let finalized_state = self.tx_executor().finalize(is_pending_block);
let (commitment_state_diff, visited_pcs) = self.tx_executor().finalize(is_pending_block);
let visited_pcs = visited_pcs
.into_iter()
.map(|(class_hash, class_visited_pcs_vec)| {
(PyFelt::from(class_hash), class_visited_pcs_vec)
})
.collect();
let finalized_state = (PyStateDiff::from(commitment_state_diff), visited_pcs);
log::debug!("Finalized execution.");

finalized_state
Expand All @@ -113,7 +139,12 @@ impl PyBlockExecutor {
&mut self,
old_block_number_and_hash: Option<(u64, PyFelt)>,
) -> NativeBlockifierResult<()> {
self.tx_executor().pre_process_block(old_block_number_and_hash)
let old_block_number_and_hash = old_block_number_and_hash
.map(|(block_number, block_hash)| BlockNumberHashPair::new(block_number, block_hash.0));
let state = &mut self.tx_executor().state;
pre_process_block(state, old_block_number_and_hash)?;

Ok(())
}

pub fn commit_tx(&mut self) {
Expand Down
21 changes: 12 additions & 9 deletions crates/native_blockifier/src/py_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use blockifier::fee::fee_checks::PostValidationReport;
use blockifier::state::cached_state::{GlobalContractCache, GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST};
use blockifier::state::state_api::StateReader;
use blockifier::transaction::account_transaction::AccountTransaction;
use blockifier::transaction::objects::{TransactionExecutionResult, TransactionInfo};
use blockifier::transaction::objects::{
TransactionExecutionInfo, TransactionExecutionResult, TransactionInfo,
};
use blockifier::transaction::transaction_execution::Transaction;
use blockifier::versioned_constants::VersionedConstants;
use pyo3::prelude::*;
Expand All @@ -15,11 +17,11 @@ 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_account_tx;
use crate::py_transaction::{py_account_tx, py_tx};
use crate::py_transaction_execution_info::PyBouncerInfo;
use crate::py_utils::{versioned_constants_with_overrides, PyFelt};
use crate::state_readers::py_state_reader::PyStateReader;
use crate::transaction_executor::{RawTransactionExecutionInfo, TransactionExecutor};
use crate::transaction_executor::TransactionExecutor;

/// Manages transaction validation for pre-execution flows.
#[pyclass]
Expand Down Expand Up @@ -74,8 +76,7 @@ impl PyValidator {
// before `__validate_deploy__`. The execution already includes all necessary validations,
// so they are skipped here.
if let AccountTransaction::DeployAccount(_deploy_account_tx) = account_tx {
let (_raw_tx_execution_info, _py_bouncer_info) =
self.execute(tx, raw_contract_class)?;
let (_tx_execution_info, _py_bouncer_info) = self.execute(tx, raw_contract_class)?;
// TODO(Ayelet, 09/11/2023): Check call succeeded.

return Ok(());
Expand Down Expand Up @@ -122,20 +123,22 @@ impl PyValidator {
)?;
Ok(Self { max_nonce_for_validation_skip: Nonce(StarkFelt::ONE), tx_executor })
}
}

impl PyValidator {
/// Applicable solely to account deployment transactions: the execution of the constructor
/// is required before they can be validated.
fn execute(
&mut self,
tx: &PyAny,
raw_contract_class: Option<&str>,
) -> NativeBlockifierResult<(RawTransactionExecutionInfo, PyBouncerInfo)> {
) -> NativeBlockifierResult<(TransactionExecutionInfo, PyBouncerInfo)> {
let limit_execution_steps_by_resource_bounds = true;
self.tx_executor.execute(tx, raw_contract_class, limit_execution_steps_by_resource_bounds)
let tx: Transaction = py_tx(tx, raw_contract_class)?;

self.tx_executor.execute(tx, limit_execution_steps_by_resource_bounds)
}
}

impl PyValidator {
fn perform_pre_validation_stage(
&mut self,
account_tx: &AccountTransaction,
Expand Down
56 changes: 12 additions & 44 deletions crates/native_blockifier/src/transaction_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use std::vec::IntoIter;

use blockifier::block::{pre_process_block, BlockNumberHashPair};
use blockifier::context::BlockContext;
use blockifier::execution::call_info::{CallInfo, MessageL1CostInfo};
use blockifier::execution::entry_point::ExecutionResources;
use blockifier::fee::actual_cost::ActualCost;
use blockifier::state::cached_state::{
CachedState, GlobalContractCache, StagedTransactionalState, StorageEntry, TransactionalState,
CachedState, CommitmentStateDiff, GlobalContractCache, StagedTransactionalState, StorageEntry,
TransactionalState,
};
use blockifier::state::state_api::{State, StateReader};
use blockifier::transaction::account_transaction::AccountTransaction;
Expand All @@ -19,27 +19,15 @@ use blockifier::transaction::transactions::{ExecutableTransaction, ValidatableTr
use blockifier::versioned_constants::VersionedConstants;
use cairo_vm::vm::runners::builtin_runner::HASH_BUILTIN_NAME;
use cairo_vm::vm::runners::cairo_runner::ExecutionResources as VmExecutionResources;
use pyo3::prelude::*;
use serde::Serialize;
use starknet_api::core::ClassHash;

use crate::errors::{NativeBlockifierError, NativeBlockifierResult};
use crate::py_block_executor::{into_block_context, PyGeneralConfig};
use crate::py_state_diff::{PyBlockInfo, PyStateDiff};
use crate::py_transaction::py_tx;
use crate::py_state_diff::PyBlockInfo;
use crate::py_transaction_execution_info::PyBouncerInfo;
use crate::py_utils::PyFelt;

pub(crate) type RawTransactionExecutionInfo = Vec<u8>;

#[pyclass]
#[derive(Debug, Serialize)]
pub(crate) struct TypedTransactionExecutionInfo {
#[serde(flatten)]
info: TransactionExecutionInfo,
tx_type: String,
}

// TODO(Gilad): make this hold TransactionContext instead of BlockContext.
pub struct TransactionExecutor<S: StateReader> {
pub block_context: BlockContext,
Expand Down Expand Up @@ -83,12 +71,9 @@ impl<S: StateReader> TransactionExecutor<S> {
/// (used for counting purposes).
pub fn execute(
&mut self,
tx: &PyAny,
raw_contract_class: Option<&str>,
tx: Transaction,
charge_fee: bool,
) -> NativeBlockifierResult<(RawTransactionExecutionInfo, PyBouncerInfo)> {
let tx_type: &str = tx.getattr("tx_type")?.getattr("name")?.extract()?;
let tx: Transaction = py_tx(tx, raw_contract_class)?;
) -> NativeBlockifierResult<(TransactionExecutionInfo, PyBouncerInfo)> {
let l1_handler_payload_size: usize =
if let Transaction::L1HandlerTransaction(l1_handler_tx) = &tx {
l1_handler_tx.payload_size()
Expand Down Expand Up @@ -146,14 +131,7 @@ impl<S: StateReader> TransactionExecutor<S> {
self.staged_for_commit_state = Some(
transactional_state.stage(tx_executed_class_hashes, tx_visited_storage_entries),
);

let typed_tx_execution_info = TypedTransactionExecutionInfo {
info: tx_execution_info,
tx_type: tx_type.to_string(),
};
let raw_tx_execution_info = serde_json::to_vec(&typed_tx_execution_info)?;

Ok((raw_tx_execution_info, py_bouncer_info))
Ok((tx_execution_info, py_bouncer_info))
}
Err(error) => {
transactional_state.abort();
Expand Down Expand Up @@ -197,7 +175,10 @@ impl<S: StateReader> TransactionExecutor<S> {

/// Returns the state diff and a list of contract class hash with the corresponding list of
/// visited PC values.
pub fn finalize(&mut self, is_pending_block: bool) -> (PyStateDiff, Vec<(PyFelt, Vec<usize>)>) {
pub fn finalize(
&mut self,
is_pending_block: bool,
) -> (CommitmentStateDiff, Vec<(ClassHash, Vec<usize>)>) {
// Do not cache classes that were declared during a pending block.
// They will be redeclared, and should not be cached since the content of this block is
// transient.
Expand All @@ -213,24 +194,11 @@ impl<S: StateReader> TransactionExecutor<S> {
.map(|(class_hash, class_visited_pcs)| {
let mut class_visited_pcs_vec: Vec<_> = class_visited_pcs.iter().cloned().collect();
class_visited_pcs_vec.sort();
(PyFelt::from(*class_hash), class_visited_pcs_vec)
(*class_hash, class_visited_pcs_vec)
})
.collect();

(PyStateDiff::from(self.state.to_state_diff()), visited_pcs)
}

// Block pre-processing; see `block::pre_process_block` documentation.
pub fn pre_process_block(
&mut self,
old_block_number_and_hash: Option<(u64, PyFelt)>,
) -> NativeBlockifierResult<()> {
let old_block_number_and_hash = old_block_number_and_hash
.map(|(block_number, block_hash)| BlockNumberHashPair::new(block_number, block_hash.0));

pre_process_block(&mut self.state, old_block_number_and_hash)?;

Ok(())
(self.state.to_state_diff(), visited_pcs)
}

pub fn commit(&mut self) {
Expand Down
Loading