Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(blockifier_reexecution): move offline reader to separate file #2312

Merged
merged 1 commit into from
Nov 28, 2024
Merged
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
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
Loading