Skip to content

Commit

Permalink
test(cairo_native): test papyrus state reader get compiled class
Browse files Browse the repository at this point in the history
  • Loading branch information
meship-starkware committed Dec 29, 2024
1 parent 6f09863 commit 75f1a4f
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@ deployments/papyrus/helm/config/*

# Generated file used for running contracts compiled with Cairo Native
crates/blockifier/libcairo_native_runtime.a
crates/papyrus_state_reader/libcairo_native_runtime.a
2 changes: 2 additions & 0 deletions Cargo.lock

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

10 changes: 10 additions & 0 deletions crates/blockifier/src/blockifier/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ impl Default for ContractClassManagerConfig {
}
}

impl ContractClassManagerConfig {
#[cfg(any(test, feature = "testing", feature = "native_blockifier"))]
pub fn create_for_testing(
run_cairo_native: bool,
wait_on_native_compilation: bool,
) -> Self {
Self { run_cairo_native, wait_on_native_compilation, contract_cache_size: GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST }
}
}

impl SerializeConfig for ContractClassManagerConfig {
fn dump(&self) -> BTreeMap<ParamPath, SerializedParam> {
BTreeMap::from_iter([
Expand Down
6 changes: 6 additions & 0 deletions crates/papyrus_state_reader/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@ workspace = true
[dependencies]
blockifier.workspace = true
papyrus_storage.workspace = true
rstest = { workspace = true, optional = true }
starknet-types-core.workspace = true
starknet_api.workspace = true

[dev-dependencies]
assert_matches.workspace = true
blockifier = { workspace = true, features = ["testing"] }
indexmap.workspace = true
rstest.workspace = true
papyrus_storage = { workspace = true, features = ["testing"] }


[build-dependencies]
infra_utils.workspace = true
69 changes: 69 additions & 0 deletions crates/papyrus_state_reader/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#[cfg(feature = "cairo_native")]
fn compile_cairo_native_aot_runtime() {
use std::path::PathBuf;
use std::process::Command;

use infra_utils::compile_time_cargo_manifest_dir;
use infra_utils::path::current_dir;

let cairo_native_dir =
PathBuf::from(compile_time_cargo_manifest_dir!()).join(PathBuf::from("../blockifier/cairo_native"));

if !cairo_native_dir.exists() || !cairo_native_dir.join(".git").exists() {
panic!(
"It seems git submodule at {} doesn't exist or it is not initialized, please \
run:\n\ngit submodule update --init --recursive\n",
cairo_native_dir.to_str().unwrap()
);
}

let runtime_target_dir = cairo_native_dir.join(PathBuf::from("target"));
let status = Command::new("cargo")
.args([
"build",
"--release",
"-p",
"cairo-native-runtime",
"--message-format=json",
"--target-dir",
runtime_target_dir.to_str().unwrap(),
])
.current_dir(cairo_native_dir)
.status()
.expect("Failed to execute cargo");
if !status.success() {
panic!("Building cairo native runtime failed: {status}")
}

let runtime_target_path =
runtime_target_dir.join(PathBuf::from("release/libcairo_native_runtime.a"));

const RUNTIME_LIBRARY: &str = "CAIRO_NATIVE_RUNTIME_LIBRARY";
let runtime_expected_path = {
let expected_path_env =
std::env::var(RUNTIME_LIBRARY).expect("Cairo Native runtime path variable is not set");
let expected_path = PathBuf::from(&expected_path_env);

if expected_path.is_absolute() {
expected_path
} else {
current_dir().expect("Failed to get current directory").join(expected_path)
}
};

std::fs::copy(&runtime_target_path, &runtime_expected_path)
.expect("Failed to copy native runtime");

println!("cargo::rerun-if-changed=./cairo_native/runtime/");
// todo(rodrigo): this directive seems to cause the build script to trigger everytime on
// Linux based machines. Investigate the issue further.
println!("cargo::rerun-if-changed={}", runtime_expected_path.to_str().unwrap());
println!("cargo::rerun-if-env-changed={RUNTIME_LIBRARY}");
}

fn main() {
// Build instructions are defined behind this condition since they are only relevant when using
// Cairo Native.
#[cfg(feature = "cairo_native")]
compile_cairo_native_aot_runtime();
}
1 change: 1 addition & 0 deletions crates/papyrus_state_reader/src/papyrus_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ impl PapyrusReader {
.get_state_reader()
.and_then(|sr| sr.get_class_definition_block_number(&class_hash))
.map_err(|err| StateError::StateReadError(err.to_string()))?;

let class_is_declared: bool = matches!(class_declaration_block_number,
Some(block_number) if block_number <= state_number.0);

Expand Down
69 changes: 67 additions & 2 deletions crates/papyrus_state_reader/src/papyrus_state_test.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
use core::panic;

use assert_matches::assert_matches;
use blockifier::blockifier::config::ContractClassManagerConfig;
use blockifier::execution::call_info::CallExecution;
use blockifier::execution::contract_class::RunnableCompiledClass;
use blockifier::execution::entry_point::CallEntryPoint;
use blockifier::retdata;
use blockifier::state::cached_state::CachedState;
use blockifier::state::contract_class_manager::ContractClassManager;
use blockifier::state::state_api::StateReader;
use blockifier::test_utils::contracts::FeatureContract;
use blockifier::test_utils::{trivial_external_entry_point_new, CairoVersion};
use blockifier::test_utils::{trivial_external_entry_point_new, CairoVersion, RunnableCairo1};
use indexmap::IndexMap;
use papyrus_storage::class::ClassStorageWriter;
use papyrus_storage::compiled_class::CasmStorageWriter;
use papyrus_storage::state::StateStorageWriter;
use rstest::rstest;
use starknet_api::abi::abi_utils::selector_from_name;
use starknet_api::block::BlockNumber;
use starknet_api::contract_class::ContractClass;
use starknet_api::state::{StateDiff, StorageKey};
use starknet_api::core::Nonce;
use starknet_api::state::{StateDiff, StorageKey, ThinStateDiff};
use starknet_api::{calldata, felt};

use crate::papyrus_state::PapyrusReader;
Expand Down Expand Up @@ -76,3 +82,62 @@ fn test_entry_point_with_papyrus_state() -> papyrus_storage::StorageResult<()> {

Ok(())
}

#[cfg(feature = "cairo_native")]
#[rstest]
fn test_get_compiled_class(
#[values(true, false)] is_cached: bool,
) -> papyrus_storage::StorageResult<()> {
use std::sync::Arc;

use blockifier::state::global_cache::CachedCasm;

let ((storage_reader, mut storage_writer), _) = papyrus_storage::test_utils::get_test_storage();
let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm));
let compiled_class = if let ContractClass::V1((casm_class, _)) = test_contract.get_class() {
casm_class
} else {
panic!("expected a V1 class")
};
let test_class_hash = test_contract.get_class_hash();
let test_compiled_class_hash = test_contract.get_compiled_class_hash();
let block_number = BlockNumber::default();

let thin_state_diff = ThinStateDiff {
declared_classes: IndexMap::from([(test_class_hash, test_compiled_class_hash)]),
nonces: IndexMap::from([(test_contract.get_instance_address(1), Nonce(1.into()))]),
..Default::default()
};
let _ = storage_writer
.begin_rw_txn()?
.append_state_diff(block_number, thin_state_diff)?
.append_classes(block_number, &[(test_class_hash, &test_contract.get_sierra())], &[])?
.append_casm(&test_class_hash, &compiled_class)?
.commit();
let contract_manager_config = ContractClassManagerConfig::create_for_testing(true, true);

let papyrus_reader = PapyrusReader::new(
storage_reader,
block_number,
ContractClassManager::start(contract_manager_config),
);
if is_cached {
papyrus_reader.contract_class_manager.set_casm(
test_class_hash,
CachedCasm::WithSierra(
test_contract.get_runnable_class(),
Arc::new(test_contract.get_sierra()),
),
);
}
let compiled_class = papyrus_reader.get_compiled_class(test_class_hash);
assert!(compiled_class.is_ok(), "compilation should have succeeded in this case");

assert_matches!(
compiled_class,
Ok(RunnableCompiledClass::V1Native(_)),
"compilation should have succeeded in this case"
);

Ok(())
}

0 comments on commit 75f1a4f

Please sign in to comment.