Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions crates/apollo_infra_utils/src/cairo0_compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod test;

pub const STARKNET_COMPILE_DEPRECATED: &str = "starknet-compile-deprecated";
pub const CAIRO0_COMPILE: &str = "cairo-compile";
pub const CAIRO0_FORMAT: &str = "cairo-format";
pub const EXPECTED_CAIRO0_VERSION: &str = "0.14.0a1";

/// The local python requirements used to determine the cairo0 compiler version.
Expand All @@ -27,12 +28,12 @@ pip install -r {:#?}"#,
});

#[derive(thiserror::Error, Debug)]
pub enum Cairo0CompilerVersionError {
pub enum Cairo0ScriptVersionError {
#[error(
"{compiler} version is not correct: required {required}, got {existing}. Are you in the \
"{script} version is not correct: required {required}, got {existing}. Are you in the \
venv? If not, run the following commands:\n{}", *ENTER_VENV_INSTRUCTIONS
)]
IncorrectVersion { compiler: String, existing: String, required: String },
IncorrectVersion { script: String, existing: String, required: String },
#[error(
"{0}. Are you in the venv? If not, run the following commands:\n{}",
*ENTER_VENV_INSTRUCTIONS
Expand All @@ -43,7 +44,7 @@ pub enum Cairo0CompilerVersionError {
#[derive(thiserror::Error, Debug)]
pub enum Cairo0CompilerError {
#[error(transparent)]
Cairo0CompilerVersion(#[from] Cairo0CompilerVersionError),
Cairo0CompilerVersion(#[from] Cairo0ScriptVersionError),
#[error("Cairo root path not found at {0:?}.")]
CairoRootNotFound(PathBuf),
#[error("Failed to compile the program. Error: {0}.")]
Expand All @@ -56,22 +57,22 @@ pub enum Cairo0CompilerError {
SourceFileNotFound(PathBuf),
}

pub fn cairo0_compilers_correct_version() -> Result<(), Cairo0CompilerVersionError> {
for compiler in [CAIRO0_COMPILE, STARKNET_COMPILE_DEPRECATED] {
let version = match Command::new(compiler).arg("--version").output() {
pub fn cairo0_scripts_correct_version() -> Result<(), Cairo0ScriptVersionError> {
for script in [CAIRO0_COMPILE, CAIRO0_FORMAT, STARKNET_COMPILE_DEPRECATED] {
let version = match Command::new(script).arg("--version").output() {
Ok(output) => String::from_utf8_lossy(&output.stdout).to_string(),
Err(error) => {
return Err(Cairo0CompilerVersionError::CompilerNotFound(format!(
"Failed to get {compiler} version: {error}."
return Err(Cairo0ScriptVersionError::CompilerNotFound(format!(
"Failed to get {script} version: {error}."
)));
}
};
if version.trim().replace("==", " ").split(" ").nth(1).ok_or(
Cairo0CompilerVersionError::CompilerNotFound("No compiler version found.".to_string()),
Cairo0ScriptVersionError::CompilerNotFound("No script version found.".to_string()),
)? != EXPECTED_CAIRO0_VERSION
{
return Err(Cairo0CompilerVersionError::IncorrectVersion {
compiler: compiler.to_string(),
return Err(Cairo0ScriptVersionError::IncorrectVersion {
script: script.to_string(),
existing: version,
required: EXPECTED_CAIRO0_VERSION.to_string(),
});
Expand All @@ -86,7 +87,7 @@ pub fn compile_cairo0_program(
path_to_main: PathBuf,
cairo_root_path: PathBuf,
) -> Result<Vec<u8>, Cairo0CompilerError> {
cairo0_compilers_correct_version()?;
cairo0_scripts_correct_version()?;
if !path_to_main.exists() {
return Err(Cairo0CompilerError::SourceFileNotFound(path_to_main));
}
Expand Down Expand Up @@ -116,17 +117,17 @@ pub fn compile_cairo0_program(

/// Verifies that the required Cairo0 compiler is available; panics if unavailable.
/// For use in tests only. If cairo0 compiler verification is required in business logic, use
/// `crate::cairo0_compiler::cairo0_compilers_correct_version` instead.
/// `crate::cairo0_compiler::cairo0_scripts_correct_version` instead.
#[cfg(any(test, feature = "testing"))]
pub fn verify_cairo0_compiler_deps() {
let specific_error = match cairo0_compilers_correct_version() {
let specific_error = match cairo0_scripts_correct_version() {
Ok(_) => {
return;
}
Err(Cairo0CompilerVersionError::CompilerNotFound(_)) => {
Err(Cairo0ScriptVersionError::CompilerNotFound(_)) => {
"no installed cairo-lang found".to_string()
}
Err(Cairo0CompilerVersionError::IncorrectVersion { existing, .. }) => {
Err(Cairo0ScriptVersionError::IncorrectVersion { existing, .. }) => {
format!("installed version: {existing}")
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// Autogenerated file.

// Transaction hash prefixes.
const DECLARE_HASH_PREFIX = 'declare';
const DEPLOY_HASH_PREFIX = 'deploy';
const DEPLOY_ACCOUNT_HASH_PREFIX = 'deploy_account';
const INVOKE_HASH_PREFIX = 'invoke';
const L1_HANDLER_HASH_PREFIX = 'l1_handler';

// An entry point offset that indicates that nothing needs to be done.
// Used to implement an empty constructor.
const NOP_ENTRY_POINT_OFFSET = {NOP_ENTRY_POINT_OFFSET};

const ENTRY_POINT_TYPE_EXTERNAL = {ENTRY_POINT_TYPE_EXTERNAL};
const ENTRY_POINT_TYPE_L1_HANDLER = {ENTRY_POINT_TYPE_L1_HANDLER};
const ENTRY_POINT_TYPE_CONSTRUCTOR = {ENTRY_POINT_TYPE_CONSTRUCTOR};

const L1_HANDLER_VERSION = {L1_HANDLER_VERSION};
const L1_HANDLER_L2_GAS_MAX_AMOUNT = {L1_HANDLER_L2_GAS_MAX_AMOUNT};

// Upper bound on the number of elements in a Sierra array.
const SIERRA_ARRAY_LEN_BOUND = {SIERRA_ARRAY_LEN_BOUND}; // 2^32

// get_selector_from_name('constructor').
const CONSTRUCTOR_ENTRY_POINT_SELECTOR = ({CONSTRUCTOR_ENTRY_POINT_SELECTOR});

// get_selector_from_name('__execute__').
const EXECUTE_ENTRY_POINT_SELECTOR = ({EXECUTE_ENTRY_POINT_SELECTOR});

// get_selector_from_name('__validate__').
const VALIDATE_ENTRY_POINT_SELECTOR = ({VALIDATE_ENTRY_POINT_SELECTOR});

// get_selector_from_name('__validate_declare__').
const VALIDATE_DECLARE_ENTRY_POINT_SELECTOR = ({VALIDATE_DECLARE_ENTRY_POINT_SELECTOR});

// get_selector_from_name('__validate_deploy__').
const VALIDATE_DEPLOY_ENTRY_POINT_SELECTOR = ({VALIDATE_DEPLOY_ENTRY_POINT_SELECTOR});

// get_selector_from_name('transfer').
const TRANSFER_ENTRY_POINT_SELECTOR = ({TRANSFER_ENTRY_POINT_SELECTOR});

const DEFAULT_ENTRY_POINT_SELECTOR = {DEFAULT_ENTRY_POINT_SELECTOR};

// OS reserved contract addresses.

// This contract stores the block number -> block hash mapping.
const BLOCK_HASH_CONTRACT_ADDRESS = {BLOCK_HASH_CONTRACT_ADDRESS};
// This contract stores the aliases mapping used for stateful compression.
const ALIAS_CONTRACT_ADDRESS = {ALIAS_CONTRACT_ADDRESS};
// Future reserved contract address.
const RESERVED_CONTRACT_ADDRESS = {RESERVED_CONTRACT_ADDRESS};
// The block number -> block hash mapping is written for the current block number minus this number.
const STORED_BLOCK_HASH_BUFFER = {STORED_BLOCK_HASH_BUFFER};

// Gas constants.

const STEP_GAS_COST = {STEP_GAS_COST};
const RANGE_CHECK_GAS_COST = {RANGE_CHECK_GAS_COST};
const RANGE_CHECK96_GAS_COST = {RANGE_CHECK96_GAS_COST};
const KECCAK_BUILTIN_GAS_COST = {KECCAK_BUILTIN_GAS_COST};
const PEDERSEN_GAS_COST = {PEDERSEN_GAS_COST};
const BITWISE_BUILTIN_GAS_COST = {BITWISE_BUILTIN_GAS_COST};
const ECOP_GAS_COST = {ECOP_GAS_COST};
const POSEIDON_GAS_COST = {POSEIDON_GAS_COST};
const ADD_MOD_GAS_COST = {ADD_MOD_GAS_COST};
const MUL_MOD_GAS_COST = {MUL_MOD_GAS_COST};
const ECDSA_GAS_COST = {ECDSA_GAS_COST};
const MEMORY_HOLE_GAS_COST = {MEMORY_HOLE_GAS_COST};

const DEFAULT_INITIAL_GAS_COST = {DEFAULT_INITIAL_GAS_COST};
const VALIDATE_MAX_SIERRA_GAS = {VALIDATE_MAX_SIERRA_GAS};
const EXECUTE_MAX_SIERRA_GAS = {EXECUTE_MAX_SIERRA_GAS};
const DEFAULT_INITIAL_GAS_COST_NO_L2 = VALIDATE_MAX_SIERRA_GAS + EXECUTE_MAX_SIERRA_GAS;

// Compiler gas costs.

// The initial budget at an entry point. This needs to be high enough to cover the initial get_gas.
// The entry point may refund whatever remains from the initial budget.
const ENTRY_POINT_INITIAL_BUDGET = {ENTRY_POINT_INITIAL_BUDGET};
// The gas cost of each syscall libfunc (this value is hard-coded by the compiler).
// This needs to be high enough to cover OS costs in the case of failure due to out of gas.
const SYSCALL_BASE_GAS_COST = {SYSCALL_BASE_GAS_COST};

// Syscall gas costs.
const CALL_CONTRACT_GAS_COST = {CALL_CONTRACT_GAS_COST};
const DEPLOY_GAS_COST = {DEPLOY_GAS_COST};
const DEPLOY_CALLDATA_FACTOR_GAS_COST = {DEPLOY_CALLDATA_FACTOR_GAS_COST};
const GET_BLOCK_HASH_GAS_COST = {GET_BLOCK_HASH_GAS_COST};
const GET_CLASS_HASH_AT_GAS_COST = {GET_CLASS_HASH_AT_GAS_COST};
const GET_EXECUTION_INFO_GAS_COST = {GET_EXECUTION_INFO_GAS_COST};
const LIBRARY_CALL_GAS_COST = {LIBRARY_CALL_GAS_COST};
const REPLACE_CLASS_GAS_COST = {REPLACE_CLASS_GAS_COST};
// TODO(Yoni, 1/1/2026): take into account Patricia updates and dict squash.
const STORAGE_READ_GAS_COST = {STORAGE_READ_GAS_COST};
const STORAGE_WRITE_GAS_COST = {STORAGE_WRITE_GAS_COST};
const EMIT_EVENT_GAS_COST = {EMIT_EVENT_GAS_COST};
const SEND_MESSAGE_TO_L1_GAS_COST = {SEND_MESSAGE_TO_L1_GAS_COST};
const META_TX_V0_GAS_COST = {META_TX_V0_GAS_COST};
const META_TX_V0_CALLDATA_FACTOR_GAS_COST = {META_TX_V0_CALLDATA_FACTOR_GAS_COST};

// Note the the following costs include `SYSCALL_BASE_GAS_COST` implicitly.
const SECP256K1_ADD_GAS_COST = {SECP256K1_ADD_GAS_COST};
const SECP256K1_GET_POINT_FROM_X_GAS_COST = {SECP256K1_GET_POINT_FROM_X_GAS_COST};
const SECP256K1_GET_XY_GAS_COST = {SECP256K1_GET_XY_GAS_COST};
const SECP256K1_MUL_GAS_COST = {SECP256K1_MUL_GAS_COST};
const SECP256K1_NEW_GAS_COST = {SECP256K1_NEW_GAS_COST};
const SECP256R1_ADD_GAS_COST = {SECP256R1_ADD_GAS_COST};
const SECP256R1_GET_POINT_FROM_X_GAS_COST = {SECP256R1_GET_POINT_FROM_X_GAS_COST};
const SECP256R1_GET_XY_GAS_COST = {SECP256R1_GET_XY_GAS_COST};
const SECP256R1_MUL_GAS_COST = {SECP256R1_MUL_GAS_COST};
const SECP256R1_NEW_GAS_COST = {SECP256R1_NEW_GAS_COST};

const KECCAK_GAS_COST = {KECCAK_GAS_COST};
const KECCAK_ROUND_COST_GAS_COST = {KECCAK_ROUND_COST_GAS_COST};
const SHA256_PROCESS_BLOCK_GAS_COST = {SHA256_PROCESS_BLOCK_GAS_COST};

// Cairo 1.0 error codes.
const ERROR_BLOCK_NUMBER_OUT_OF_RANGE = {ERROR_BLOCK_NUMBER_OUT_OF_RANGE};
const ERROR_OUT_OF_GAS = {ERROR_OUT_OF_GAS};
const ERROR_ENTRY_POINT_FAILED = {ERROR_ENTRY_POINT_FAILED};
const ERROR_ENTRY_POINT_NOT_FOUND = {ERROR_ENTRY_POINT_NOT_FOUND};
const ERROR_INVALID_INPUT_LEN = {ERROR_INVALID_INPUT_LEN};
const ERROR_INVALID_ARGUMENT = {ERROR_INVALID_ARGUMENT};

// The expected return value of the `__validate*__` functions of a Cairo 1.0 account contract.
const VALIDATED = {VALIDATED};

// Resources
const L1_GAS = {L1_GAS};
const L2_GAS = {L2_GAS};
const L1_DATA_GAS = {L1_DATA_GAS};
const L1_GAS_INDEX = {L1_GAS_INDEX};
const L2_GAS_INDEX = {L2_GAS_INDEX};
const L1_DATA_GAS_INDEX = {L1_DATA_GAS_INDEX};

// Round down the block number and timestamp when queried inside `__validate__`.
const VALIDATE_BLOCK_NUMBER_ROUNDING = {VALIDATE_BLOCK_NUMBER_ROUNDING};
const VALIDATE_TIMESTAMP_ROUNDING = {VALIDATE_TIMESTAMP_ROUNDING};

// List of CairoZero account contracts that require the transaction version to be 1.
{V1_BOUND_ACCOUNTS_CAIRO0}

// List of Cairo1 account contracts that require the transaction version to be 1.
{V1_BOUND_ACCOUNTS_CAIRO1}

// Max transaction tip for which a v3 transaction can be replaced with a v1 transaction.
const V1_BOUND_ACCOUNTS_MAX_TIP = {V1_BOUND_ACCOUNTS_MAX_TIP};

// List of Cairo1 account contracts that require the resource bounds to exclude data gas.
{DATA_GAS_ACCOUNTS}
114 changes: 107 additions & 7 deletions crates/blockifier/src/blockifier_versioned_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,10 @@ impl SyscallGasCost {
assert!(self.linear_factor == 0, "The syscall has a linear factor cost to be considered.");
self.base
}

pub fn linear_syscall_cost(&self) -> u64 {
self.linear_factor
}
}

#[cfg_attr(any(test, feature = "testing"), derive(Clone))]
Expand Down Expand Up @@ -1072,29 +1076,125 @@ impl GasCosts {
#[derive(Debug, Default, PartialEq)]
pub struct OsConstants {
pub gas_costs: GasCosts,
pub validate_rounding_consts: ValidateRoundingConsts,
pub os_contract_addresses: OsContractAddresses,

// Selectors.
pub constructor_entry_point_selector: EntryPointSelector,
pub default_entry_point_selector: EntryPointSelector,
pub execute_entry_point_selector: EntryPointSelector,
pub transfer_entry_point_selector: EntryPointSelector,
pub validate_declare_entry_point_selector: EntryPointSelector,
pub validate_deploy_entry_point_selector: EntryPointSelector,
pub validate_entry_point_selector: EntryPointSelector,

// Execution limits.
pub validate_max_sierra_gas: GasAmount,
pub execute_max_sierra_gas: GasAmount,

// Validation.
pub validate_rounding_consts: ValidateRoundingConsts,
pub validated: String,

// Error strings.
pub error_block_number_out_of_range: String,
pub error_invalid_input_len: String,
pub error_invalid_argument: String,
pub error_out_of_gas: String,
pub error_entry_point_failed: String,
pub error_entry_point_not_found: String,

// Resource bounds names.
pub l1_gas: String,
pub l2_gas: String,
pub l1_data_gas: String,

// Resource bounds indices.
pub l1_gas_index: usize,
pub l1_data_gas_index: usize,
pub l2_gas_index: usize,

// Initial costs.
pub entry_point_initial_budget: GasAmount,
pub default_initial_gas_cost: GasAmount,

// L1 handler.
pub l1_handler_version: u8,
pub l1_handler_max_amount_bounds: GasVector,

// Miscellaneous.
pub nop_entry_point_offset: i8,
pub os_contract_addresses: OsContractAddresses,
pub sierra_array_len_bound: u64,
pub stored_block_hash_buffer: u8,

// Entry point type identifiers (in the OS).
pub entry_point_type_constructor: u8,
pub entry_point_type_external: u8,
pub entry_point_type_l1_handler: u8,

// Deprecated contract logic support.
pub v1_bound_accounts_cairo0: Vec<ClassHash>,
pub v1_bound_accounts_cairo1: Vec<ClassHash>,
pub v1_bound_accounts_max_tip: Tip,
pub l1_handler_max_amount_bounds: GasVector,
pub data_gas_accounts: Vec<ClassHash>,
}

impl OsConstants {
fn from_raw(raw_constants: &RawOsConstants, raw_resources: &RawOsResources) -> Self {
let gas_costs = GasCosts::from_raw(raw_constants, raw_resources);

// Preprocess inital budget costs.
let RawStepGasCost { step_gas_cost: entry_point_initial_budget_steps } =
raw_constants.entry_point_initial_budget;
let RawStepGasCost { step_gas_cost: default_initial_gas_cost_steps } =
raw_constants.default_initial_gas_cost;
let entry_point_initial_budget = entry_point_initial_budget_steps
.checked_factor_mul(gas_costs.base.step_gas_cost)
.expect("The entry point initial budget - in gas - should not overflow.");
let default_initial_gas_cost = default_initial_gas_cost_steps
.checked_factor_mul(gas_costs.base.step_gas_cost)
.expect("The default initial gas should not overflow.");

Self {
gas_costs: GasCosts::from_raw(raw_constants, raw_resources),
validate_rounding_consts: raw_constants.validate_rounding_consts,
os_contract_addresses: raw_constants.os_contract_addresses,
gas_costs,
constructor_entry_point_selector: raw_constants.constructor_entry_point_selector,
default_entry_point_selector: raw_constants.default_entry_point_selector,
execute_entry_point_selector: raw_constants.execute_entry_point_selector,
transfer_entry_point_selector: raw_constants.transfer_entry_point_selector,
validate_declare_entry_point_selector: raw_constants
.validate_declare_entry_point_selector,
validate_deploy_entry_point_selector: raw_constants
.validate_deploy_entry_point_selector,
validate_entry_point_selector: raw_constants.validate_entry_point_selector,
validate_max_sierra_gas: raw_constants.validate_max_sierra_gas,
execute_max_sierra_gas: raw_constants.execute_max_sierra_gas,
validate_rounding_consts: raw_constants.validate_rounding_consts,
validated: raw_constants.validated.clone(),
error_block_number_out_of_range: raw_constants.error_block_number_out_of_range.clone(),
error_invalid_input_len: raw_constants.error_invalid_input_len.clone(),
error_invalid_argument: raw_constants.error_invalid_argument.clone(),
error_out_of_gas: raw_constants.error_out_of_gas.clone(),
error_entry_point_failed: raw_constants.error_entry_point_failed.clone(),
error_entry_point_not_found: raw_constants.error_entry_point_not_found.clone(),
l1_gas: raw_constants.l1_gas.clone(),
l2_gas: raw_constants.l2_gas.clone(),
l1_data_gas: raw_constants.l1_data_gas.clone(),
l1_gas_index: raw_constants.l1_gas_index,
l1_data_gas_index: raw_constants.l1_data_gas_index,
l2_gas_index: raw_constants.l2_gas_index,
entry_point_initial_budget,
default_initial_gas_cost,
l1_handler_version: raw_constants.l1_handler_version,
l1_handler_max_amount_bounds: raw_constants.l1_handler_max_amount_bounds,
nop_entry_point_offset: raw_constants.nop_entry_point_offset,
os_contract_addresses: raw_constants.os_contract_addresses,
sierra_array_len_bound: raw_constants.sierra_array_len_bound,
stored_block_hash_buffer: raw_constants.stored_block_hash_buffer,
entry_point_type_constructor: raw_constants.entry_point_type_constructor,
entry_point_type_external: raw_constants.entry_point_type_external,
entry_point_type_l1_handler: raw_constants.entry_point_type_l1_handler,
v1_bound_accounts_cairo0: raw_constants.v1_bound_accounts_cairo0.clone(),
v1_bound_accounts_cairo1: raw_constants.v1_bound_accounts_cairo1.clone(),
v1_bound_accounts_max_tip: raw_constants.v1_bound_accounts_max_tip,
l1_handler_max_amount_bounds: raw_constants.l1_handler_max_amount_bounds,
data_gas_accounts: raw_constants.data_gas_accounts.clone(),
}
}
Expand Down
Loading