Skip to content

Commit ddae6f3

Browse files
starknet_os_runner: build os input
1 parent b626b52 commit ddae6f3

File tree

6 files changed

+156
-41
lines changed

6 files changed

+156
-41
lines changed

crates/starknet_os_runner/src/classes_provider.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@ pub trait ClassesProvider {
2121
/// Fetches all classes required for the OS run based on the executed class hashes.
2222
fn get_classes(
2323
&self,
24-
executed_class_hashes: HashSet<ClassHash>,
24+
executed_class_hashes: &HashSet<ClassHash>,
2525
) -> Result<ClassesInput, ClassesProviderError>;
2626
}

crates/starknet_os_runner/src/errors.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,18 @@ pub enum VirtualBlockExecutorError {
1313

1414
#[error("Block state unavailable after execution")]
1515
StateUnavailable,
16+
}
1617

17-
#[error("Unsupported transaction type: only Invoke transactions are supported")]
18-
UnsupportedTransactionType,
18+
#[derive(Debug, Error)]
19+
pub enum RunnerError {
20+
#[error(transparent)]
21+
ClassesProvider(#[from] ClassesProviderError),
22+
#[error(transparent)]
23+
ProofProvider(#[from] ProofProviderError),
24+
#[error(transparent)]
25+
VirtualBlockExecutor(#[from] VirtualBlockExecutorError),
26+
#[error("OS Input generation failed: {0}")]
27+
InputGenerationError(String),
1928
}
2029

2130
#[derive(Debug, Error)]

crates/starknet_os_runner/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod classes_provider;
22
pub mod errors;
3+
pub mod runner;
34
pub mod storage_proofs;
45
pub mod virtual_block_executor;
56

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
use std::collections::HashMap;
2+
3+
use blockifier::state::contract_class_manager::ContractClassManager;
4+
use starknet_api::block::{BlockHash, BlockNumber};
5+
use starknet_api::block_hash::block_hash_calculator::BlockHeaderCommitments;
6+
use starknet_api::transaction::{InvokeTransaction, TransactionHash};
7+
use starknet_os::io::os_input::{OsBlockInput, StarknetOsInput};
8+
9+
use crate::classes_provider::ClassesProvider;
10+
use crate::errors::RunnerError;
11+
use crate::storage_proofs::StorageProofProvider;
12+
use crate::virtual_block_executor::VirtualBlockExecutor;
13+
14+
pub struct Runner<C, S, V>
15+
where
16+
C: ClassesProvider,
17+
S: StorageProofProvider,
18+
V: VirtualBlockExecutor,
19+
{
20+
pub classes_provider: C,
21+
pub storage_proofs_provider: S,
22+
pub virtual_block_executor: V,
23+
}
24+
25+
impl<C, S, V> Runner<C, S, V>
26+
where
27+
C: ClassesProvider,
28+
S: StorageProofProvider,
29+
V: VirtualBlockExecutor,
30+
{
31+
pub fn new(classes_provider: C, storage_proofs_provider: S, virtual_block_executor: V) -> Self {
32+
Self { classes_provider, storage_proofs_provider, virtual_block_executor }
33+
}
34+
35+
/// Creates OS input from execution data and storage proofs.
36+
pub fn create_os_input(
37+
&self,
38+
block_number: BlockNumber,
39+
contract_class_manager: ContractClassManager,
40+
txs: Vec<(InvokeTransaction, TransactionHash)>,
41+
) -> Result<StarknetOsInput, RunnerError> {
42+
// 1. Execute virtual block and get execution data.
43+
let mut execution_data = self.virtual_block_executor.execute(
44+
block_number,
45+
contract_class_manager,
46+
txs.clone(),
47+
)?;
48+
49+
// 2. Fetch classes (consuming executed_class_hashes).
50+
let classes = self.classes_provider.get_classes(&execution_data.executed_class_hashes)?;
51+
52+
// 3. Fetch storage proofs (pass execution_data by reference to avoid moving yet).
53+
let storage_proofs =
54+
self.storage_proofs_provider.get_storage_proofs(block_number, &execution_data)?;
55+
56+
// 4. Convert execution outputs to CentralTransactionExecutionInfo (consuming).
57+
let tx_execution_infos =
58+
execution_data.execution_outputs.into_iter().map(|output| output.0.into()).collect();
59+
60+
// 5. Merge initial_reads with proof_state.
61+
execution_data.initial_reads.extend(&storage_proofs.proof_state);
62+
63+
// 6. Assemble OsBlockInput.
64+
let os_block_input = OsBlockInput {
65+
// TODO(Aviv): Add block hash commitments.
66+
block_hash_commitments: BlockHeaderCommitments::default(),
67+
contract_state_commitment_info: storage_proofs
68+
.commitment_infos
69+
.contracts_trie_commitment_info,
70+
address_to_storage_commitment_info: storage_proofs
71+
.commitment_infos
72+
.storage_tries_commitment_infos,
73+
contract_class_commitment_info: storage_proofs
74+
.commitment_infos
75+
.classes_trie_commitment_info,
76+
transactions: txs
77+
.into_iter()
78+
.map(|(invoke_tx, tx_hash)| {
79+
starknet_api::executable_transaction::Transaction::Account(
80+
starknet_api::executable_transaction::AccountTransaction::Invoke(
81+
starknet_api::executable_transaction::InvokeTransaction {
82+
tx: invoke_tx,
83+
tx_hash,
84+
},
85+
),
86+
)
87+
})
88+
.collect(),
89+
tx_execution_infos,
90+
// We assume that no classes are declared.
91+
declared_class_hash_to_component_hashes: HashMap::new(),
92+
// We assume that no classes are migrated.
93+
class_hashes_to_migrate: HashMap::new(),
94+
// Stored block hash buffer skipped for now.
95+
old_block_number_and_hash: None,
96+
// Block info and hashes from execution context.
97+
block_info: execution_data.block_context.block_info().clone(),
98+
// TODO(Aviv): Add prev and new block hashes.
99+
prev_block_hash: BlockHash::default(),
100+
new_block_hash: BlockHash::default(),
101+
initial_reads: execution_data.initial_reads,
102+
};
103+
104+
// 7. Final StarknetOsInput (consuming classes).
105+
Ok(StarknetOsInput {
106+
os_block_inputs: vec![os_block_input],
107+
deprecated_compiled_classes: classes.deprecated_compiled_classes,
108+
compiled_classes: classes.compiled_classes,
109+
})
110+
}
111+
}

crates/starknet_os_runner/src/virtual_block_executor.rs

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use blockifier_reexecution::state_reader::rpc_state_reader::RpcStateReader;
1818
use starknet_api::block::BlockNumber;
1919
use starknet_api::core::{ChainId, ClassHash};
2020
use starknet_api::transaction::fields::Fee;
21-
use starknet_api::transaction::{Transaction, TransactionHash};
21+
use starknet_api::transaction::{InvokeTransaction, Transaction, TransactionHash};
2222

2323
use crate::errors::VirtualBlockExecutorError;
2424

@@ -76,12 +76,12 @@ pub trait VirtualBlockExecutor {
7676
/// # Returns
7777
///
7878
/// Returns `VirtualBlockExecutionData` containing execution outputs for all
79-
/// transactions, or an error if any transaction fails or is not an Invoke.
79+
/// transactions, or an error if any transaction fails.
8080
fn execute(
8181
&self,
8282
block_number: BlockNumber,
8383
contract_class_manager: ContractClassManager,
84-
txs: Vec<(Transaction, TransactionHash)>,
84+
txs: Vec<(InvokeTransaction, TransactionHash)>,
8585
) -> Result<VirtualBlockExecutionData, VirtualBlockExecutorError> {
8686
let blockifier_txs = Self::convert_invoke_txs(txs)?;
8787
let block_context = self.block_context(block_number)?;
@@ -137,38 +137,31 @@ pub trait VirtualBlockExecutor {
137137

138138
/// Converts Invoke transactions to blockifier transactions.
139139
///
140-
/// Uses execution flags that skip fee charging and nonce check.
141-
/// Returns an error if any transaction is not an Invoke.
140+
/// Uses execution flags that skip strict nonce check for virtual block execution.
142141
fn convert_invoke_txs(
143-
txs: Vec<(Transaction, TransactionHash)>,
142+
txs: Vec<(InvokeTransaction, TransactionHash)>,
144143
) -> Result<Vec<BlockifierTransaction>, VirtualBlockExecutorError> {
145144
txs.into_iter()
146-
.map(|(tx, tx_hash)| {
147-
if let Transaction::Invoke(invoke_tx) = tx {
148-
// Execute with validation, conditional fee charging based on resource bounds,
149-
// but skip strict nonce check for virtual block execution.
150-
let execution_flags = ExecutionFlags {
151-
only_query: false,
152-
charge_fee: invoke_tx.resource_bounds().max_possible_fee(invoke_tx.tip())
153-
> Fee(0),
154-
validate: true,
155-
strict_nonce_check: false,
156-
};
157-
158-
BlockifierTransaction::from_api(
159-
Transaction::Invoke(invoke_tx),
160-
tx_hash,
161-
None, // class_info - not needed for Invoke.
162-
None, // paid_fee_on_l1 - not needed for Invoke.
163-
None, // deployed_contract_address - not needed for Invoke.
164-
execution_flags,
165-
)
166-
.map_err(|e| {
167-
VirtualBlockExecutorError::TransactionExecutionError(e.to_string())
168-
})
169-
} else {
170-
Err(VirtualBlockExecutorError::UnsupportedTransactionType)
171-
}
145+
.map(|(invoke_tx, tx_hash)| {
146+
// Execute with validation, conditional fee charging based on resource bounds,
147+
// but skip strict nonce check for virtual block execution.
148+
let execution_flags = ExecutionFlags {
149+
only_query: false,
150+
charge_fee: invoke_tx.resource_bounds().max_possible_fee(invoke_tx.tip())
151+
> Fee(0),
152+
validate: true,
153+
strict_nonce_check: false,
154+
};
155+
156+
BlockifierTransaction::from_api(
157+
Transaction::Invoke(invoke_tx),
158+
tx_hash,
159+
None, // class_info - not needed for Invoke.
160+
None, // paid_fee_on_l1 - not needed for Invoke.
161+
None, // deployed_contract_address - not needed for Invoke.
162+
execution_flags,
163+
)
164+
.map_err(|e| VirtualBlockExecutorError::TransactionExecutionError(e.to_string()))
172165
})
173166
.collect()
174167
}

crates/starknet_os_runner/src/virtual_block_executor_test.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use starknet_api::abi::abi_utils::{get_storage_var_address, selector_from_name};
77
use starknet_api::block::BlockNumber;
88
use starknet_api::core::{ChainId, ContractAddress, Nonce};
99
use starknet_api::test_utils::invoke::invoke_tx;
10-
use starknet_api::transaction::{Transaction, TransactionHash};
10+
use starknet_api::transaction::{InvokeTransaction, Transaction, TransactionHash};
1111
use starknet_api::{calldata, felt, invoke_tx_args};
1212

1313
use crate::errors::VirtualBlockExecutorError;
@@ -40,7 +40,7 @@ impl VirtualBlockExecutor for TestRpcVirtualBlockExecutor {
4040

4141
// Override the default implementation to skip validation.
4242
fn convert_invoke_txs(
43-
txs: Vec<(Transaction, TransactionHash)>,
43+
txs: Vec<(InvokeTransaction, TransactionHash)>,
4444
) -> Result<Vec<BlockifierTransaction>, VirtualBlockExecutorError> {
4545
// Call the default trait implementation.
4646
let mut blockifier_txs = RpcVirtualBlockExecutor::convert_invoke_txs(txs)?;
@@ -60,7 +60,7 @@ impl VirtualBlockExecutor for TestRpcVirtualBlockExecutor {
6060
///
6161
/// Since we skip validation and fee charging, we can use dummy values for signature,
6262
/// nonce, and resource bounds.
63-
fn construct_balance_of_invoke() -> (Transaction, TransactionHash) {
63+
fn construct_balance_of_invoke() -> (InvokeTransaction, TransactionHash) {
6464
let strk_token = ContractAddress::try_from(STRK_TOKEN_ADDRESS).unwrap();
6565
let sender = ContractAddress::try_from(SENDER_ADDRESS).unwrap();
6666

@@ -85,9 +85,10 @@ fn construct_balance_of_invoke() -> (Transaction, TransactionHash) {
8585
nonce: Nonce(felt!("0x1000000")),
8686
});
8787

88-
let tx = Transaction::Invoke(invoke_tx);
89-
let tx_hash = tx.calculate_transaction_hash(&ChainId::Mainnet).unwrap();
90-
(tx, tx_hash)
88+
let tx_hash = Transaction::Invoke(invoke_tx.clone())
89+
.calculate_transaction_hash(&ChainId::Mainnet)
90+
.unwrap();
91+
(invoke_tx, tx_hash)
9192
}
9293

9394
/// Integration test for RpcVirtualBlockExecutor with a constructed transaction.

0 commit comments

Comments
 (0)