Skip to content

Commit

Permalink
feat(blockifier): add support for native testing (#1301)
Browse files Browse the repository at this point in the history
* feat: add native to testing suite

* feat(blockifier): add cairo native feature test folder and contract

* refactor: starknet compile function in casm compile

* refactor: use unwrap_or_else instead of match

* chore: add Native as a compilation feature

* fix: compilation issues caused by previous refactor

* feat(blockifier): add support for native testing

Co-Authored-By: Bohdan Ohorodnii <[email protected]>
Co-Authored-By: Noa Oved <[email protected]>
  • Loading branch information
3 people authored Nov 10, 2024
1 parent eba18d3 commit adbaf96
Show file tree
Hide file tree
Showing 11 changed files with 9,592 additions and 28 deletions.

Large diffs are not rendered by default.

608 changes: 608 additions & 0 deletions crates/blockifier/feature_contracts/cairo_native/test_contract.cairo

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion crates/blockifier/src/execution/native/contract_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use cairo_lang_starknet_classes::contract_class::{
ContractClass as SierraContractClass,
ContractEntryPoint as SierraContractEntryPoint,
};
#[allow(unused_imports)]
use cairo_native::executor::AotNativeExecutor;
use starknet_api::core::EntryPointSelector;

Expand Down
20 changes: 20 additions & 0 deletions crates/blockifier/src/execution/stack_trace_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ Error in contract (contract address: {test_contract_address_2_felt:#064x}, class
let expected_trace = match cairo_version {
CairoVersion::Cairo0 => expected_trace_cairo0,
CairoVersion::Cairo1 => expected_trace_cairo1,
#[cfg(feature = "cairo_native")]
CairoVersion::Native => panic!("Cairo Native is not yet supported"),
};

assert_eq!(tx_execution_error.to_string(), expected_trace);
Expand Down Expand Up @@ -365,6 +367,10 @@ Error in contract (contract address: {contract_address_felt:#064x}, class hash:
"
)
}
#[cfg(feature = "cairo_native")]
CairoVersion::Native => {
todo!("Cairo Native is not yet supported here")
}
};

assert_eq!(tx_execution_error.to_string(), expected_trace);
Expand Down Expand Up @@ -520,6 +526,10 @@ Error in contract (contract address: {address_felt:#064x}, class hash: {test_con
"
)
}
#[cfg(feature = "cairo_native")]
CairoVersion::Native => {
todo!("Cairo Native not yet supported here.")
}
};

assert_eq!(tx_execution_error.to_string(), expected_trace);
Expand Down Expand Up @@ -620,6 +630,8 @@ Error in contract (contract address: {contract_address:#064x}, class hash: {:#06
0x496e76616c6964207363656e6172696f ('Invalid scenario').",
class_hash.0
),
#[cfg(feature = "cairo_native")]
CairoVersion::Native => todo!("Cairo Native is not yet supported here."),
};

// Clean pc locations from the trace.
Expand Down Expand Up @@ -692,6 +704,10 @@ Error in contract (contract address: {expected_address:#064x}, class hash: {:#06
class_hash.0
)
.to_string(),
#[cfg(feature = "cairo_native")]
CairoVersion::Native => {
todo!("Cairo Native not yet supported here.")
}
};

// Compare expected and actual error.
Expand Down Expand Up @@ -829,6 +845,10 @@ Error in contract (contract address: {expected_address:#064x}, class hash: {:#06
ctor_selector.0
)
}
#[cfg(feature = "cairo_native")]
CairoVersion::Native => {
todo!("Cairo Native not yet supported here.")
}
};

// Compare expected and actual error.
Expand Down
26 changes: 22 additions & 4 deletions crates/blockifier/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ pub const ERC20_CONTRACT_PATH: &str = "./ERC20/ERC20_Cairo0/ERC20_without_some_s
pub enum CairoVersion {
Cairo0,
Cairo1,
#[cfg(feature = "cairo_native")]
Native,
}

impl Default for CairoVersion {
Expand All @@ -91,6 +93,8 @@ impl CairoVersion {
match self {
Self::Cairo0 => Self::Cairo1,
Self::Cairo1 => Self::Cairo0,
#[cfg(feature = "cairo_native")]
Self::Native => panic!("There is no other version for native"),
}
}
}
Expand All @@ -117,6 +121,8 @@ impl CompilerBasedVersion {
TrackedResource::CairoSteps
}
Self::CairoVersion(CairoVersion::Cairo1) => TrackedResource::SierraGas,
#[cfg(feature = "cairo_native")]
Self::CairoVersion(CairoVersion::Native) => TrackedResource::SierraGas,
}
}
}
Expand Down Expand Up @@ -319,8 +325,6 @@ macro_rules! check_tx_execution_error_for_custom_hint {
#[macro_export]
macro_rules! check_tx_execution_error_for_invalid_scenario {
($cairo_version:expr, $error:expr, $validate_constructor:expr $(,)?) => {
use $crate::transaction::errors::TransactionExecutionError;

match $cairo_version {
CairoVersion::Cairo0 => {
$crate::check_tx_execution_error_inner!(
Expand All @@ -329,8 +333,22 @@ macro_rules! check_tx_execution_error_for_invalid_scenario {
$validate_constructor,
);
}
CairoVersion::Cairo1 => {
if let TransactionExecutionError::ValidateTransactionError { error, .. } = $error {
CairoVersion::Cairo1 => {
if let $crate::transaction::errors::TransactionExecutionError::ValidateTransactionError {
error, ..
} = $error {
assert_eq!(
error.to_string(),
"Execution failed. Failure reason: 0x496e76616c6964207363656e6172696f \
('Invalid scenario')."
)
}
}
#[cfg(feature = "cairo_native")]
CairoVersion::Native => {
if let $crate::transaction::errors::TransactionExecutionError::ValidateTransactionError {
error, ..
} = $error {
assert_eq!(
error.to_string(),
"Execution failed. Failure reason: 0x496e76616c6964207363656e6172696f \
Expand Down
51 changes: 34 additions & 17 deletions crates/blockifier/src/test_utils/cairo_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ fn local_cairo1_compiler_repo_path() -> PathBuf {
// Location of blockifier's Cargo.toml.
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();

Path::new(&manifest_dir).join(match std::env::var(CAIRO1_REPO_RELATIVE_PATH_OVERRIDE_ENV_VAR) {
Ok(cairo1_repo_relative_path) => cairo1_repo_relative_path,
Err(_) => DEFAULT_CAIRO1_REPO_RELATIVE_PATH.into(),
})
Path::new(&manifest_dir).join(
env::var(CAIRO1_REPO_RELATIVE_PATH_OVERRIDE_ENV_VAR)
.unwrap_or_else(|_| DEFAULT_CAIRO1_REPO_RELATIVE_PATH.into()),
)
}

/// Runs a command. If it has succeeded, it returns the command's output; otherwise, it panics with
Expand Down Expand Up @@ -110,16 +110,43 @@ pub fn cairo1_compile(
path: String,
git_tag_override: Option<String>,
cargo_nightly_arg: Option<String>,
) -> Vec<u8> {
let mut base_compile_args = vec![];

let sierra_output =
starknet_compile(path, git_tag_override, cargo_nightly_arg, &mut base_compile_args);

let mut temp_file = NamedTempFile::new().unwrap();
temp_file.write_all(&sierra_output).unwrap();
let temp_path_str = temp_file.into_temp_path();

// Sierra -> CASM.
let mut sierra_compile_command = Command::new("cargo");
sierra_compile_command.args(base_compile_args);
sierra_compile_command.args(["starknet-sierra-compile", temp_path_str.to_str().unwrap()]);
let casm_output = run_and_verify_output(&mut sierra_compile_command);

casm_output.stdout
}

/// Compile Cairo1 Contract into their Sierra version using the compiler version set in the
/// Cargo.toml
pub fn starknet_compile(
path: String,
git_tag_override: Option<String>,
cargo_nightly_arg: Option<String>,
base_compile_args: &mut Vec<String>,
) -> Vec<u8> {
prepare_cairo1_compiler_deps(git_tag_override);

let cairo1_compiler_path = local_cairo1_compiler_repo_path();

// Command args common to both compilation phases.
let mut base_compile_args = vec![
base_compile_args.extend(vec![
"run".into(),
format!("--manifest-path={}/Cargo.toml", cairo1_compiler_path.to_string_lossy()),
"--bin".into(),
];
]);
// Add additional cargo arg if provided. Should be first arg (base command is `cargo`).
if let Some(nightly_version) = cargo_nightly_arg {
base_compile_args.insert(0, format!("+nightly-{nightly_version}"));
Expand All @@ -131,17 +158,7 @@ pub fn cairo1_compile(
starknet_compile_commmand.args(["starknet-compile", "--", "--single-file", &path]);
let sierra_output = run_and_verify_output(&mut starknet_compile_commmand);

let mut temp_file = NamedTempFile::new().unwrap();
temp_file.write_all(&sierra_output.stdout).unwrap();
let temp_path_str = temp_file.into_temp_path();

// Sierra -> CASM.
let mut sierra_compile_command = Command::new("cargo");
sierra_compile_command.args(base_compile_args);
sierra_compile_command.args(["starknet-sierra-compile", temp_path_str.to_str().unwrap()]);
let casm_output = run_and_verify_output(&mut sierra_compile_command);

casm_output.stdout
sierra_output.stdout
}

/// Verifies that the required dependencies are available before compiling; panics if unavailable.
Expand Down
38 changes: 38 additions & 0 deletions crates/blockifier/src/test_utils/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ use crate::abi::abi_utils::selector_from_name;
use crate::abi::constants::CONSTRUCTOR_ENTRY_POINT_NAME;
use crate::execution::contract_class::RunnableContractClass;
use crate::execution::entry_point::CallEntryPoint;
#[cfg(feature = "cairo_native")]
use crate::execution::native::contract_class::NativeContractClassV1;
#[cfg(feature = "cairo_native")]
use crate::test_utils::cairo_compile::starknet_compile;
use crate::test_utils::cairo_compile::{cairo0_compile, cairo1_compile};
use crate::test_utils::struct_impls::LoadContractFromFile;
use crate::test_utils::{get_raw_contract_class, CairoVersion};
Expand Down Expand Up @@ -141,6 +145,8 @@ impl FeatureContract {
match self.cairo_version() {
CairoVersion::Cairo0 => CompiledClassHash(Felt::ZERO),
CairoVersion::Cairo1 => CompiledClassHash(felt!(self.get_integer_base())),
#[cfg(feature = "cairo_native")]
CairoVersion::Native => CompiledClassHash(felt!(self.get_integer_base())),
}
}

Expand All @@ -158,10 +164,20 @@ impl FeatureContract {
CairoVersion::Cairo1 => {
ContractClass::V1(CasmContractClass::from_file(&self.get_compiled_path()))
}
#[cfg(feature = "cairo_native")]
CairoVersion::Native => {
panic!("Native contracts are not supported by this function.")
}
}
}

pub fn get_runnable_class(&self) -> RunnableContractClass {
#[cfg(feature = "cairo_native")]
if CairoVersion::Native == self.cairo_version() {
let native_contract_class = NativeContractClassV1::from_file(&self.get_compiled_path());
return RunnableContractClass::V1Native(native_contract_class);
}

self.get_class().try_into().unwrap()
}

Expand All @@ -188,6 +204,8 @@ impl FeatureContract {
match self.cairo_version() {
CairoVersion::Cairo0 => 0,
CairoVersion::Cairo1 => CAIRO1_BIT,
#[cfg(feature = "cairo_native")]
CairoVersion::Native => CAIRO1_BIT,
}
}

Expand Down Expand Up @@ -244,6 +262,8 @@ impl FeatureContract {
match cairo_version {
CairoVersion::Cairo0 => ERC20_CAIRO0_CONTRACT_SOURCE_PATH,
CairoVersion::Cairo1 => ERC20_CAIRO1_CONTRACT_SOURCE_PATH,
#[cfg(feature = "cairo_native")]
CairoVersion::Native => todo!("ERC20 contract is not supported by Native yet"),
}
.into()
} else {
Expand All @@ -252,6 +272,8 @@ impl FeatureContract {
match self.cairo_version() {
CairoVersion::Cairo0 => "0",
CairoVersion::Cairo1 => "1",
#[cfg(feature = "cairo_native")]
CairoVersion::Native => "_native",
},
self.get_non_erc20_base_name()
)
Expand All @@ -264,6 +286,8 @@ impl FeatureContract {
match cairo_version {
CairoVersion::Cairo0 => ERC20_CAIRO0_CONTRACT_PATH,
CairoVersion::Cairo1 => ERC20_CAIRO1_CONTRACT_PATH,
#[cfg(feature = "cairo_native")]
CairoVersion::Native => todo!("ERC20 cannot be tested with Native"),
}
.into()
} else {
Expand All @@ -273,11 +297,15 @@ impl FeatureContract {
match cairo_version {
CairoVersion::Cairo0 => "0",
CairoVersion::Cairo1 => "1",
#[cfg(feature = "cairo_native")]
CairoVersion::Native => "_native",
},
self.get_non_erc20_base_name(),
match cairo_version {
CairoVersion::Cairo0 => "_compiled",
CairoVersion::Cairo1 => ".casm",
#[cfg(feature = "cairo_native")]
CairoVersion::Native => ".sierra",
}
)
}
Expand Down Expand Up @@ -309,6 +337,16 @@ impl FeatureContract {
let (tag_override, cargo_nightly_arg) = self.fixed_tag_and_rust_toolchain();
cairo1_compile(self.get_source_path(), tag_override, cargo_nightly_arg)
}
#[cfg(feature = "cairo_native")]
CairoVersion::Native => {
let (tag_override, cargo_nightly_arg) = self.fixed_tag_and_rust_toolchain();
starknet_compile(
self.get_source_path(),
tag_override,
cargo_nightly_arg,
&mut vec![],
)
}
}
}

Expand Down
Loading

0 comments on commit adbaf96

Please sign in to comment.