Skip to content

Commit

Permalink
build(blockifier): add get class hash at syscall
Browse files Browse the repository at this point in the history
  • Loading branch information
AvivYossef-starkware committed Nov 11, 2024
1 parent a8e48ad commit aff6aff
Show file tree
Hide file tree
Showing 18 changed files with 196 additions and 1 deletion.
9 changes: 9 additions & 0 deletions crates/blockifier/resources/versioned_constants_0_13_0.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@
"syscall_base_gas_cost": 1,
"step_gas_cost": 50
},
"get_class_hash_at_gas_cost": {
"step_gas_cost": 0,
"syscall_base_gas_cost": 0
},
"emit_event_gas_cost": {
"syscall_base_gas_cost": 1,
"step_gas_cost": 10
Expand Down Expand Up @@ -397,6 +401,11 @@
"builtin_instance_counter": {},
"n_memory_holes": 0,
"n_steps": 46
},
"GetClassHashAt": {
"n_steps": 0,
"builtin_instance_counter": {},
"n_memory_holes": 0
}
},
"execute_txs_inner": {
Expand Down
9 changes: 9 additions & 0 deletions crates/blockifier/resources/versioned_constants_0_13_1.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@
"syscall_base_gas_cost": 1,
"step_gas_cost": 50
},
"get_class_hash_at_gas_cost": {
"step_gas_cost": 0,
"syscall_base_gas_cost": 0
},
"emit_event_gas_cost": {
"syscall_base_gas_cost": 1,
"step_gas_cost": 10
Expand Down Expand Up @@ -421,6 +425,11 @@
"range_check_builtin": 1
},
"n_memory_holes": 0
},
"GetClassHashAt": {
"n_steps": 0,
"builtin_instance_counter": {},
"n_memory_holes": 0
}
},
"execute_txs_inner": {
Expand Down
9 changes: 9 additions & 0 deletions crates/blockifier/resources/versioned_constants_0_13_1_1.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@
"syscall_base_gas_cost": 1,
"step_gas_cost": 50
},
"get_class_hash_at_gas_cost": {
"step_gas_cost": 0,
"syscall_base_gas_cost": 0
},
"emit_event_gas_cost": {
"syscall_base_gas_cost": 1,
"step_gas_cost": 10
Expand Down Expand Up @@ -421,6 +425,11 @@
"range_check_builtin": 1
},
"n_memory_holes": 0
},
"GetClassHashAt": {
"n_steps": 0,
"builtin_instance_counter": {},
"n_memory_holes": 0
}
},
"execute_txs_inner": {
Expand Down
9 changes: 9 additions & 0 deletions crates/blockifier/resources/versioned_constants_0_13_2.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@
"step_gas_cost": 50,
"syscall_base_gas_cost": 1
},
"get_class_hash_at_gas_cost": {
"step_gas_cost": 0,
"syscall_base_gas_cost": 0
},
"stored_block_hash_buffer": 10,
"syscall_base_gas_cost": {
"step_gas_cost": 100
Expand Down Expand Up @@ -425,6 +429,11 @@
"range_check_builtin": 1
},
"n_memory_holes": 0
},
"GetClassHashAt": {
"n_steps": 0,
"builtin_instance_counter": {},
"n_memory_holes": 0
}
},
"execute_txs_inner": {
Expand Down
9 changes: 9 additions & 0 deletions crates/blockifier/resources/versioned_constants_0_13_2_1.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@
"step_gas_cost": 50,
"syscall_base_gas_cost": 1
},
"get_class_hash_at_gas_cost": {
"step_gas_cost": 0,
"syscall_base_gas_cost": 0
},
"stored_block_hash_buffer": 10,
"syscall_base_gas_cost": {
"step_gas_cost": 100
Expand Down Expand Up @@ -425,6 +429,11 @@
"range_check_builtin": 1
},
"n_memory_holes": 0
},
"GetClassHashAt": {
"n_steps": 0,
"builtin_instance_counter": {},
"n_memory_holes": 0
}
},
"execute_txs_inner": {
Expand Down
9 changes: 9 additions & 0 deletions crates/blockifier/resources/versioned_constants_0_13_3.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@
"step_gas_cost": 50,
"syscall_base_gas_cost": 1
},
"get_class_hash_at_gas_cost": {
"step_gas_cost": 0,
"syscall_base_gas_cost": 0
},
"stored_block_hash_buffer": 10,
"syscall_base_gas_cost": {
"step_gas_cost": 100
Expand Down Expand Up @@ -425,6 +429,11 @@
"range_check_builtin": 1
},
"n_memory_holes": 0
},
"GetClassHashAt": {
"n_steps": 0,
"builtin_instance_counter": {},
"n_memory_holes": 0
}
},
"execute_txs_inner": {
Expand Down
11 changes: 11 additions & 0 deletions crates/blockifier/resources/versioned_constants_0_13_4.json
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@
"step_gas_cost": 100,
"range_check_gas_cost": 1
},
"get_class_hash_at_gas_cost": {
"step_gas_cost": 100,
"range_check_gas_cost": 1
},
"stored_block_hash_buffer": 10,
"syscall_base_gas_cost": {
"step_gas_cost": 100
Expand Down Expand Up @@ -427,6 +431,13 @@
"range_check_builtin": 1
},
"n_memory_holes": 0
},
"GetClassHashAt": {
"n_steps": 100,
"builtin_instance_counter": {
"range_check_builtin": 1
},
"n_memory_holes": 0
}
},
"execute_txs_inner": {
Expand Down
4 changes: 3 additions & 1 deletion crates/blockifier/src/execution/call_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::ops::Add;

use cairo_vm::vm::runners::cairo_runner::ExecutionResources;
use serde::Serialize;
use starknet_api::core::{ClassHash, EthAddress};
use starknet_api::core::{ClassHash, ContractAddress, EthAddress};
use starknet_api::execution_resources::GasAmount;
use starknet_api::state::StorageKey;
use starknet_api::transaction::{EventContent, L2ToL1Payload};
Expand Down Expand Up @@ -126,6 +126,8 @@ pub struct CallInfo {
// Additional information gathered during execution.
pub storage_read_values: Vec<Felt>,
pub accessed_storage_keys: HashSet<StorageKey>,
pub read_class_hash_values: Vec<ClassHash>,
pub accessed_contract_addresses: HashSet<ContractAddress>,
}

impl CallInfo {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ pub fn finalize_execution(
),
storage_read_values: syscall_handler.read_values,
accessed_storage_keys: syscall_handler.accessed_keys,
..Default::default()
})
}

Expand Down
2 changes: 2 additions & 0 deletions crates/blockifier/src/execution/deprecated_syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ pub enum DeprecatedSyscallSelector {
GetBlockNumber,
GetBlockTimestamp,
GetCallerAddress,
GetClassHashAt,
GetContractAddress,
GetExecutionInfo,
GetSequencerAddress,
Expand Down Expand Up @@ -99,6 +100,7 @@ impl TryFrom<Felt> for DeprecatedSyscallSelector {
b"GetBlockNumber" => Ok(Self::GetBlockNumber),
b"GetBlockTimestamp" => Ok(Self::GetBlockTimestamp),
b"GetCallerAddress" => Ok(Self::GetCallerAddress),
b"GetClassHashAt" => Ok(Self::GetClassHashAt),
b"GetContractAddress" => Ok(Self::GetContractAddress),
b"GetExecutionInfo" => Ok(Self::GetExecutionInfo),
b"GetSequencerAddress" => Ok(Self::GetSequencerAddress),
Expand Down
2 changes: 2 additions & 0 deletions crates/blockifier/src/execution/entry_point_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,8 @@ pub fn finalize_execution(
charged_resources,
storage_read_values: syscall_handler.read_values,
accessed_storage_keys: syscall_handler.accessed_keys,
read_class_hash_values: syscall_handler.read_class_hash_values,
accessed_contract_addresses: syscall_handler.accessed_contract_addresses,
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub fn execute_entry_point_call(
create_callinfo(call_result, syscall_handler)
}

#[allow(unreachable_code)]
fn create_callinfo(
call_result: ContractExecutionResult,
syscall_handler: NativeSyscallHandler<'_>,
Expand Down Expand Up @@ -78,6 +79,11 @@ fn create_callinfo(
inner_calls: syscall_handler.inner_calls,
storage_read_values: syscall_handler.read_values,
accessed_storage_keys: syscall_handler.accessed_keys,
// TODO(Aviv): The syscall is not supported here yet.
// Currently, `accessed_contract_addresses` and `read_class_hash_values` are initialized
// as empty. Support for handling accessed storage keys via syscalls should be implemente
accessed_contract_addresses: todo!("Implement the syscall GetClassHashAt"),
read_class_hash_values: todo!("Implement the syscall GetClassHashAt"),
tracked_resource: TrackedResource::SierraGas,
})
}
11 changes: 11 additions & 0 deletions crates/blockifier/src/execution/syscalls/hint_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ use crate::execution::syscalls::{
deploy,
emit_event,
get_block_hash,
get_class_hash_at,
get_execution_info,
keccak,
library_call,
Expand Down Expand Up @@ -233,6 +234,9 @@ pub struct SyscallHintProcessor<'a> {
// Additional information gathered during execution.
pub read_values: Vec<Felt>,
pub accessed_keys: HashSet<StorageKey>,
pub read_class_hash_values: Vec<ClassHash>,
// Accessed addresses by the `get_class_hash_at` syscall.
pub accessed_contract_addresses: HashSet<ContractAddress>,

// The original storage value of the executed contract.
// Should be moved back `context.revert_info` before executing an inner call.
Expand Down Expand Up @@ -282,6 +286,8 @@ impl<'a> SyscallHintProcessor<'a> {
syscall_ptr: initial_syscall_ptr,
read_values: vec![],
accessed_keys: HashSet::new(),
read_class_hash_values: vec![],
accessed_contract_addresses: HashSet::new(),
original_values,
hints,
execution_info_ptr: None,
Expand Down Expand Up @@ -338,6 +344,11 @@ impl<'a> SyscallHintProcessor<'a> {
call_contract,
self.context.gas_costs().call_contract_gas_cost,
),
SyscallSelector::GetClassHashAt => self.execute_syscall(
vm,
get_class_hash_at,
self.context.gas_costs().get_class_hash_at_gas_cost,
),
SyscallSelector::Deploy => {
self.execute_syscall(vm, deploy, self.context.gas_costs().deploy_gas_cost)
}
Expand Down
31 changes: 31 additions & 0 deletions crates/blockifier/src/execution/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -786,3 +786,34 @@ pub fn sha_256_process_block(

Ok(Sha256ProcessBlockResponse { state_ptr: response })
}

// GetClassHashAt syscall.

pub(crate) type GetClassHashAtRequest = ContractAddress;
pub(crate) type GetClassHashAtResponse = ClassHash;

impl SyscallRequest for GetClassHashAtRequest {
fn read(vm: &VirtualMachine, ptr: &mut Relocatable) -> SyscallResult<GetClassHashAtRequest> {
let address = ContractAddress::try_from(felt_from_ptr(vm, ptr)?)?;
Ok(address)
}
}

impl SyscallResponse for GetClassHashAtResponse {
fn write(self, vm: &mut VirtualMachine, ptr: &mut Relocatable) -> WriteResponseResult {
write_felt(vm, ptr, *self)?;
Ok(())
}
}

pub(crate) fn get_class_hash_at(
request: GetClassHashAtRequest,
_vm: &mut VirtualMachine,
syscall_handler: &mut SyscallHintProcessor<'_>,
_remaining_gas: &mut u64,
) -> SyscallResult<GetClassHashAtResponse> {
syscall_handler.accessed_contract_addresses.insert(request);
let class_hash = syscall_handler.state.get_class_hash_at(request)?;
syscall_handler.read_class_hash_values.push(class_hash);
Ok(class_hash)
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub const REQUIRED_GAS_CALL_CONTRACT_TEST: u64 = 170370;
pub const REQUIRED_GAS_STORAGE_READ_WRITE_TEST: u64 = 16990;
pub const REQUIRED_GAS_GET_CLASS_HASH_AT_TEST: u64 = 7830;
pub const REQUIRED_GAS_LIBRARY_CALL_TEST: u64 = 167970;
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use starknet_api::{calldata, class_hash, contract_address};
use test_case::test_case;

use crate::abi::abi_utils::selector_from_name;
use crate::context::ChainInfo;
use crate::execution::call_info::CallExecution;
use crate::execution::entry_point::CallEntryPoint;
use crate::execution::syscalls::syscall_tests::constants::REQUIRED_GAS_GET_CLASS_HASH_AT_TEST;
use crate::retdata;
use crate::test_utils::contracts::FeatureContract;
use crate::test_utils::initial_test_state::test_state;
use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE};

/// Tests the `get_class_hash_at` syscall, ensuring that:
/// 1. `accessed_contract_addresses` contains `address` for a valid entry.
/// 2. `read_class_hash_values` includes `class_hash`.
/// 3. Execution succeeds with expected gas for valid cases.
/// 4. Execution fails if `address` has a different `class_hash`.
/// 5. Execution succeeds and returns `class_hash` = 0 if `address` is absent.
#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), REQUIRED_GAS_GET_CLASS_HASH_AT_TEST; "VM")]
fn test_get_class_hash_at(test_contract: FeatureContract, expected_gas: u64) {
let chain_info = &ChainInfo::create_for_testing();
let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]);
let address = contract_address!("0x111");
let class_hash = class_hash!("0x222");
state.state.address_to_class_hash.insert(address, class_hash);

// Positive case: address and class_hash are correct
let positive_entry_point_call = CallEntryPoint {
calldata: calldata![address.into(), class_hash.0],
entry_point_selector: selector_from_name("test_get_class_hash_at"),
..trivial_external_entry_point_new(test_contract)
};
let positive_call_info = positive_entry_point_call.execute_directly(&mut state).unwrap();
assert!(positive_call_info.accessed_contract_addresses.contains(&address));
assert!(positive_call_info.read_class_hash_values[0] == class_hash);
assert_eq!(
positive_call_info.execution,
CallExecution {
retdata: retdata!(),
gas_consumed: expected_gas,
failed: false,
..CallExecution::default()
}
);

// Negative case 1: Non-existing address should return class_hash = 0 and succeed.
let non_existing_address = contract_address!("0x333");
let class_hash_of_undeployed_contract = class_hash!("0x0");

let negative_entry_point_call = CallEntryPoint {
calldata: calldata![non_existing_address.into(), class_hash_of_undeployed_contract.0],
entry_point_selector: selector_from_name("test_get_class_hash_at"),
..trivial_external_entry_point_new(test_contract)
};
assert!(!negative_entry_point_call.execute_directly(&mut state).unwrap().execution.failed);

// Negative case 2: Existing address but mismatched class_hash should fail.
let different_class_hash = class_hash!("0x444");
let different_class_hash_entry_point_call = CallEntryPoint {
calldata: calldata![address.into(), different_class_hash.0],
entry_point_selector: selector_from_name("test_get_class_hash_at"),
..trivial_external_entry_point_new(test_contract)
};
assert!(
different_class_hash_entry_point_call
.execute_directly(&mut state)
.unwrap()
.execution
.failed
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod deploy;
mod emit_event;
mod failure_format;
mod get_block_hash;
mod get_class_hash_at;
mod get_execution_info;
mod keccak;
mod library_call;
Expand Down
Loading

0 comments on commit aff6aff

Please sign in to comment.