Skip to content

Commit 9c75c41

Browse files
starknet_os_runner: run virtual os with state changes test (#12305)
1 parent 9ac3421 commit 9c75c41

File tree

4 files changed

+135
-8
lines changed

4 files changed

+135
-8
lines changed

crates/starknet_os_runner/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ pub mod virtual_snos_prover;
1212
#[cfg(test)]
1313
mod classes_provider_test;
1414
#[cfg(test)]
15+
mod runner_test;
16+
#[cfg(test)]
1517
mod storage_proofs_test;
1618
#[cfg(test)]
1719
pub mod test_utils;

crates/starknet_os_runner/src/runner.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,11 @@ where
209209
let tx_execution_infos =
210210
execution_data.execution_outputs.into_iter().map(|output| output.0.into()).collect();
211211

212-
// Add class hash to compiled class hash mappings from the classes provider.
212+
// The extended_initial_reads from storage proofs already has class_hashes, nonces,
213+
// and storage values. We just need to add compiled class hashes from the classes provider.
213214
let mut extended_initial_reads = storage_proofs.extended_initial_reads;
215+
216+
// Add class hash to compiled class hash mappings from the classes provider.
214217
extended_initial_reads
215218
.compiled_class_hashes
216219
.extend(&classes.class_hash_to_compiled_class_hash);
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//! Integration tests for the Runner.
2+
3+
use blockifier_reexecution::state_reader::rpc_objects::BlockId;
4+
use blockifier_test_utils::calldata::create_calldata;
5+
use rstest::rstest;
6+
use starknet_api::core::ContractAddress;
7+
use starknet_api::invoke_tx_args;
8+
use starknet_api::test_utils::invoke::invoke_tx;
9+
10+
use crate::runner::VirtualSnosRunner;
11+
use crate::test_utils::{
12+
default_resource_bounds_for_client_side_tx,
13+
sepolia_runner_factory,
14+
DUMMY_ACCOUNT_ADDRESS,
15+
STRK_TOKEN_ADDRESS_SEPOLIA,
16+
};
17+
18+
/// Integration test for the full Runner flow with a balance_of transaction.
19+
/// # Running
20+
///
21+
/// ```bash
22+
/// SEPOLIA_NODE_URL=https://your-rpc-node cargo test -p starknet_os_runner test_run_os_with_balance_of_transaction -- --ignored
23+
/// ```
24+
#[rstest]
25+
#[tokio::test(flavor = "multi_thread")]
26+
#[ignore] // Requires RPC access.
27+
async fn test_run_os_with_balance_of_transaction() {
28+
// Creates an invoke transaction that calls `balanceOf` on the STRK token.
29+
let strk_token = ContractAddress::try_from(STRK_TOKEN_ADDRESS_SEPOLIA).unwrap();
30+
let account = ContractAddress::try_from(DUMMY_ACCOUNT_ADDRESS).unwrap();
31+
32+
// Calldata matches dummy account's __execute__(contract_address, selector, calldata).
33+
let calldata = create_calldata(strk_token, "balanceOf", &[account.into()]);
34+
let resource_bounds = default_resource_bounds_for_client_side_tx();
35+
36+
let invoke_tx = invoke_tx(invoke_tx_args! {
37+
sender_address: account,
38+
calldata,
39+
resource_bounds,
40+
});
41+
42+
// Create a custom factory with the specified run_committer setting.
43+
let factory = sepolia_runner_factory();
44+
let block_id = BlockId::Latest;
45+
46+
// Verify execution succeeds.
47+
factory
48+
.run_virtual_os(block_id, vec![(invoke_tx)])
49+
.await
50+
.expect("run_virtual_os should succeed");
51+
}

crates/starknet_os_runner/src/test_utils.rs

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,27 @@
11
use std::env;
22

3+
use blockifier::blockifier::config::ContractClassManagerConfig;
4+
use blockifier::state::contract_class_manager::ContractClassManager;
35
use blockifier_reexecution::state_reader::rpc_objects::BlockId;
46
use blockifier_reexecution::state_reader::rpc_state_reader::RpcStateReader;
57
use rstest::fixture;
6-
use starknet_api::block::BlockNumber;
8+
use starknet_api::block::{BlockNumber, GasPrice};
79
use starknet_api::core::ChainId;
10+
use starknet_api::execution_resources::GasAmount;
11+
use starknet_api::transaction::fields::{AllResourceBounds, ResourceBounds, ValidResourceBounds};
812
use starknet_types_core::felt::Felt;
913
use url::Url;
1014

11-
use crate::storage_proofs::RpcStorageProofsProvider;
15+
use crate::runner::{RpcRunnerFactory, RunnerConfig};
16+
use crate::storage_proofs::{RpcStorageProofsProvider, StorageProofConfig};
1217
use crate::virtual_block_executor::RpcVirtualBlockExecutor;
1318

19+
// ================================================================================================
20+
// Constants
21+
// ================================================================================================
22+
23+
// --- Mainnet ---
24+
1425
/// Block number to use for testing (mainnet block with known state).
1526
pub const TEST_BLOCK_NUMBER: u64 = 800000;
1627

@@ -22,12 +33,36 @@ pub const STRK_TOKEN_ADDRESS: Felt =
2233
pub const SENDER_ADDRESS: Felt =
2334
Felt::from_hex_unchecked("0x01176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8");
2435

25-
/// Gets the RPC URL from the environment (NODE_URL).
36+
// --- Sepolia ---
37+
38+
/// STRK token contract address on Sepolia.
39+
pub const STRK_TOKEN_ADDRESS_SEPOLIA: Felt =
40+
Felt::from_hex_unchecked("0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d");
41+
42+
/// Dummy account on Sepolia (no signature validation required).
43+
/// This account uses the `account_with_dummy_validate` contract which always returns VALIDATED.
44+
pub const DUMMY_ACCOUNT_ADDRESS: Felt =
45+
Felt::from_hex_unchecked("0x0786ed7d8dcbf1489241d65a4dd55f18b984c078558ce12def69802526fa918e");
46+
47+
// ================================================================================================
48+
// RPC URL Helpers
49+
// ================================================================================================
50+
51+
/// Gets the mainnet RPC URL from the environment (NODE_URL).
2652
pub fn get_rpc_url() -> String {
2753
env::var("NODE_URL").expect("NODE_URL environment variable required for this test")
2854
}
2955

30-
/// Fixture that creates an RpcStateReader for testing.
56+
/// Gets the Sepolia RPC URL (defaults to local node, can be overridden via SEPOLIA_NODE_URL).
57+
pub fn get_sepolia_rpc_url() -> String {
58+
env::var("SEPOLIA_NODE_URL").unwrap_or_else(|_| "http://localhost:9546/rpc/v0_10".to_string())
59+
}
60+
61+
// ================================================================================================
62+
// Mainnet Fixtures
63+
// ================================================================================================
64+
65+
/// Fixture that creates an RpcStateReader for mainnet testing.
3166
#[fixture]
3267
pub fn rpc_state_reader() -> RpcStateReader {
3368
let node_url = get_rpc_url();
@@ -38,6 +73,7 @@ pub fn rpc_state_reader() -> RpcStateReader {
3873
)
3974
}
4075

76+
/// Fixture that creates an RpcVirtualBlockExecutor for mainnet testing.
4177
#[fixture]
4278
pub fn rpc_virtual_block_executor(rpc_state_reader: RpcStateReader) -> RpcVirtualBlockExecutor {
4379
RpcVirtualBlockExecutor {
@@ -47,10 +83,45 @@ pub fn rpc_virtual_block_executor(rpc_state_reader: RpcStateReader) -> RpcVirtua
4783
}
4884
}
4985

50-
/// Fixture that creates an RpcStorageProofsProvider for testing.
86+
/// Fixture that creates an RpcStorageProofsProvider for mainnet testing.
5187
#[fixture]
5288
pub fn rpc_provider() -> RpcStorageProofsProvider {
53-
let rpc_url_str = get_rpc_url();
54-
let rpc_url = Url::parse(&rpc_url_str).expect("Invalid RPC URL");
89+
let rpc_url = Url::parse(&get_rpc_url()).expect("Invalid RPC URL");
5590
RpcStorageProofsProvider::new(rpc_url)
5691
}
92+
93+
// ================================================================================================
94+
// Sepolia Fixtures
95+
// ================================================================================================
96+
97+
/// Fixture that creates an RpcRunnerFactory for Sepolia with committer enabled.
98+
///
99+
/// This factory is configured to run the committer, meaning it will:
100+
/// - Build a FactsDb from RPC proofs and execution data.
101+
/// - Execute the committer to compute new state roots.
102+
/// - Generate commitment infos with actual root changes.
103+
#[fixture]
104+
pub fn sepolia_runner_factory() -> RpcRunnerFactory {
105+
let rpc_url = Url::parse(&get_sepolia_rpc_url()).expect("Invalid Sepolia RPC URL");
106+
let contract_class_manager = ContractClassManager::start(ContractClassManagerConfig::default());
107+
108+
let runner_config =
109+
RunnerConfig { storage_proof_config: StorageProofConfig { include_state_changes: true } };
110+
111+
RpcRunnerFactory::new(rpc_url, ChainId::Sepolia, contract_class_manager, runner_config)
112+
}
113+
114+
// ================================================================================================
115+
// Transaction Helpers
116+
// ================================================================================================
117+
118+
pub(crate) fn default_resource_bounds_for_client_side_tx() -> ValidResourceBounds {
119+
ValidResourceBounds::AllResources(AllResourceBounds {
120+
l1_gas: ResourceBounds { max_amount: GasAmount(0), max_price_per_unit: GasPrice(0) },
121+
l2_gas: ResourceBounds {
122+
max_amount: GasAmount(10_000_000),
123+
max_price_per_unit: GasPrice(0),
124+
},
125+
l1_data_gas: ResourceBounds { max_amount: GasAmount(0), max_price_per_unit: GasPrice(0) },
126+
})
127+
}

0 commit comments

Comments
 (0)