Skip to content

Commit c2f1eb4

Browse files
starknet_os_runner: build os input
1 parent 89ce4f0 commit c2f1eb4

File tree

7 files changed

+156
-43
lines changed

7 files changed

+156
-43
lines changed

crates/starknet_os_runner/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ description = "Runs transactions through the Starknet OS and returns Cairo PIE a
99
[dependencies]
1010
blockifier.workspace = true
1111
blockifier_reexecution.workspace = true
12+
cairo-lang-starknet-classes.workspace = true
1213
indexmap.workspace = true
1314
starknet-rust.workspace = true
1415
starknet-rust-core.workspace = true
1516
starknet-types-core.workspace = true
1617
starknet_api.workspace = true
1718
starknet_os.workspace = true
1819
starknet_patricia.workspace = true
19-
cairo-lang-starknet-classes.workspace = true
2020
thiserror.workspace = true
2121
tokio.workspace = true
2222
url.workspace = true

crates/starknet_os_runner/src/classes_provider.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::{BTreeMap, HashMap, HashSet};
1+
use std::collections::{BTreeMap, HashSet};
22

33
use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass;
44
use starknet_api::core::{ClassHash, CompiledClassHash};
@@ -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: 2 additions & 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

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

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::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

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

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

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 = RpcStateReader::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)