diff --git a/Cargo.lock b/Cargo.lock index cc31d6a5a4a..33c89494418 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12752,6 +12752,7 @@ dependencies = [ name = "starknet_os_runner" version = "0.0.0" dependencies = [ + "apollo_gateway", "async-trait", "blockifier", "blockifier_reexecution", diff --git a/crates/blockifier_reexecution/src/state_reader/rpc_state_reader.rs b/crates/blockifier_reexecution/src/state_reader/rpc_state_reader.rs index 850bd138ddd..a2c2d065a9b 100644 --- a/crates/blockifier_reexecution/src/state_reader/rpc_state_reader.rs +++ b/crates/blockifier_reexecution/src/state_reader/rpc_state_reader.rs @@ -99,9 +99,9 @@ impl Default for RetryConfig { #[derive(Clone)] pub struct RpcStateReader { - pub(crate) rpc_state_reader: GatewayRpcStateReader, + pub rpc_state_reader: GatewayRpcStateReader, pub(crate) retry_config: RetryConfig, - pub(crate) chain_id: ChainId, + pub chain_id: ChainId, #[allow(dead_code)] pub(crate) contract_class_mapping_dumper: Arc>>, } diff --git a/crates/starknet_api/src/block_hash/block_hash_calculator.rs b/crates/starknet_api/src/block_hash/block_hash_calculator.rs index b714972e21a..d77f6a7e60f 100644 --- a/crates/starknet_api/src/block_hash/block_hash_calculator.rs +++ b/crates/starknet_api/src/block_hash/block_hash_calculator.rs @@ -312,7 +312,7 @@ pub async fn calculate_block_commitments( // transaction_count (64 bits) | event_count (64 bits) | state_diff_length (64 bits) // | L1 data availability mode: 0 for calldata, 1 for blob (1 bit) | 0 ... // ]. -pub(crate) fn concat_counts( +pub fn concat_counts( transaction_count: usize, event_count: usize, state_diff_length: usize, diff --git a/crates/starknet_os_runner/Cargo.toml b/crates/starknet_os_runner/Cargo.toml index 71713e43f89..e3d508eea66 100644 --- a/crates/starknet_os_runner/Cargo.toml +++ b/crates/starknet_os_runner/Cargo.toml @@ -10,6 +10,7 @@ description = "Runs transactions through the Starknet OS and returns Cairo PIE a cairo_native = ["blockifier/cairo_native"] [dependencies] +apollo_gateway.workspace = true async-trait.workspace = true blockifier.workspace = true blockifier_reexecution.workspace = true diff --git a/crates/starknet_os_runner/src/errors.rs b/crates/starknet_os_runner/src/errors.rs index fc3404bc490..f7937b8b17c 100644 --- a/crates/starknet_os_runner/src/errors.rs +++ b/crates/starknet_os_runner/src/errors.rs @@ -10,10 +10,8 @@ pub enum VirtualBlockExecutorError { #[error(transparent)] // Boxed to reduce the size of Result on the stack (ReexecutionError is >128 bytes). ReexecutionError(#[from] Box), - #[error("Transaction execution failed: {0}")] TransactionExecutionError(String), - #[error("Block state unavailable after execution")] StateUnavailable, } diff --git a/crates/starknet_os_runner/src/runner.rs b/crates/starknet_os_runner/src/runner.rs index 07cedb21a04..f3a3faafb32 100644 --- a/crates/starknet_os_runner/src/runner.rs +++ b/crates/starknet_os_runner/src/runner.rs @@ -33,6 +33,8 @@ pub struct VirtualOsBlockInput { pub tx_execution_infos: Vec, pub block_info: BlockInfo, pub initial_reads: StateMaps, + pub base_block_hash: BlockHash, + pub base_block_header_commitments: BlockHeaderCommitments, pub prev_base_block_hash: BlockHash, pub compiled_classes: BTreeMap, } @@ -40,7 +42,7 @@ pub struct VirtualOsBlockInput { impl From for StarknetOsInput { fn from(virtual_os_block_input: VirtualOsBlockInput) -> Self { let os_block_input = OsBlockInput { - block_hash_commitments: BlockHeaderCommitments::default(), + block_hash_commitments: virtual_os_block_input.base_block_header_commitments, contract_state_commitment_info: virtual_os_block_input.contract_state_commitment_info, address_to_storage_commitment_info: virtual_os_block_input .address_to_storage_commitment_info, @@ -64,7 +66,7 @@ impl From for StarknetOsInput { block_info: virtual_os_block_input.block_info, initial_reads: virtual_os_block_input.initial_reads, declared_class_hash_to_component_hashes: HashMap::new(), - new_block_hash: BlockHash::default(), + new_block_hash: virtual_os_block_input.base_block_hash, old_block_number_and_hash: None, class_hashes_to_migrate: Vec::new(), }; @@ -114,7 +116,7 @@ where )?; // Extract chain info from block context. - let chain_info = execution_data.block_context.chain_info(); + let chain_info = execution_data.base_block_info.block_context.chain_info(); let os_chain_info = OsChainInfo { chain_id: chain_info.chain_id.clone(), strk_fee_token_address: chain_info.fee_token_addresses.strk_fee_token_address, @@ -148,9 +150,13 @@ where .classes_trie_commitment_info, transactions: txs, tx_execution_infos, - block_info: execution_data.block_context.block_info().clone(), + block_info: execution_data.base_block_info.block_context.block_info().clone(), initial_reads: execution_data.initial_reads, - prev_base_block_hash: execution_data.prev_base_block_hash, + base_block_hash: execution_data.base_block_info.base_block_hash, + base_block_header_commitments: execution_data + .base_block_info + .base_block_header_commitments, + prev_base_block_hash: execution_data.base_block_info.prev_base_block_hash, compiled_classes: classes.compiled_classes, }; diff --git a/crates/starknet_os_runner/src/storage_proofs_test.rs b/crates/starknet_os_runner/src/storage_proofs_test.rs index 43c415ef012..3073b8db211 100644 --- a/crates/starknet_os_runner/src/storage_proofs_test.rs +++ b/crates/starknet_os_runner/src/storage_proofs_test.rs @@ -4,6 +4,7 @@ use blockifier::context::BlockContext; use blockifier::state::cached_state::StateMaps; use rstest::rstest; use starknet_api::block::{BlockHash, BlockNumber}; +use starknet_api::block_hash::block_hash_calculator::BlockHeaderCommitments; use starknet_api::core::ContractAddress; use starknet_api::state::StorageKey; use starknet_rust::providers::Provider; @@ -11,7 +12,7 @@ use starknet_types_core::felt::Felt; use crate::storage_proofs::{RpcStorageProofsProvider, StorageProofProvider}; use crate::test_utils::{rpc_provider, STRK_TOKEN_ADDRESS}; -use crate::virtual_block_executor::VirtualBlockExecutionData; +use crate::virtual_block_executor::{BaseBlockInfo, VirtualBlockExecutionData}; /// Fixture: Creates initial reads with the STRK contract and storage slot 0. #[rstest::fixture] @@ -44,10 +45,14 @@ fn test_get_storage_proofs_from_rpc( let execution_data = VirtualBlockExecutionData { execution_outputs: vec![], - block_context: BlockContext::create_for_account_testing(), + base_block_info: BaseBlockInfo { + block_context: BlockContext::create_for_account_testing(), + base_block_hash: BlockHash::default(), + prev_base_block_hash: BlockHash::default(), + base_block_header_commitments: BlockHeaderCommitments::default(), + }, initial_reads: state_maps, executed_class_hashes: HashSet::new(), - prev_base_block_hash: BlockHash::default(), }; let result = runtime.block_on(async { diff --git a/crates/starknet_os_runner/src/virtual_block_executor.rs b/crates/starknet_os_runner/src/virtual_block_executor.rs index a558f30cb7a..e873e0d4e9b 100644 --- a/crates/starknet_os_runner/src/virtual_block_executor.rs +++ b/crates/starknet_os_runner/src/virtual_block_executor.rs @@ -1,10 +1,13 @@ use std::collections::HashSet; +use apollo_gateway::rpc_objects::BlockHeader; use blockifier::blockifier::config::TransactionExecutorConfig; use blockifier::blockifier::transaction_executor::{ TransactionExecutionOutput, TransactionExecutor, }; +use blockifier::blockifier_versioned_constants::VersionedConstants; +use blockifier::bouncer::BouncerConfig; use blockifier::context::BlockContext; use blockifier::state::cached_state::{CachedState, StateMaps}; use blockifier::state::contract_class_manager::ContractClassManager; @@ -14,29 +17,88 @@ use blockifier::state::state_reader_and_contract_manager::{ }; use blockifier::transaction::account_transaction::ExecutionFlags; use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction; -use blockifier_reexecution::state_reader::reexecution_state_reader::ReexecutionStateReader; use blockifier_reexecution::state_reader::rpc_state_reader::RpcStateReader; -use starknet_api::block::{BlockHash, BlockNumber}; +use blockifier_reexecution::utils::get_chain_info; +use starknet_api::block::{BlockHash, BlockInfo, BlockNumber}; +use starknet_api::block_hash::block_hash_calculator::{concat_counts, BlockHeaderCommitments}; use starknet_api::core::{ChainId, ClassHash}; use starknet_api::transaction::fields::Fee; use starknet_api::transaction::{InvokeTransaction, Transaction, TransactionHash}; +use starknet_api::versioned_constants_logic::VersionedConstantsTrait; use crate::errors::VirtualBlockExecutorError; /// Captures execution data for a virtual block (multiple transactions). /// /// This struct contains all the execution data needed for proof generation. +pub struct BaseBlockInfo { + pub(crate) block_context: BlockContext, + /// The block hash of the base block, + /// in which the virtual block is executed. + pub(crate) base_block_hash: BlockHash, + /// The commitment used for computing the block hash of the base block. + pub(crate) base_block_header_commitments: BlockHeaderCommitments, + /// The block hash of the previous base block. + /// Used to compute the base block hash in the os. + pub(crate) prev_base_block_hash: BlockHash, +} + +impl TryFrom<(BlockHeader, ChainId)> for BaseBlockInfo { + type Error = VirtualBlockExecutorError; + + fn try_from((header, chain_id): (BlockHeader, ChainId)) -> Result { + let base_block_hash = header.block_hash; + let prev_base_block_hash = header.parent_hash; + let base_block_header_commitments = BlockHeaderCommitments { + transaction_commitment: header.transaction_commitment, + event_commitment: header.event_commitment, + receipt_commitment: header.receipt_commitment, + state_diff_commitment: header.state_diff_commitment, + concatenated_counts: concat_counts( + header.transaction_count, + header.event_count, + header.state_diff_length, + header.l1_da_mode, + ), + }; + + let block_info: BlockInfo = header.try_into().map_err(|e| { + VirtualBlockExecutorError::TransactionExecutionError(format!( + "Failed to convert block header to block info: {e}" + )) + })?; + let chain_info = get_chain_info(&chain_id); + let versioned_constants = + VersionedConstants::get(&block_info.starknet_version).map_err(|e| { + VirtualBlockExecutorError::TransactionExecutionError(format!( + "Failed to get versioned constants: {e}" + )) + })?; + let block_context = BlockContext::new( + block_info, + chain_info, + versioned_constants.clone(), + BouncerConfig::default(), + ); + + Ok(BaseBlockInfo { + block_context, + base_block_hash, + base_block_header_commitments, + prev_base_block_hash, + }) + } +} + pub struct VirtualBlockExecutionData { /// Execution outputs for all transactions in the virtual block. pub execution_outputs: Vec, - /// The block context in which the transactions were executed. - pub block_context: BlockContext, /// The initial state reads (accessed state) during execution. pub initial_reads: StateMaps, /// The class hashes of all contracts executed in the virtual block. pub executed_class_hashes: HashSet, - /// The block hash of the state at the start of the virtual block. - pub prev_base_block_hash: BlockHash, + /// The base block info for the virtual block. + pub base_block_info: BaseBlockInfo, } /// Executes a virtual block of transactions. @@ -85,9 +147,8 @@ pub trait VirtualBlockExecutor { txs: Vec<(InvokeTransaction, TransactionHash)>, ) -> Result { let blockifier_txs = self.convert_invoke_txs(txs)?; - let block_context = self.block_context(block_number)?; + let base_block_info = self.base_block_info(block_number)?; let state_reader = self.state_reader(block_number)?; - let prev_base_block_hash = self.prev_base_block_hash(block_number)?; // Create state reader with contract manager. let state_reader_and_contract_manager = @@ -98,7 +159,7 @@ pub trait VirtualBlockExecutor { // Create executor WITHOUT preprocessing (no pre_process_block call). let mut transaction_executor = TransactionExecutor::new( block_state, - block_context.clone(), + base_block_info.block_context.clone(), TransactionExecutorConfig::default(), ); @@ -131,10 +192,9 @@ pub trait VirtualBlockExecutor { Ok(VirtualBlockExecutionData { execution_outputs, - block_context, + base_block_info, initial_reads, executed_class_hashes, - prev_base_block_hash, }) } @@ -169,17 +229,12 @@ pub trait VirtualBlockExecutor { }) .collect() } - /// Returns the block context for the given block number. - fn block_context( - &self, - block_number: BlockNumber, - ) -> Result; - /// Returns the block hash of the state at the start of the virtual block. - fn prev_base_block_hash( + /// Returns the base block info for the given block number. + fn base_block_info( &self, block_number: BlockNumber, - ) -> Result; + ) -> Result; /// Returns a state reader that implements `FetchCompiledClasses` for the given block number. /// Must be `Send + Sync + 'static` to be used in the transaction executor. @@ -194,6 +249,7 @@ pub trait VirtualBlockExecutor { #[allow(dead_code)] pub(crate) struct RpcVirtualBlockExecutor { + /// The state reader for the virtual block executor. pub rpc_state_reader: RpcStateReader, /// Whether transaction validation is enabled during execution. pub validate_txs: bool, @@ -219,22 +275,15 @@ impl RpcVirtualBlockExecutor { /// without block preprocessing. Validation and fee charging are always skipped, /// making it suitable for simulation and OS input generation. impl VirtualBlockExecutor for RpcVirtualBlockExecutor { - fn block_context( + fn base_block_info( &self, _block_number: BlockNumber, - ) -> Result { - self.rpc_state_reader - .get_block_context() - .map_err(|e| VirtualBlockExecutorError::ReexecutionError(Box::new(e))) - } - - fn prev_base_block_hash( - &self, - block_number: BlockNumber, - ) -> Result { - self.rpc_state_reader - .get_old_block_hash(block_number) - .map_err(|e| VirtualBlockExecutorError::ReexecutionError(Box::new(e))) + ) -> Result { + let block_header = self + .rpc_state_reader + .get_block_header() + .map_err(|e| VirtualBlockExecutorError::ReexecutionError(Box::new(e)))?; + BaseBlockInfo::try_from((block_header, self.rpc_state_reader.chain_id.clone())) } fn state_reader( diff --git a/crates/starknet_os_runner/src/virtual_block_executor_test.rs b/crates/starknet_os_runner/src/virtual_block_executor_test.rs index 10bd96739ae..0575c606e7c 100644 --- a/crates/starknet_os_runner/src/virtual_block_executor_test.rs +++ b/crates/starknet_os_runner/src/virtual_block_executor_test.rs @@ -124,7 +124,7 @@ fn test_execute_constructed_balance_of_transaction( // Verify block context was captured. assert_eq!( - result.block_context.block_info().block_number, + result.base_block_info.block_context.block_info().block_number, BlockNumber(TEST_BLOCK_NUMBER), "Block context should have the correct block number" );