Skip to content

Commit

Permalink
build: blockifier regression test compile class
Browse files Browse the repository at this point in the history
  • Loading branch information
AvivYossef-starkware committed Sep 24, 2024
1 parent b65faeb commit 5120916
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 2 deletions.
6 changes: 6 additions & 0 deletions Cargo.lock

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

6 changes: 6 additions & 0 deletions crates/blockifier_regression_test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@ license-file.workspace = true

[dependencies]
blockifier = { workspace = true }
cairo-lang-starknet-classes.workspace = true
cairo-lang-utils.workspace = true
cairo-vm.workspace = true
flate2.workspace = true
papyrus_execution = { workspace = true }
serde.workspace = true
serde_json.workspace = true
starknet-core.workspace = true
starknet-types-core.workspace = true
starknet_api = { workspace = true }
starknet_gateway = { workspace = true }
Expand Down
99 changes: 99 additions & 0 deletions crates/blockifier_regression_test/src/compile.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use std::collections::HashMap;
use std::io::{self, Read};
use std::sync::Arc;

use blockifier::execution::contract_class::{ContractClass, ContractClassV0, ContractClassV0Inner};
use blockifier::state::state_api::StateResult;
use cairo_lang_starknet_classes::contract_class::ContractEntryPoints;
use cairo_lang_utils::bigint::BigUintAsHex;
use cairo_vm::types::program::Program;
use flate2::bufread;
use serde::Deserialize;
use starknet_api::core::EntryPointSelector;
use starknet_api::deprecated_contract_class::{EntryPoint, EntryPointOffset, EntryPointType};
use starknet_api::hash::StarkHash;
use starknet_core::types::{
CompressedLegacyContractClass,
FlattenedSierraClass,
LegacyContractEntryPoint,
LegacyEntryPointsByType,
};
use starknet_gateway::errors::serde_err_to_state_err;

#[derive(Debug, Deserialize)]
pub struct MiddleSierraContractClass {
pub sierra_program: Vec<BigUintAsHex>,
pub contract_class_version: String,
pub entry_points_by_type: ContractEntryPoints,
}

/// Maps `LegacyEntryPointsByType` to a `HashMap` where each `EntryPointType`
/// is associated with a vector of `EntryPoint`. Converts selectors and offsets
/// from legacy format to new `EntryPoint` struct.
pub fn map_entry_points_by_type_legacy(
entry_points_by_type: LegacyEntryPointsByType,
) -> HashMap<EntryPointType, Vec<EntryPoint>> {
let entry_types_to_points = HashMap::from([
(EntryPointType::Constructor, entry_points_by_type.constructor),
(EntryPointType::External, entry_points_by_type.external),
(EntryPointType::L1Handler, entry_points_by_type.l1_handler),
]);

let to_contract_entry_point = |entrypoint: &LegacyContractEntryPoint| -> EntryPoint {
let felt: StarkHash = StarkHash::from_bytes_be(&entrypoint.selector.to_bytes_be());
EntryPoint {
offset: EntryPointOffset(usize::try_from(entrypoint.offset).unwrap()),
selector: EntryPointSelector(felt),
}
};

let mut entry_points_by_type_map = HashMap::new();
for (entry_point_type, entry_points) in entry_types_to_points.into_iter() {
let values = entry_points.iter().map(to_contract_entry_point).collect::<Vec<_>>();
entry_points_by_type_map.insert(entry_point_type, values);
}

entry_points_by_type_map
}

/// Uncompresses a Gz Encoded vector of bytes and returns a string or error
/// Here &[u8] implements BufRead
pub fn decode_reader(bytes: Vec<u8>) -> io::Result<String> {
let mut gz = bufread::GzDecoder::new(&bytes[..]);
let mut s = String::new();
gz.read_to_string(&mut s)?;
Ok(s)
}

pub fn sierra_to_contact_class_v1(sierra: FlattenedSierraClass) -> StateResult<ContractClass> {
let middle_sierra: MiddleSierraContractClass = {
let v = serde_json::to_value(sierra).map_err(serde_err_to_state_err);
serde_json::from_value(v?).map_err(serde_err_to_state_err)?
};
let sierra = cairo_lang_starknet_classes::contract_class::ContractClass {
sierra_program: middle_sierra.sierra_program,
contract_class_version: middle_sierra.contract_class_version,
entry_points_by_type: middle_sierra.entry_points_by_type,
sierra_program_debug_info: None,
abi: None,
};

let casm =
cairo_lang_starknet_classes::casm_contract_class::CasmContractClass::from_contract_class(
sierra,
false,
usize::MAX,
)
.unwrap();
Ok(ContractClass::V1(casm.try_into().unwrap()))
}

pub fn legacy_to_contract_class_v0(
legacy: CompressedLegacyContractClass,
) -> StateResult<ContractClass> {
let as_str = decode_reader(legacy.program).unwrap();
let program = Program::from_bytes(as_str.as_bytes(), None).unwrap();
let entry_points_by_type = map_entry_points_by_type_legacy(legacy.entry_points_by_type);
let inner = Arc::new(ContractClassV0Inner { program, entry_points_by_type });
Ok(ContractClass::V0(ContractClassV0(inner)))
}
1 change: 1 addition & 0 deletions crates/blockifier_regression_test/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod compile;
pub mod test_state_reader;
pub mod test_utils;
51 changes: 49 additions & 2 deletions crates/blockifier_regression_test/src/test_state_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use blockifier::state::cached_state::CachedState;
use blockifier::state::errors::StateError;
use blockifier::state::state_api::{StateReader, StateResult};
use blockifier::versioned_constants::{StarknetVersion, VersionedConstants};
use serde_json::json;
use starknet_api::block::BlockNumber;
use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce};
use starknet_api::state::StorageKey;
Expand All @@ -18,6 +19,7 @@ use starknet_gateway::rpc_state_reader::RpcStateReader;
use starknet_gateway::state_reader::MempoolStateReader;
use starknet_types_core::felt::Felt;

use crate::compile::{legacy_to_contract_class_v0, sierra_to_contact_class_v1};
use crate::test_utils::{get_chain_info, get_rpc_state_reader_config};

pub struct TestStateReader(RpcStateReader);
Expand All @@ -39,8 +41,20 @@ impl StateReader for TestStateReader {
self.0.get_class_hash_at(contract_address)
}

fn get_compiled_contract_class(&self, _class_hash: ClassHash) -> StateResult<ContractClass> {
todo!()
/// Returns the contract class of the given class hash.
/// Compile the contract class if it is Sierra.
fn get_compiled_contract_class(
&self,
class_hash: starknet_api::core::ClassHash,
) -> StateResult<ContractClass> {
match self.get_contract_class(&class_hash)? {
starknet_core::types::ContractClass::Sierra(sierra) => {
sierra_to_contact_class_v1(sierra)
}
starknet_core::types::ContractClass::Legacy(legacy) => {
legacy_to_contract_class_v0(legacy)
}
}
}

fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult<CompiledClassHash> {
Expand Down Expand Up @@ -78,6 +92,20 @@ impl TestStateReader {
}
}

pub fn get_contract_class(
&self,
class_hash: &ClassHash,
) -> StateResult<starknet_core::types::ContractClass> {
let params = json!({
"block_id": self.0.block_id,
"class_hash": class_hash.0.to_string(),
});
let contract_class: starknet_core::types::ContractClass =
serde_json::from_value(self.0.send_rpc_request("starknet_getClass", params.clone())?)
.map_err(serde_err_to_state_err)?;
Ok(contract_class)
}

pub fn get_versioned_constants(&self) -> StateResult<&'static VersionedConstants> {
let starknet_version = self.get_starknet_version()?;
let versioned_constants: &'static VersionedConstants = starknet_version.into();
Expand Down Expand Up @@ -109,9 +137,12 @@ impl TestStateReader {
pub mod test {
use assert_matches::assert_matches;
use blockifier::blockifier::block::BlockInfo;
use blockifier::state::state_api::StateReader;
use blockifier::versioned_constants::StarknetVersion;
use rstest::*;
use starknet_api::block::BlockNumber;
use starknet_api::core::ClassHash;
use starknet_api::{class_hash, felt};

use super::TestStateReader;

Expand All @@ -136,4 +167,20 @@ pub mod test {
pub fn test_get_starknet_version(test_state_reader: TestStateReader) {
assert!(test_state_reader.get_starknet_version().unwrap() == StarknetVersion::V0_13_2_1)
}

#[rstest]
#[ignore = "This test using http request, so it should not be run in CI"]
pub fn test_get_contract_class(test_state_reader: TestStateReader) {
let class_hash =
class_hash!("0x3131fa018d520a037686ce3efddeab8f28895662f019ca3ca18a626650f7d1e");
test_state_reader.get_contract_class(&class_hash).unwrap();
}

#[rstest]
#[ignore = "This test using http request, so it should not be run in CI"]
pub fn test_get_compiled_contract_class(test_state_reader: TestStateReader) {
let class_hash =
class_hash!("0x3131fa018d520a037686ce3efddeab8f28895662f019ca3ca18a626650f7d1e");
test_state_reader.get_compiled_contract_class(class_hash).unwrap();
}
}

0 comments on commit 5120916

Please sign in to comment.