Skip to content

Commit

Permalink
refactor(blockifier_reexecution): move offline reader to separate file
Browse files Browse the repository at this point in the history
  • Loading branch information
aner-starkware committed Nov 27, 2024
1 parent 18e06a7 commit 4bd767f
Show file tree
Hide file tree
Showing 8 changed files with 297 additions and 265 deletions.
6 changes: 2 additions & 4 deletions crates/blockifier_reexecution/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use std::fs;
use std::path::Path;

use blockifier_reexecution::state_reader::test_state_reader::{
ConsecutiveTestStateReaders,
OfflineConsecutiveStateReaders,
};
use blockifier_reexecution::state_reader::offline_state_reader::OfflineConsecutiveStateReaders;
use blockifier_reexecution::state_reader::test_state_reader::ConsecutiveTestStateReaders;
use blockifier_reexecution::state_reader::utils::{
get_block_numbers_for_reexecution,
guess_chain_id_from_node_url,
Expand Down
1 change: 1 addition & 0 deletions crates/blockifier_reexecution/src/state_reader.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod compile;
mod errors;
pub mod offline_state_reader;
#[cfg(test)]
pub mod raw_rpc_json_test;
pub mod reexecution_state_reader;
Expand Down
2 changes: 2 additions & 0 deletions crates/blockifier_reexecution/src/state_reader/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ pub enum ReexecutionError {
#[error(transparent)]
VersionedConstants(#[from] VersionedConstantsError),
}

pub type ReexecutionResult<T> = Result<T, ReexecutionError>;
259 changes: 259 additions & 0 deletions crates/blockifier_reexecution/src/state_reader/offline_state_reader.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
use std::fs;

use blockifier::abi::constants;
use blockifier::blockifier::block::BlockInfo;
use blockifier::blockifier::config::TransactionExecutorConfig;
use blockifier::blockifier::transaction_executor::TransactionExecutor;
use blockifier::bouncer::BouncerConfig;
use blockifier::context::BlockContext;
use blockifier::execution::contract_class::RunnableCompiledClass;
use blockifier::state::cached_state::{CommitmentStateDiff, StateMaps};
use blockifier::state::errors::StateError;
use blockifier::state::state_api::{StateReader, StateResult};
use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction;
use blockifier::versioned_constants::VersionedConstants;
use serde::{Deserialize, Serialize};
use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber, StarknetVersion};
use starknet_api::core::{ChainId, ClassHash, CompiledClassHash, ContractAddress, Nonce};
use starknet_api::state::StorageKey;
use starknet_api::transaction::{Transaction, TransactionHash};
use starknet_core::types::ContractClass as StarknetContractClass;
use starknet_types_core::felt::Felt;

use crate::state_reader::compile::{legacy_to_contract_class_v0, sierra_to_contact_class_v1};
use crate::state_reader::errors::ReexecutionResult;
use crate::state_reader::reexecution_state_reader::{
ConsecutiveReexecutionStateReaders,
ReexecutionStateReader,
};
use crate::state_reader::test_state_reader::StarknetContractClassMapping;
use crate::state_reader::utils::{get_chain_info, ReexecutionStateMaps};

pub struct OfflineReexecutionData {
offline_state_reader_prev_block: OfflineStateReader,
block_context_next_block: BlockContext,
transactions_next_block: Vec<BlockifierTransaction>,
state_diff_next_block: CommitmentStateDiff,
}

#[derive(Serialize, Deserialize)]
pub struct SerializableDataNextBlock {
pub block_info_next_block: BlockInfo,
pub starknet_version: StarknetVersion,
pub transactions_next_block: Vec<(Transaction, TransactionHash)>,
pub state_diff_next_block: CommitmentStateDiff,
pub declared_classes: StarknetContractClassMapping,
}

#[derive(Serialize, Deserialize)]
pub struct SerializableDataPrevBlock {
pub state_maps: ReexecutionStateMaps,
pub contract_class_mapping: StarknetContractClassMapping,
}

#[derive(Serialize, Deserialize)]
pub struct SerializableOfflineReexecutionData {
pub serializable_data_prev_block: SerializableDataPrevBlock,
pub serializable_data_next_block: SerializableDataNextBlock,
pub chain_id: ChainId,
pub old_block_hash: BlockHash,
}

impl SerializableOfflineReexecutionData {
pub fn write_to_file(&self, full_file_path: &str) -> ReexecutionResult<()> {
let file_path = full_file_path.rsplit_once('/').expect("Invalid file path.").0;
fs::create_dir_all(file_path)
.unwrap_or_else(|err| panic!("Failed to create directory {file_path}. Error: {err}"));
fs::write(full_file_path, serde_json::to_string_pretty(&self)?)
.unwrap_or_else(|err| panic!("Failed to write to file {full_file_path}. Error: {err}"));
Ok(())
}

pub fn read_from_file(full_file_path: &str) -> ReexecutionResult<Self> {
let file_content = fs::read_to_string(full_file_path).unwrap_or_else(|err| {
panic!("Failed to read reexecution data from file {full_file_path}. Error: {err}")
});
Ok(serde_json::from_str(&file_content)?)
}
}

impl From<SerializableOfflineReexecutionData> for OfflineReexecutionData {
fn from(value: SerializableOfflineReexecutionData) -> Self {
let SerializableOfflineReexecutionData {
serializable_data_prev_block:
SerializableDataPrevBlock { state_maps, contract_class_mapping },
serializable_data_next_block:
SerializableDataNextBlock {
block_info_next_block,
starknet_version,
transactions_next_block,
state_diff_next_block,
declared_classes,
},
chain_id,
old_block_hash,
} = value;

let offline_state_reader_prev_block = OfflineStateReader {
state_maps: state_maps.try_into().expect("Failed to deserialize state maps."),
contract_class_mapping,
old_block_hash,
};

// Use the declared classes from the next block to allow retrieving the class info.
let transactions_next_block =
OfflineStateReader { contract_class_mapping: declared_classes, ..Default::default() }
.api_txs_to_blockifier_txs_next_block(transactions_next_block)
.expect("Failed to convert starknet-api transactions to blockifier transactions.");

Self {
offline_state_reader_prev_block,
block_context_next_block: BlockContext::new(
block_info_next_block,
get_chain_info(&chain_id),
VersionedConstants::get(&starknet_version).unwrap().clone(),
BouncerConfig::max(),
),
transactions_next_block,
state_diff_next_block,
}
}
}

#[derive(Default)]
pub struct OfflineStateReader {
pub state_maps: StateMaps,
pub contract_class_mapping: StarknetContractClassMapping,
pub old_block_hash: BlockHash,
}

impl StateReader for OfflineStateReader {
fn get_storage_at(
&self,
contract_address: ContractAddress,
key: StorageKey,
) -> StateResult<Felt> {
Ok(*self.state_maps.storage.get(&(contract_address, key)).ok_or(
StateError::StateReadError(format!(
"Missing Storage Value at contract_address: {}, key:{:?}",
contract_address, key
)),
)?)
}

fn get_nonce_at(&self, contract_address: ContractAddress) -> StateResult<Nonce> {
Ok(*self.state_maps.nonces.get(&contract_address).ok_or(StateError::StateReadError(
format!("Missing nonce at contract_address: {contract_address}"),
))?)
}

fn get_class_hash_at(&self, contract_address: ContractAddress) -> StateResult<ClassHash> {
Ok(*self.state_maps.class_hashes.get(&contract_address).ok_or(
StateError::StateReadError(format!(
"Missing class hash at contract_address: {contract_address}"
)),
)?)
}

fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult<RunnableCompiledClass> {
match self.get_contract_class(&class_hash)? {
StarknetContractClass::Sierra(sierra) => {
Ok(sierra_to_contact_class_v1(sierra).unwrap().try_into().unwrap())
}
StarknetContractClass::Legacy(legacy) => {
Ok(legacy_to_contract_class_v0(legacy).unwrap().try_into().unwrap())
}
}
}

fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult<CompiledClassHash> {
Ok(*self
.state_maps
.compiled_class_hashes
.get(&class_hash)
.ok_or(StateError::UndeclaredClassHash(class_hash))?)
}
}

impl ReexecutionStateReader for OfflineStateReader {
fn get_contract_class(&self, class_hash: &ClassHash) -> StateResult<StarknetContractClass> {
Ok(self
.contract_class_mapping
.get(class_hash)
.ok_or(StateError::UndeclaredClassHash(*class_hash))?
.clone())
}

fn get_old_block_hash(&self, _old_block_number: BlockNumber) -> ReexecutionResult<BlockHash> {
Ok(self.old_block_hash)
}
}

impl OfflineStateReader {
pub fn get_transaction_executor(
self,
block_context_next_block: BlockContext,
transaction_executor_config: Option<TransactionExecutorConfig>,
) -> ReexecutionResult<TransactionExecutor<OfflineStateReader>> {
let old_block_number = BlockNumber(
block_context_next_block.block_info().block_number.0
- constants::STORED_BLOCK_HASH_BUFFER,
);
let hash = self.old_block_hash;
Ok(TransactionExecutor::<OfflineStateReader>::pre_process_and_create(
self,
block_context_next_block,
Some(BlockHashAndNumber { number: old_block_number, hash }),
transaction_executor_config.unwrap_or_default(),
)?)
}
}

pub struct OfflineConsecutiveStateReaders {
pub offline_state_reader_prev_block: OfflineStateReader,
pub block_context_next_block: BlockContext,
pub transactions_next_block: Vec<BlockifierTransaction>,
pub state_diff_next_block: CommitmentStateDiff,
}

impl OfflineConsecutiveStateReaders {
pub fn new_from_file(full_file_path: &str) -> ReexecutionResult<Self> {
let serializable_offline_reexecution_data =
SerializableOfflineReexecutionData::read_from_file(full_file_path)?;
Ok(Self::new(serializable_offline_reexecution_data.into()))
}

pub fn new(
OfflineReexecutionData {
offline_state_reader_prev_block,
block_context_next_block,
transactions_next_block,
state_diff_next_block,
}: OfflineReexecutionData,
) -> Self {
Self {
offline_state_reader_prev_block,
block_context_next_block,
transactions_next_block,
state_diff_next_block,
}
}
}

impl ConsecutiveReexecutionStateReaders<OfflineStateReader> for OfflineConsecutiveStateReaders {
fn pre_process_and_create_executor(
self,
transaction_executor_config: Option<TransactionExecutorConfig>,
) -> ReexecutionResult<TransactionExecutor<OfflineStateReader>> {
self.offline_state_reader_prev_block
.get_transaction_executor(self.block_context_next_block, transaction_executor_config)
}

fn get_next_block_txs(&self) -> ReexecutionResult<Vec<BlockifierTransaction>> {
Ok(self.transactions_next_block.clone())
}

fn get_next_block_state_diff(&self) -> ReexecutionResult<CommitmentStateDiff> {
Ok(self.state_diff_next_block.clone())
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use blockifier::state::state_api::StateResult;
use blockifier::blockifier::config::TransactionExecutorConfig;
use blockifier::blockifier::transaction_executor::TransactionExecutor;
use blockifier::state::cached_state::CommitmentStateDiff;
use blockifier::state::state_api::{StateReader, StateResult};
use blockifier::test_utils::MAX_FEE;
use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction;
use papyrus_execution::DEPRECATED_CONTRACT_SIERRA_SIZE;
Expand All @@ -8,9 +11,8 @@ use starknet_api::core::ClassHash;
use starknet_api::transaction::{Transaction, TransactionHash};
use starknet_core::types::ContractClass as StarknetContractClass;

use super::compile::{legacy_to_contract_class_v0, sierra_to_contact_class_v1};
use crate::state_reader::errors::ReexecutionError;
use crate::state_reader::test_state_reader::ReexecutionResult;
use crate::state_reader::compile::{legacy_to_contract_class_v0, sierra_to_contact_class_v1};
use crate::state_reader::errors::{ReexecutionError, ReexecutionResult};

pub trait ReexecutionStateReader {
fn get_contract_class(&self, class_hash: &ClassHash) -> StateResult<StarknetContractClass>;
Expand Down Expand Up @@ -76,3 +78,15 @@ pub trait ReexecutionStateReader {

fn get_old_block_hash(&self, old_block_number: BlockNumber) -> ReexecutionResult<BlockHash>;
}

/// Trait of the functions \ queries required for reexecution.
pub trait ConsecutiveReexecutionStateReaders<S: StateReader> {
fn pre_process_and_create_executor(
self,
transaction_executor_config: Option<TransactionExecutorConfig>,
) -> ReexecutionResult<TransactionExecutor<S>>;

fn get_next_block_txs(&self) -> ReexecutionResult<Vec<BlockifierTransaction>>;

fn get_next_block_state_diff(&self) -> ReexecutionResult<CommitmentStateDiff>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use starknet_api::transaction::{
Transaction,
};

use crate::state_reader::test_state_reader::ReexecutionResult;
use crate::state_reader::errors::ReexecutionResult;

/// In old transaction, the resource bounds names are lowercase.
/// need to convert to uppercase for deserialization to work.
Expand Down
Loading

0 comments on commit 4bd767f

Please sign in to comment.