Skip to content

Commit

Permalink
feat(blockifier): add get_block_hash cairo native syscall
Browse files Browse the repository at this point in the history
  • Loading branch information
PearsonWhite authored and rodrigo-pino committed Nov 12, 2024
1 parent 686003c commit 08bcb32
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 10 deletions.
45 changes: 41 additions & 4 deletions crates/blockifier/src/execution/native/syscall_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ use cairo_native::starknet::{
U256,
};
use cairo_vm::vm::runners::cairo_runner::ExecutionResources;
use starknet_api::core::ContractAddress;
use starknet_api::state::StorageKey;
use starknet_types_core::felt::Felt;

use crate::abi::constants;
use crate::execution::call_info::{CallInfo, OrderedEvent, OrderedL2ToL1Message, Retdata};
use crate::execution::common_hints::ExecutionMode;
use crate::execution::entry_point::{CallEntryPoint, EntryPointExecutionContext};
use crate::execution::syscalls::hint_processor::{
SyscallCounter,
SyscallExecutionError,
BLOCK_NUMBER_OUT_OF_RANGE_ERROR,
OUT_OF_GAS_ERROR,
};
use crate::execution::syscalls::SyscallSelector;
Expand Down Expand Up @@ -60,8 +64,8 @@ impl<'state> NativeSyscallHandler<'state> {
context,
events: Vec::new(),
l2_to_l1_messages: Vec::new(),
inner_calls: Vec::new(),
syscall_counter: SyscallCounter::new(),
inner_calls: Vec::new(),
read_values: Vec::new(),
accessed_keys: HashSet::new(),
unrecoverable_error: None,
Expand Down Expand Up @@ -159,10 +163,43 @@ impl<'state> NativeSyscallHandler<'state> {
impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> {
fn get_block_hash(
&mut self,
_block_number: u64,
_remaining_gas: &mut u128,
block_number: u64,
remaining_gas: &mut u128,
) -> SyscallResult<Felt> {
todo!("Implement get_block_hash syscall.");
self.pre_execute_syscall(
remaining_gas,
SyscallSelector::GetBlockHash,
self.context.gas_costs().get_block_hash_gas_cost,
)?;

if self.context.execution_mode == ExecutionMode::Validate {
let err = SyscallExecutionError::InvalidSyscallInExecutionMode {
syscall_name: "get_block_hash".to_string(),
execution_mode: ExecutionMode::Validate,
};
return Err(self.handle_error(remaining_gas, err));
}

let current_block_number =
self.context.tx_context.block_context.block_info().block_number.0;
if current_block_number < constants::STORED_BLOCK_HASH_BUFFER
|| block_number > current_block_number - constants::STORED_BLOCK_HASH_BUFFER
{
let out_of_range_felt = Felt::from_hex(BLOCK_NUMBER_OUT_OF_RANGE_ERROR).unwrap();
let error = SyscallExecutionError::SyscallError { error_data: vec![out_of_range_felt] };
return Err(self.handle_error(remaining_gas, error));
}

let key = StorageKey::try_from(Felt::from(block_number))
.map_err(|e| self.handle_error(remaining_gas, e.into()))?;
let block_hash_contract_address =
ContractAddress::try_from(Felt::from(constants::BLOCK_HASH_CONTRACT_ADDRESS))
.map_err(|e| self.handle_error(remaining_gas, e.into()))?;

match self.state.get_storage_at(block_hash_contract_address, key) {
Ok(value) => Ok(value),
Err(e) => Err(self.handle_error(remaining_gas, e.into())),
}
}

fn get_execution_info(&mut self, _remaining_gas: &mut u128) -> SyscallResult<ExecutionInfo> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ fn initialize_state(test_contract: FeatureContract) -> (CachedState<DictStateRea
(state, block_number, block_hash)
}

#[cfg_attr(
feature = "cairo_native",
test_case(FeatureContract::TestContract(CairoVersion::Native), 15220; "Native")
)]
#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 5220; "VM")]
fn positive_flow(test_contract: FeatureContract, expected_gas: u64) {
let (mut state, block_number, block_hash) = initialize_state(test_contract);
Expand All @@ -60,6 +64,10 @@ fn positive_flow(test_contract: FeatureContract, expected_gas: u64) {
);
}

#[cfg_attr(
feature = "cairo_native",
test_case(FeatureContract::TestContract(CairoVersion::Native); "Native")
)]
#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")]
fn negative_flow_execution_mode_validate(test_contract: FeatureContract) {
let (mut state, block_number, _) = initialize_state(test_contract);
Expand All @@ -72,13 +80,30 @@ fn negative_flow_execution_mode_validate(test_contract: FeatureContract) {
};

let error = entry_point_call.execute_directly_in_validate_mode(&mut state).unwrap_err();

#[cfg(feature = "cairo_native")]
if matches!(test_contract, FeatureContract::TestContract(CairoVersion::Native)) {
assert!(
error
.to_string()
.contains("Unauthorized syscall get_block_hash in execution mode Validate.")
);
} else {
check_entry_point_execution_error_for_custom_hint!(
&error,
"Unauthorized syscall get_block_hash in execution mode Validate.",
);
}
#[cfg(not(feature = "cairo_native"))]
check_entry_point_execution_error_for_custom_hint!(
&error,
"Unauthorized syscall get_block_hash in execution mode Validate.",
);
}

#[cfg_attr(
feature = "cairo_native",
test_case(FeatureContract::TestContract(CairoVersion::Native); "Native")
)]
#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")]
fn negative_flow_block_number_out_of_range(test_contract: FeatureContract) {
let (mut state, _, _) = initialize_state(test_contract);
Expand All @@ -92,10 +117,11 @@ fn negative_flow_block_number_out_of_range(test_contract: FeatureContract) {
..trivial_external_entry_point_new(test_contract)
};

let call_info = entry_point_call.execute_directly(&mut state).unwrap();
assert!(call_info.execution.failed);
assert_eq!(
format_panic_data(&call_info.execution.retdata.0),
"0x426c6f636b206e756d626572206f7574206f662072616e6765 ('Block number out of range')"
let call_result = entry_point_call.execute_directly(&mut state);
let (actual_error_msg, expected_error_msg) = (
format_panic_data(&call_result.unwrap().execution.retdata.0),
"0x426c6f636b206e756d626572206f7574206f662072616e6765 ('Block number out of range')",
);

assert_eq!(actual_error_msg, expected_error_msg);
}

0 comments on commit 08bcb32

Please sign in to comment.