Skip to content

Commit 5c8512b

Browse files
blockifier_reexecution: impl FetchedCompiledClass for test and offline state readers
1 parent c8f3060 commit 5c8512b

File tree

10 files changed

+132
-22
lines changed

10 files changed

+132
-22
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/blockifier/src/state/errors.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ pub enum StateError {
3232
/// Represents all unexpected errors that may occur while reading from state.
3333
#[error("Failed to read from state: {0}.")]
3434
StateReadError(String),
35-
#[error("Missing Sierra class for CASM class with hash {:#066x}.", **.0)]
36-
MissingSierra(ClassHash),
3735
#[error("Missing compiled class hash v2 for class with hash {:#064x}.", **.0)]
3836
MissingCompiledClassHashV2(ClassHash),
3937
}

crates/blockifier_reexecution/src/state_reader/compile.rs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ use starknet_api::hash::StarkHash;
2626
use starknet_api::state::SierraContractClass;
2727
use starknet_core::types::{
2828
CompressedLegacyContractClass,
29-
FlattenedSierraClass,
3029
LegacyContractEntryPoint,
3130
LegacyEntryPointsByType,
3231
};
@@ -76,20 +75,11 @@ pub fn decode_reader(bytes: Vec<u8>) -> io::Result<String> {
7675
Ok(s)
7776
}
7877

79-
/// Compile a FlattenedSierraClass to a versioned ContractClass V1 (casm) using
78+
/// Compile a SierraContractClass to a versioned ContractClass V1 (casm) using
8079
/// apollo_compile_to_casm.
8180
pub fn sierra_to_versioned_contract_class_v1(
82-
flattened_sierra: FlattenedSierraClass,
81+
sierra_contract: SierraContractClass,
8382
) -> StateResult<(ContractClass, SierraVersion)> {
84-
let serde_value = serde_json::to_value(&flattened_sierra)
85-
.unwrap_or_else(|err| panic!("Failed to serialize flattened Sierra: {err}"));
86-
let sierra_contract: SierraContractClass =
87-
serde_json::from_value(serde_value).unwrap_or_else(|err| {
88-
panic!(
89-
"Failed to deserialize SierraContractClass: {err} for flattened_sierra: \
90-
{flattened_sierra:?}"
91-
);
92-
});
9383
let sierra_version = SierraVersion::extract_from_program(&sierra_contract.sierra_program)
9484
.unwrap_or_else(|err| panic!("Failed to extract Sierra version: {err}"));
9585
let raw_class = RawClass::try_from(sierra_contract)

crates/blockifier_reexecution/src/state_reader/offline_state_reader.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ use blockifier::context::BlockContext;
99
use blockifier::execution::contract_class::RunnableCompiledClass;
1010
use blockifier::state::cached_state::{CommitmentStateDiff, StateMaps};
1111
use blockifier::state::errors::StateError;
12+
use blockifier::state::global_cache::CompiledClasses;
1213
use blockifier::state::state_api::{StateReader, StateResult};
14+
use blockifier::state::state_reader_and_contract_manager::FetchCompiledClasses;
1315
use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction;
1416
use serde::{Deserialize, Serialize};
1517
use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockInfo, BlockNumber, StarknetVersion};
1618
use starknet_api::core::{ChainId, ClassHash, CompiledClassHash, ContractAddress, Nonce};
17-
use starknet_api::state::StorageKey;
19+
use starknet_api::state::{SierraContractClass, StorageKey};
1820
use starknet_api::transaction::{Transaction, TransactionHash};
1921
use starknet_api::versioned_constants_logic::VersionedConstantsTrait;
2022
use starknet_core::types::ContractClass as StarknetContractClass;
@@ -160,7 +162,8 @@ impl StateReader for OfflineStateReader {
160162
fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult<RunnableCompiledClass> {
161163
match self.get_contract_class(&class_hash)? {
162164
StarknetContractClass::Sierra(sierra) => {
163-
let (casm, _) = sierra_to_versioned_contract_class_v1(sierra).unwrap();
165+
let sierra_contract = SierraContractClass::from(sierra);
166+
let (casm, _) = sierra_to_versioned_contract_class_v1(sierra_contract).unwrap();
164167
Ok(casm.try_into().unwrap())
165168
}
166169
StarknetContractClass::Legacy(legacy) => {
@@ -192,6 +195,19 @@ impl ReexecutionStateReader for OfflineStateReader {
192195
}
193196
}
194197

198+
impl FetchCompiledClasses for OfflineStateReader {
199+
fn get_compiled_classes(&self, class_hash: ClassHash) -> StateResult<CompiledClasses> {
200+
let contract_class = self.get_contract_class(&class_hash)?;
201+
self.starknet_core_contract_class_to_compiled_class(contract_class)
202+
}
203+
204+
/// This check is no needed in the reexecution context.
205+
/// We assume that all the classes returned successfuly by the OfflineStateReader are declared.
206+
fn is_declared(&self, _class_hash: ClassHash) -> StateResult<bool> {
207+
Ok(true)
208+
}
209+
}
210+
195211
impl OfflineStateReader {
196212
pub fn get_transaction_executor(
197213
self,

crates/blockifier_reexecution/src/state_reader/reexecution_state_reader.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ use apollo_rpc_execution::DEPRECATED_CONTRACT_SIERRA_SIZE;
22
use blockifier::blockifier::config::TransactionExecutorConfig;
33
use blockifier::blockifier::transaction_executor::TransactionExecutor;
44
use blockifier::state::cached_state::CommitmentStateDiff;
5+
use blockifier::state::global_cache::CompiledClasses;
56
use blockifier::state::state_api::{StateReader, StateResult};
67
use blockifier::transaction::account_transaction::ExecutionFlags;
78
use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction;
89
use starknet_api::block::{BlockHash, BlockNumber};
910
use starknet_api::contract_class::{ClassInfo, SierraVersion};
1011
use starknet_api::core::ClassHash;
12+
use starknet_api::state::SierraContractClass;
1113
use starknet_api::test_utils::MAX_FEE;
1214
use starknet_api::transaction::{Transaction, TransactionHash};
1315
use starknet_core::types::ContractClass as StarknetContractClass;
@@ -17,6 +19,7 @@ use crate::state_reader::compile::{
1719
sierra_to_versioned_contract_class_v1,
1820
};
1921
use crate::state_reader::errors::ReexecutionResult;
22+
use crate::state_reader::utils::contract_class_to_compiled_classes;
2023

2124
pub trait ReexecutionStateReader {
2225
fn get_contract_class(&self, class_hash: &ClassHash) -> StateResult<StarknetContractClass>;
@@ -27,8 +30,9 @@ pub trait ReexecutionStateReader {
2730
let abi_length = sierra.abi.len();
2831
let sierra_length = sierra.sierra_program.len();
2932

33+
let sierra_contract = SierraContractClass::from(sierra);
3034
let (contract_class, sierra_version) =
31-
sierra_to_versioned_contract_class_v1(sierra)?;
35+
sierra_to_versioned_contract_class_v1(sierra_contract)?;
3236

3337
Ok(ClassInfo::new(&contract_class, sierra_length, abi_length, sierra_version)?)
3438
}
@@ -92,6 +96,26 @@ pub trait ReexecutionStateReader {
9296
}
9397

9498
fn get_old_block_hash(&self, old_block_number: BlockNumber) -> ReexecutionResult<BlockHash>;
99+
100+
/// Converts a `starknet_core::types::ContractClass` to `CompiledClasses`.
101+
fn starknet_core_contract_class_to_compiled_class(
102+
&self,
103+
contract_class: StarknetContractClass,
104+
) -> StateResult<CompiledClasses> {
105+
match contract_class {
106+
StarknetContractClass::Sierra(flat_sierra) => {
107+
let sierra = SierraContractClass::from(flat_sierra);
108+
let (class_v1, _) = sierra_to_versioned_contract_class_v1(sierra.clone())?;
109+
110+
Ok(contract_class_to_compiled_classes(class_v1, Some(sierra))?)
111+
}
112+
StarknetContractClass::Legacy(legacy) => {
113+
let class_v0 = legacy_to_contract_class_v0(legacy)?;
114+
115+
Ok(contract_class_to_compiled_classes(class_v0, None)?)
116+
}
117+
}
118+
}
95119
}
96120

97121
/// Trait of the functions \ queries required for reexecution.

crates/blockifier_reexecution/src/state_reader/test_state_reader.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ use blockifier::context::BlockContext;
1515
use blockifier::execution::contract_class::RunnableCompiledClass;
1616
use blockifier::state::cached_state::CommitmentStateDiff;
1717
use blockifier::state::errors::StateError;
18+
use blockifier::state::global_cache::CompiledClasses;
1819
use blockifier::state::state_api::{StateReader, StateResult};
20+
use blockifier::state::state_reader_and_contract_manager::FetchCompiledClasses;
1921
use blockifier::transaction::transaction_execution::Transaction as BlockifierTransaction;
2022
use serde::Serialize;
2123
use serde_json::{json, to_value};
@@ -28,7 +30,7 @@ use starknet_api::block::{
2830
StarknetVersion,
2931
};
3032
use starknet_api::core::{ChainId, ClassHash, CompiledClassHash, ContractAddress, Nonce};
31-
use starknet_api::state::StorageKey;
33+
use starknet_api::state::{SierraContractClass, StorageKey};
3234
use starknet_api::transaction::{Transaction, TransactionHash};
3335
use starknet_api::versioned_constants_logic::VersionedConstantsTrait;
3436
use starknet_core::types::ContractClass as StarknetContractClass;
@@ -139,7 +141,8 @@ impl StateReader for TestStateReader {
139141

140142
match contract_class {
141143
StarknetContractClass::Sierra(sierra) => {
142-
let (casm, _) = sierra_to_versioned_contract_class_v1(sierra).unwrap();
144+
let sierra_contract = SierraContractClass::from(sierra);
145+
let (casm, _) = sierra_to_versioned_contract_class_v1(sierra_contract).unwrap();
143146
Ok(RunnableCompiledClass::try_from(casm).unwrap())
144147
}
145148
StarknetContractClass::Legacy(legacy) => {
@@ -153,6 +156,21 @@ impl StateReader for TestStateReader {
153156
}
154157
}
155158

159+
impl FetchCompiledClasses for TestStateReader {
160+
fn get_compiled_classes(&self, class_hash: ClassHash) -> StateResult<CompiledClasses> {
161+
let contract_class =
162+
retry_request!(self.retry_config, || self.get_contract_class(&class_hash))?;
163+
164+
self.starknet_core_contract_class_to_compiled_class(contract_class)
165+
}
166+
167+
/// This check is no needed in the reexecution context.
168+
/// We assume that all the classes returned successfuly by the rpc-provider are declared.
169+
fn is_declared(&self, _class_hash: ClassHash) -> StateResult<bool> {
170+
Ok(true)
171+
}
172+
}
173+
156174
impl TestStateReader {
157175
pub fn new(
158176
config: &RpcStateReaderConfig,

crates/blockifier_reexecution/src/state_reader/utils.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
use std::collections::{BTreeMap, HashMap};
22
use std::env;
33
use std::fs::read_to_string;
4-
use std::sync::LazyLock;
4+
use std::sync::{Arc, LazyLock};
55

66
use apollo_gateway_config::config::RpcStateReaderConfig;
77
use apollo_rpc_execution::{ETH_FEE_CONTRACT_ADDRESS, STRK_FEE_CONTRACT_ADDRESS};
88
use assert_matches::assert_matches;
99
use blockifier::context::{ChainInfo, FeeTokenAddresses};
10+
use blockifier::execution::contract_class::{CompiledClassV0, CompiledClassV1};
1011
use blockifier::state::cached_state::{CachedState, CommitmentStateDiff, StateMaps};
11-
use blockifier::state::state_api::StateReader;
12+
use blockifier::state::global_cache::CompiledClasses;
13+
use blockifier::state::state_api::{StateReader, StateResult};
1214
use indexmap::IndexMap;
1315
use pretty_assertions::assert_eq;
1416
use serde::{Deserialize, Serialize};
1517
use serde_json::Value;
1618
use starknet_api::block::BlockNumber;
19+
use starknet_api::contract_class::ContractClass;
1720
use starknet_api::core::{ChainId, ClassHash, CompiledClassHash, ContractAddress, Nonce};
18-
use starknet_api::state::StorageKey;
21+
use starknet_api::state::{SierraContractClass, StorageKey};
1922
use starknet_api::transaction::TransactionHash;
2023
use starknet_types_core::felt::Felt;
2124

@@ -39,6 +42,30 @@ pub static RPC_NODE_URL: LazyLock<String> = LazyLock::new(|| {
3942
.unwrap_or_else(|_| "https://free-rpc.nethermind.io/mainnet-juno/".to_string())
4043
});
4144

45+
/// Converts a [`starknet_api::contract_class::ContractClass`] into the corresponding
46+
/// [`CompiledClasses`].
47+
///
48+
/// For `V1` (Cairo 1) classes, a matching `SierraContractClass` must be provided.
49+
/// For `V0` classes, this argument should be `None`.
50+
pub fn contract_class_to_compiled_classes(
51+
contract_class: ContractClass,
52+
sierra_contract_class: Option<SierraContractClass>,
53+
) -> StateResult<CompiledClasses> {
54+
match contract_class {
55+
ContractClass::V0(deprecated_class) => {
56+
Ok(CompiledClasses::V0(CompiledClassV0::try_from(deprecated_class)?))
57+
}
58+
ContractClass::V1(versioned_casm) => {
59+
let sierra_contract_class =
60+
sierra_contract_class.expect("V1 contract class requires Sierra class");
61+
Ok(CompiledClasses::V1(
62+
CompiledClassV1::try_from(versioned_casm)?,
63+
Arc::new(sierra_contract_class),
64+
))
65+
}
66+
}
67+
}
68+
4269
/// Returns the fee token addresses of mainnet.
4370
pub fn get_fee_token_addresses(chain_id: &ChainId) -> FeeTokenAddresses {
4471
match chain_id {

crates/starknet_api/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ semver.workspace = true
3434
serde = { workspace = true, features = ["derive", "rc"] }
3535
serde_json.workspace = true
3636
sha3.workspace = true
37+
starknet-core.workspace = true
3738
starknet-crypto.workspace = true
3839
starknet-types-core = { workspace = true, features = ["hash"] }
3940
strum = { workspace = true, features = ["derive"] }

crates/starknet_api/src/rpc_transaction.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::collections::HashMap;
77
use apollo_sizeof::SizeOf;
88
use cairo_lang_starknet_classes::contract_class::ContractEntryPoints as CairoLangContractEntryPoints;
99
use serde::{Deserialize, Serialize};
10+
use starknet_core::types::EntryPointsByType as StarknetCoreEntryPointsByType;
1011
use strum::EnumVariantNames;
1112
use strum_macros::{EnumDiscriminants, EnumIter, IntoStaticStr};
1213

@@ -680,6 +681,16 @@ impl From<CairoLangContractEntryPoints> for EntryPointByType {
680681
}
681682
}
682683

684+
impl From<StarknetCoreEntryPointsByType> for EntryPointByType {
685+
fn from(value: StarknetCoreEntryPointsByType) -> Self {
686+
Self {
687+
constructor: value.constructor.into_iter().map(EntryPoint::from).collect(),
688+
external: value.external.into_iter().map(EntryPoint::from).collect(),
689+
l1handler: value.l1_handler.into_iter().map(EntryPoint::from).collect(),
690+
}
691+
}
692+
}
693+
683694
impl EntryPointByType {
684695
pub fn from_hash_map(entry_points_by_type: HashMap<EntryPointType, Vec<EntryPoint>>) -> Self {
685696
macro_rules! get_entrypoint_by_type {

crates/starknet_api/src/state.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use cairo_lang_starknet_classes::contract_class::ContractEntryPoint as CairoLang
99
use indexmap::IndexMap;
1010
use serde::{Deserialize, Serialize};
1111
use sha3::Digest;
12+
use starknet_core::types::{FlattenedSierraClass, SierraEntryPoint};
1213
use starknet_types_core::felt::Felt;
1314
use starknet_types_core::hash::{Poseidon, StarkHash as SNTypsCoreStarkHash};
1415

@@ -270,6 +271,17 @@ impl SierraContractClass {
270271
}
271272
}
272273

274+
impl From<FlattenedSierraClass> for SierraContractClass {
275+
fn from(flattened_sierra: FlattenedSierraClass) -> Self {
276+
Self {
277+
sierra_program: flattened_sierra.sierra_program,
278+
contract_class_version: flattened_sierra.contract_class_version,
279+
entry_points_by_type: flattened_sierra.entry_points_by_type.into(),
280+
abi: flattened_sierra.abi,
281+
}
282+
}
283+
}
284+
273285
#[derive(Clone, Debug, Deserialize)]
274286
pub struct ContractClassComponentHashes {
275287
pub contract_class_version: Felt,
@@ -327,6 +339,18 @@ impl From<CairoLangContractEntryPoint> for EntryPoint {
327339
}
328340
}
329341

342+
impl From<SierraEntryPoint> for EntryPoint {
343+
fn from(entry_point: SierraEntryPoint) -> Self {
344+
Self {
345+
function_idx: FunctionIndex(
346+
usize::try_from(entry_point.function_idx)
347+
.expect("Function index should fit in a usize"),
348+
),
349+
selector: EntryPointSelector(entry_point.selector),
350+
}
351+
}
352+
}
353+
330354
#[derive(
331355
Debug, Copy, Clone, Default, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord,
332356
)]

0 commit comments

Comments
 (0)