Skip to content
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -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<Mutex<Option<StarknetContractClassMapping>>>,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions crates/starknet_os_runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions crates/starknet_os_runner/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ReexecutionError>),

#[error("Transaction execution failed: {0}")]
TransactionExecutionError(String),

#[error("Block state unavailable after execution")]
StateUnavailable,
}
Expand Down
16 changes: 11 additions & 5 deletions crates/starknet_os_runner/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,16 @@ pub struct VirtualOsBlockInput {
pub tx_execution_infos: Vec<CentralTransactionExecutionInfo>,
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<CompiledClassHash, CasmContractClass>,
}

impl From<VirtualOsBlockInput> 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,
Expand All @@ -64,7 +66,7 @@ impl From<VirtualOsBlockInput> 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(),
};
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
};

Expand Down
11 changes: 8 additions & 3 deletions crates/starknet_os_runner/src/storage_proofs_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ 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;
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]
Expand Down Expand Up @@ -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 {
Expand Down
115 changes: 82 additions & 33 deletions crates/starknet_os_runner/src/virtual_block_executor.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<Self, Self::Error> {
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<TransactionExecutionOutput>,
/// 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<ClassHash>,
/// 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.
Expand Down Expand Up @@ -85,9 +147,8 @@ pub trait VirtualBlockExecutor {
txs: Vec<(InvokeTransaction, TransactionHash)>,
) -> Result<VirtualBlockExecutionData, VirtualBlockExecutorError> {
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 =
Expand All @@ -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(),
);

Expand Down Expand Up @@ -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,
})
}

Expand Down Expand Up @@ -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<BlockContext, VirtualBlockExecutorError>;

/// 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<BlockHash, VirtualBlockExecutorError>;
) -> Result<BaseBlockInfo, VirtualBlockExecutorError>;

/// Returns a state reader that implements `FetchCompiledClasses` for the given block number.
/// Must be `Send + Sync + 'static` to be used in the transaction executor.
Expand All @@ -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,
Expand All @@ -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<BlockContext, VirtualBlockExecutorError> {
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<BlockHash, VirtualBlockExecutorError> {
self.rpc_state_reader
.get_old_block_hash(block_number)
.map_err(|e| VirtualBlockExecutorError::ReexecutionError(Box::new(e)))
) -> Result<BaseBlockInfo, VirtualBlockExecutorError> {
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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
);
Expand Down
Loading