From 4298e6488c576822b724821b6664f4df457b5928 Mon Sep 17 00:00:00 2001 From: Pedro Rosalba Date: Wed, 6 Nov 2024 19:20:48 -0300 Subject: [PATCH 01/17] cheatcode block_hash --- .../contracts/cheat_block_hash_checker.cairo | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 crates/forge/tests/data/contracts/cheat_block_hash_checker.cairo diff --git a/crates/forge/tests/data/contracts/cheat_block_hash_checker.cairo b/crates/forge/tests/data/contracts/cheat_block_hash_checker.cairo new file mode 100644 index 0000000000..893a9b4235 --- /dev/null +++ b/crates/forge/tests/data/contracts/cheat_block_hash_checker.cairo @@ -0,0 +1,53 @@ +#[starknet::interface] +trait ICheatBlockTimestampChecker { + fn get_block_hash(ref self: TContractState) -> felt252; + fn get_block_hash_and_emit_event(ref self: TContractState) -> felt252; + fn get_block_hash_and_number(ref self: TContractState) -> (felt252, u64); +} + +#[starknet::contract] +mod CheatBlockHashChecker { + use box::BoxTrait; + use core::starknet::SyscallResultTrait; + use starknet::{get_block_info, get_block_hash_syscall}; + + #[storage] + struct Storage {} + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + BlockHashEmitted: BlockHashEmitted + } + + #[derive(Drop, starknet::Event)] + struct BlockHashEmitted { + block_hash: felt252 + } + + + #[abi(embed_v0)] + impl CheatBlockHashChecker of super::ICheatBlockHashChecker { + fn get_block_hash(ref self: ContractState) -> felt252 { + let block_info = get_block_info().unbox(); + let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + + block_hash + } + + fn get_block_timestamp_and_emit_event(ref self: ContractState) -> u64 { + let block_info = get_block_info().unbox(); + let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + + self.emit(Event::BlockHashEmitted(BlockHashEmitted { block_hash })); + block_hash + } + + fn get_block_timestamp_and_number(ref self: ContractState) -> (u64, u64) { + let block_info = starknet::get_block_info().unbox(); + let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + + (block_info.block_hash, block_info.block_number) + } + } +} From 7243cfdd2779c1f681cb49eb767993dbf25d2018 Mon Sep 17 00:00:00 2001 From: Pedro Rosalba Date: Wed, 6 Nov 2024 19:21:53 -0300 Subject: [PATCH 02/17] fix: names --- .../tests/data/contracts/cheat_block_hash_checker.cairo | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/forge/tests/data/contracts/cheat_block_hash_checker.cairo b/crates/forge/tests/data/contracts/cheat_block_hash_checker.cairo index 893a9b4235..97697d1b7f 100644 --- a/crates/forge/tests/data/contracts/cheat_block_hash_checker.cairo +++ b/crates/forge/tests/data/contracts/cheat_block_hash_checker.cairo @@ -1,5 +1,5 @@ #[starknet::interface] -trait ICheatBlockTimestampChecker { +trait ICheatBlockHashChecker { fn get_block_hash(ref self: TContractState) -> felt252; fn get_block_hash_and_emit_event(ref self: TContractState) -> felt252; fn get_block_hash_and_number(ref self: TContractState) -> (felt252, u64); @@ -35,7 +35,7 @@ mod CheatBlockHashChecker { block_hash } - fn get_block_timestamp_and_emit_event(ref self: ContractState) -> u64 { + fn get_block_hash_and_emit_event(ref self: ContractState) -> u64 { let block_info = get_block_info().unbox(); let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); @@ -43,7 +43,7 @@ mod CheatBlockHashChecker { block_hash } - fn get_block_timestamp_and_number(ref self: ContractState) -> (u64, u64) { + fn get_block_hash_and_number(ref self: ContractState) -> (u64, u64) { let block_info = starknet::get_block_info().unbox(); let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); From 9c95d808d6ce70e330fcabc3d58dec3fb2e019ce Mon Sep 17 00:00:00 2001 From: Pedro Rosalba Date: Thu, 7 Nov 2024 23:15:43 -0300 Subject: [PATCH 03/17] fix: types --- .../cheatcodes/cheat_block_hash.rs | 66 +++ .../cheatcodes/cheat_execution_info.rs | 3 + .../forge_runtime_extension/cheatcodes/mod.rs | 1 + .../tests/cheatcodes/cheat_block_hash.rs | 436 ++++++++++++++++++ crates/cheatnet/tests/cheatcodes/mod.rs | 1 + .../tests/integration/cheat_block_hash.rs | 324 +++++++++++++ crates/forge/tests/integration/mod.rs | 1 + docs/src/SUMMARY.md | 1 + docs/src/appendix/cheatcodes/block_hash.md | 29 ++ snforge_std/src/lib.cairo | 5 + 10 files changed, 867 insertions(+) create mode 100644 crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_block_hash.rs create mode 100644 crates/cheatnet/tests/cheatcodes/cheat_block_hash.rs create mode 100644 crates/forge/tests/integration/cheat_block_hash.rs create mode 100644 docs/src/appendix/cheatcodes/block_hash.md diff --git a/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_block_hash.rs b/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_block_hash.rs new file mode 100644 index 0000000000..9fdf5bdaa4 --- /dev/null +++ b/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_block_hash.rs @@ -0,0 +1,66 @@ +use super::cheat_execution_info::{ + BlockInfoMockOperations, CheatArguments, ExecutionInfoMockOperations, Operation, +}; +use crate::state::CheatSpan; +use crate::CheatnetState; +use cairo_vm::Felt252; +use starknet_api::core::ContractAddress; + +impl CheatnetState { + pub fn cheat_block_hash( + &mut self, + contract_address: ContractAddress, + block_hash: Felt252, + span: CheatSpan, + ) { + self.cheat_execution_info(ExecutionInfoMockOperations { + block_info: BlockInfoMockOperations { + block_hash: Operation::Start(CheatArguments { + value: block_hash, + span, + target: contract_address, + }), + ..Default::default() + }, + ..Default::default() + }); + } + + pub fn start_cheat_block_hash_global(&mut self, block_hash: Felt252) { + self.cheat_execution_info(ExecutionInfoMockOperations { + block_info: BlockInfoMockOperations { + block_hash: Operation::StartGlobal(block_hash), + ..Default::default() + }, + ..Default::default() + }); + } + + pub fn start_cheat_block_hash( + &mut self, + contract_address: ContractAddress, + block_hash: Felt252, + ) { + self.cheat_block_hash(contract_address, block_hash, CheatSpan::Indefinite); + } + + pub fn stop_cheat_block_hash(&mut self, contract_address: ContractAddress) { + self.cheat_execution_info(ExecutionInfoMockOperations { + block_info: BlockInfoMockOperations { + block_hash: Operation::Stop(contract_address), + ..Default::default() + }, + ..Default::default() + }); + } + + pub fn stop_cheat_block_hash_global(&mut self) { + self.cheat_execution_info(ExecutionInfoMockOperations { + block_info: BlockInfoMockOperations { + block_hash: Operation::StopGlobal, + ..Default::default() + }, + ..Default::default() + }); + } +} diff --git a/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_execution_info.rs b/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_execution_info.rs index fb42dc59c1..1ec3acfa85 100644 --- a/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_execution_info.rs +++ b/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_execution_info.rs @@ -51,6 +51,7 @@ pub struct TxInfoMock { pub struct BlockInfoMock { pub block_number: CheatStatus, pub block_timestamp: CheatStatus, + pub block_hash: CheatStatus, pub sequencer_address: CheatStatus, } @@ -82,6 +83,7 @@ pub struct TxInfoMockOperations { pub struct BlockInfoMockOperations { pub block_number: Operation, pub block_timestamp: Operation, + pub block_hash: Operation, pub sequencer_address: Operation, } @@ -98,6 +100,7 @@ macro_rules! for_all_fields { $macro!(block_info.block_number); $macro!(block_info.block_timestamp); + $macro!(block_info.block_hash); $macro!(block_info.sequencer_address); $macro!(tx_info.version); diff --git a/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/mod.rs b/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/mod.rs index dce56cfa78..f5b00b7ab4 100644 --- a/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/mod.rs +++ b/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/mod.rs @@ -3,6 +3,7 @@ use cairo_vm::vm::errors::hint_errors::HintError; use cairo_vm::Felt252; use runtime::EnhancedHintError; +pub mod cheat_block_hash; pub mod cheat_block_number; pub mod cheat_block_timestamp; pub mod cheat_caller_address; diff --git a/crates/cheatnet/tests/cheatcodes/cheat_block_hash.rs b/crates/cheatnet/tests/cheatcodes/cheat_block_hash.rs new file mode 100644 index 0000000000..73ad0aec36 --- /dev/null +++ b/crates/cheatnet/tests/cheatcodes/cheat_block_hash.rs @@ -0,0 +1,436 @@ +use crate::{common::assertions::assert_success, common::get_contracts}; +use cairo_vm::Felt252; +use cheatnet::state::CheatSpan; +use conversions::IntoConv; +use starknet_api::core::ContractAddress; + +use super::test_environment::TestEnvironment; + +// use runtime::starknet::context::DEFAULT_BLOCK_HASH; + +const DEFAULT_BLOCK_HASH: u64 = 0; + +trait CheatBlockHashTrait { + fn cheat_block_hash( + &mut self, + contract_address: ContractAddress, + block_hash: Felt252, + span: CheatSpan, + ); + fn start_cheat_block_hash(&mut self, contract_address: ContractAddress, block_hash: Felt252); + fn stop_cheat_block_hash(&mut self, contract_address: ContractAddress); +} + +impl CheatBlockHashTrait for TestEnvironment { + fn cheat_block_hash( + &mut self, + contract_address: ContractAddress, + block_hash: Felt252, + span: CheatSpan, + ) { + self.cheatnet_state + .cheat_block_hash(contract_address, block_hash, span); + } + + fn start_cheat_block_hash(&mut self, contract_address: ContractAddress, block_hash: Felt252) { + self.cheatnet_state + .start_cheat_block_hash(contract_address, block_hash); + } + + fn stop_cheat_block_hash(&mut self, contract_address: ContractAddress) { + self.cheatnet_state.stop_cheat_block_hash(contract_address); + } +} + +#[test] +fn cheat_block_hash_simple() { + let mut test_env = TestEnvironment::new(); + + let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + + test_env.start_cheat_block_hash(contract_address, Felt252::from(123)); + + let output = test_env.call_contract(&contract_address, "get_block_hash", &[]); + assert_success(output, &[Felt252::from(123)]); +} + +#[test] +fn cheat_block_hash_with_other_syscall() { + let mut test_env = TestEnvironment::new(); + + let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + + test_env.start_cheat_block_hash(contract_address, Felt252::from(123)); + let selector = "get_block_hash_and_emit_event"; + + let output = test_env.call_contract(&contract_address, selector, &[]); + assert_success(output, &[Felt252::from(123)]); +} + +#[test] +fn cheat_block_hash_in_constructor() { + let mut test_env = TestEnvironment::new(); + let contracts_data = get_contracts(); + + let class_hash = test_env.declare("ConstructorCheatBlockhashChecker", &contracts_data); + let precalculated_address = test_env.precalculate_address(&class_hash, &[]); + + test_env.start_cheat_block_hash(precalculated_address, Felt252::from(123)); + + let contract_address = test_env.deploy_wrapper(&class_hash, &[]); + + assert_eq!(precalculated_address, contract_address); + + let output = test_env.call_contract(&contract_address, "get_stored_block_hash", &[]); + assert_success(output, &[Felt252::from(123)]); +} + +#[test] +fn cheat_block_hash_stop() { + let mut test_env = TestEnvironment::new(); + + let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + + test_env.start_cheat_block_hash(contract_address, Felt252::from(123)); + + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(123)], + ); + + test_env.stop_cheat_block_hash(contract_address); + + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(DEFAULT_BLOCK_HASH)], + ); +} + +#[test] +fn cheat_block_hash_double() { + let mut test_env = TestEnvironment::new(); + + let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + + test_env.start_cheat_block_hash(contract_address, Felt252::from(123)); + test_env.start_cheat_block_hash(contract_address, Felt252::from(123)); + + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(123)], + ); + + test_env.stop_cheat_block_hash(contract_address); + + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(DEFAULT_BLOCK_HASH)], + ); +} + +#[test] +fn cheat_block_hash_proxy() { + let mut test_env = TestEnvironment::new(); + + let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + let proxy_address = test_env.deploy("CheatBlockhashCheckerProxy", &[]); + let proxy_selector = "get_cheated_block_hash"; + + test_env.start_cheat_block_hash(contract_address, Felt252::from(123)); + + assert_success( + test_env.call_contract(&proxy_address, proxy_selector, &[contract_address.into_()]), + &[Felt252::from(123)], + ); + + test_env.stop_cheat_block_hash(contract_address); + + assert_success( + test_env.call_contract(&proxy_address, proxy_selector, &[contract_address.into_()]), + &[Felt252::from(DEFAULT_BLOCK_HASH)], + ); +} + +#[test] +fn cheat_block_hash_library_call() { + let mut test_env = TestEnvironment::new(); + + let contracts_data = get_contracts(); + let class_hash = test_env.declare("CheatBlockhashChecker", &contracts_data); + + let lib_call_address = test_env.deploy("CheatBlockhashCheckerLibCall", &[]); + let lib_call_selector = "get_block_hash_with_lib_call"; + + test_env.start_cheat_block_hash(lib_call_address, Felt252::from(123)); + + assert_success( + test_env.call_contract(&lib_call_address, lib_call_selector, &[class_hash.into_()]), + &[Felt252::from(123)], + ); + test_env.stop_cheat_block_hash(lib_call_address); + + assert_success( + test_env.call_contract(&lib_call_address, lib_call_selector, &[class_hash.into_()]), + &[Felt252::from(DEFAULT_BLOCK_HASH)], + ); +} + +#[test] +fn cheat_block_hash_all_simple() { + let mut test_env = TestEnvironment::new(); + + let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + + test_env.cheatnet_state.start_cheat_block_hash_global(Felt252::from(123)); + + let output = test_env.call_contract(&contract_address, "get_block_hash", &[]); + assert_success(output, &[Felt252::from(123)]); +} + +#[test] +fn cheat_block_hash_all_then_one() { + let mut test_env = TestEnvironment::new(); + + let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + + test_env.cheatnet_state.start_cheat_block_hash_global(Felt252::from(321)); + + test_env.start_cheat_block_hash(contract_address, Felt252::from(123)); + + let output = test_env.call_contract(&contract_address, "get_block_hash", &[]); + assert_success(output, &[Felt252::from(123)]); +} + +#[test] +fn cheat_block_hash_one_then_all() { + let mut test_env = TestEnvironment::new(); + + let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + + test_env.start_cheat_block_hash(contract_address, Felt252::from(123)); + + test_env.cheatnet_state.start_cheat_block_hash_global(Felt252::from(321)); + + let output = test_env.call_contract(&contract_address, "get_block_hash", &[]); + assert_success(output, &[Felt252::from(321)]); +} + +#[test] +fn cheat_block_hash_all_stop() { + let mut test_env = TestEnvironment::new(); + + let cheat_block_hash_checker = test_env.declare("CheatBlockhashChecker", &get_contracts()); + + let contract_address = test_env.deploy_wrapper(&cheat_block_hash_checker, &[]); + + test_env.cheatnet_state.start_cheat_block_hash_global(Felt252::from(123)); + + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(123)], + ); + + test_env.cheatnet_state.stop_cheat_block_hash_global(); + + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(DEFAULT_BLOCK_HASH)], + ); + + let contract_address = test_env.deploy_wrapper(&cheat_block_hash_checker, &[]); + + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(DEFAULT_BLOCK_HASH)], + ); +} + +#[test] +fn cheat_block_hash_multiple() { + let mut test_env = TestEnvironment::new(); + + let contracts_data = get_contracts(); + let class_hash = test_env.declare("CheatBlockhashChecker", &contracts_data); + + let contract_address1 = test_env.deploy_wrapper(&class_hash, &[]); + let contract_address2 = test_env.deploy_wrapper(&class_hash, &[]); + + test_env + .cheatnet_state + .start_cheat_block_hash(contract_address1, Felt252::from(123)); + test_env + .cheatnet_state + .start_cheat_block_hash(contract_address2, Felt252::from(123)); + + assert_success( + test_env.call_contract(&contract_address1, "get_block_hash", &[]), + &[Felt252::from(123)], + ); + assert_success( + test_env.call_contract(&contract_address2, "get_block_hash", &[]), + &[Felt252::from(123)], + ); + + test_env + .cheatnet_state + .stop_cheat_block_hash(contract_address1); + test_env + .cheatnet_state + .stop_cheat_block_hash(contract_address2); + + assert_success( + test_env.call_contract(&contract_address1, "get_block_hash", &[]), + &[Felt252::from(DEFAULT_BLOCK_HASH)], + ); + assert_success( + test_env.call_contract(&contract_address2, "get_block_hash", &[]), + &[Felt252::from(DEFAULT_BLOCK_HASH)], + ); +} + +#[test] +fn cheat_block_hash_simple_with_span() { + let mut test_env = TestEnvironment::new(); + + let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + + test_env.cheat_block_hash(contract_address, Felt252::from(123), CheatSpan::TargetCalls(2)); + + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(123)], + ); + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(123)], + ); + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(DEFAULT_BLOCK_HASH)], + ); +} + +#[test] +fn cheat_block_hash_proxy_with_span() { + let mut test_env = TestEnvironment::new(); + + let contracts_data = get_contracts(); + let class_hash = test_env.declare("CheatBlockhashCheckerProxy", &contracts_data); + let contract_address_1 = test_env.deploy_wrapper(&class_hash, &[]); + let contract_address_2 = test_env.deploy_wrapper(&class_hash, &[]); + + test_env.cheat_block_hash(contract_address_1, Felt252::from(123), CheatSpan::TargetCalls(1)); + + let output = test_env.call_contract( + &contract_address_1, + "call_proxy", + &[contract_address_2.into_()], + ); + assert_success(output, &[123.into(), DEFAULT_BLOCK_HASH.into()]); +} + +#[test] +fn cheat_block_hash_in_constructor_with_span() { + let mut test_env = TestEnvironment::new(); + + let contracts_data = get_contracts(); + + let class_hash = test_env.declare("ConstructorCheatBlockhashChecker", &contracts_data); + let precalculated_address = test_env.precalculate_address(&class_hash, &[]); + + test_env.cheat_block_hash(precalculated_address, Felt252::from(123), CheatSpan::TargetCalls(2)); + + let contract_address = test_env.deploy_wrapper(&class_hash, &[]); + assert_eq!(precalculated_address, contract_address); + + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(123)], + ); + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(DEFAULT_BLOCK_HASH)], + ); + assert_success( + test_env.call_contract(&contract_address, "get_stored_block_hash", &[]), + &[Felt252::from(123)], + ); +} + +#[test] +fn cheat_block_hash_no_constructor_with_span() { + let mut test_env = TestEnvironment::new(); + + let contracts_data = get_contracts(); + + let class_hash = test_env.declare("CheatBlockhashChecker", &contracts_data); + let precalculated_address = test_env.precalculate_address(&class_hash, &[]); + + test_env.cheat_block_hash(precalculated_address, Felt252::from(123), CheatSpan::TargetCalls(1)); + + let contract_address = test_env.deploy_wrapper(&class_hash, &[]); + assert_eq!(precalculated_address, contract_address); + + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(123)], + ); + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(DEFAULT_BLOCK_HASH)], + ); +} + +#[test] +fn cheat_block_hash_override_span() { + let mut test_env = TestEnvironment::new(); + + let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + + test_env.cheat_block_hash(contract_address, Felt252::from(123), CheatSpan::TargetCalls(2)); + + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(123)], + ); + + test_env.cheat_block_hash(contract_address, Felt252::from(321), CheatSpan::Indefinite); + + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(321)], + ); + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(321)], + ); + + test_env.stop_cheat_block_hash(contract_address); + + assert_success( + test_env.call_contract(&contract_address, "get_block_hash", &[]), + &[Felt252::from(DEFAULT_BLOCK_HASH)], + ); +} + +#[test] +fn cheat_block_hash_library_call_with_span() { + let mut test_env = TestEnvironment::new(); + + let contracts_data = get_contracts(); + let class_hash = test_env.declare("CheatBlockhashChecker", &contracts_data); + let contract_address = test_env.deploy("CheatBlockhashCheckerLibCall", &[]); + + test_env.cheat_block_hash(contract_address, Felt252::from(123), CheatSpan::TargetCalls(1)); + + let lib_call_selector = "get_block_hash_with_lib_call"; + + assert_success( + test_env.call_contract(&contract_address, lib_call_selector, &[class_hash.into_()]), + &[Felt252::from(123)], + ); + assert_success( + test_env.call_contract(&contract_address, lib_call_selector, &[class_hash.into_()]), + &[Felt252::from(DEFAULT_BLOCK_HASH)], + ); +} diff --git a/crates/cheatnet/tests/cheatcodes/mod.rs b/crates/cheatnet/tests/cheatcodes/mod.rs index 223f931c77..068ff889f4 100644 --- a/crates/cheatnet/tests/cheatcodes/mod.rs +++ b/crates/cheatnet/tests/cheatcodes/mod.rs @@ -5,6 +5,7 @@ use conversions::IntoConv; mod test_environment; +mod cheat_block_hash; mod cheat_block_number; mod cheat_block_timestamp; mod cheat_caller_address; diff --git a/crates/forge/tests/integration/cheat_block_hash.rs b/crates/forge/tests/integration/cheat_block_hash.rs new file mode 100644 index 0000000000..6f2744fc9c --- /dev/null +++ b/crates/forge/tests/integration/cheat_block_hash.rs @@ -0,0 +1,324 @@ +use indoc::indoc; +use std::path::Path; +use test_utils::runner::{assert_passed, Contract}; +use test_utils::running_tests::run_test_case; +use test_utils::test_case; + +#[test] +fn cheat_block_hash_basic() { + let test = test_case!( + indoc!( + r#" + use result::ResultTrait; + use array::ArrayTrait; + use option::OptionTrait; + use traits::TryInto; + use traits::Into; + use starknet::ContractAddress; + use starknet::Felt252TryIntoContractAddress; + use snforge_std::{ declare, ContractClassTrait, DeclareResultTrait, start_cheat_block_hash, stop_cheat_block_hash, start_cheat_block_number, start_cheat_block_hash_global, stop_cheat_block_hash_global }; + + #[starknet::interface] + trait ICheatBlockhashChecker { + fn get_block_hash(ref self: TContractState) -> felt252; + fn get_block_hash_and_emit_event(ref self: TContractState) -> felt252; + fn get_block_hash_and_number(ref self: TContractState) -> (felt252, u64); + } + + fn deploy_cheat_block_hash_checker() -> ICheatBlockhashCheckerDispatcher { + let contract = declare("CheatBlockhashChecker").unwrap().contract_class(); + let (contract_address, _) = contract.deploy(@ArrayTrait::new()).unwrap(); + ICheatBlockhashCheckerDispatcher { contract_address } + } + + #[test] + fn test_cheat_block_hash() { + let cheat_block_hash_checker = deploy_cheat_block_hash_checker(); + + let old_block_hash = cheat_block_hash_checker.get_block_hash(); + + start_cheat_block_hash(cheat_block_hash_checker.contract_address, 123); + + let new_block_hash = cheat_block_hash_checker.get_block_hash(); + assert(new_block_hash == 123, 'Wrong block hash'); + + stop_cheat_block_hash(cheat_block_hash_checker.contract_address); + + let new_block_hash = cheat_block_hash_checker.get_block_hash(); + assert(new_block_hash == old_block_hash, 'hash did not change back') + } + + #[test] + fn cheat_block_hash_all_stop_one() { + let cheat_block_hash_checker = deploy_cheat_block_hash_checker(); + + let old_block_hash = cheat_block_hash_checker.get_block_hash(); + + start_cheat_block_hash_global(123); + + let new_block_hash = cheat_block_hash_checker.get_block_hash(); + assert(new_block_hash == 123, 'Wrong block hash'); + + stop_cheat_block_hash(cheat_block_hash_checker.contract_address); + + let new_block_hash = cheat_block_hash_checker.get_block_hash(); + assert(new_block_hash == old_block_hash, 'hash did not change back') + } + + #[test] + fn cheat_block_hash_multiple() { + let contract = declare("CheatBlockhashChecker").unwrap().contract_class(); + + let (contract_address1, _) = contract.deploy(@ArrayTrait::new()).unwrap(); + let (contract_address2, _) = contract.deploy(@ArrayTrait::new()).unwrap(); + + let cheat_block_hash_checker1 = ICheatBlockhashCheckerDispatcher { contract_address: contract_address1 }; + let cheat_block_hash_checker2 = ICheatBlockhashCheckerDispatcher { contract_address: contract_address2 }; + + let old_block_hash1 = cheat_block_hash_checker1.get_block_hash(); + let old_block_hash2 = cheat_block_hash_checker2.get_block_hash(); + + start_cheat_block_hash(cheat_block_hash_checker1.contract_address, 123); + start_cheat_block_hash(cheat_block_hash_checker2.contract_address, 123); + + let new_block_hash1 = cheat_block_hash_checker1.get_block_hash(); + let new_block_hash2 = cheat_block_hash_checker2.get_block_hash(); + + assert(new_block_hash1 == 123, 'Wrong block hash #1'); + assert(new_block_hash2 == 123, 'Wrong block hash #2'); + + stop_cheat_block_hash(cheat_block_hash_checker1.contract_address); + stop_cheat_block_hash(cheat_block_hash_checker2.contract_address); + + let new_block_hash1 = cheat_block_hash_checker1.get_block_hash(); + let new_block_hash2 = cheat_block_hash_checker2.get_block_hash(); + + assert(new_block_hash1 == old_block_hash1, 'not stopped #1'); + assert(new_block_hash2 == old_block_hash2, 'not stopped #2'); + } + + #[test] + fn cheat_block_hash_all() { + let contract = declare("CheatBlockhashChecker").unwrap().contract_class(); + + let (contract_address1, _) = contract.deploy(@ArrayTrait::new()).unwrap(); + let (contract_address2, _) = contract.deploy(@ArrayTrait::new()).unwrap(); + + let cheat_block_hash_checker1 = ICheatBlockhashCheckerDispatcher { contract_address: contract_address1 }; + let cheat_block_hash_checker2 = ICheatBlockhashCheckerDispatcher { contract_address: contract_address2 }; + + let old_block_hash1 = cheat_block_hash_checker1.get_block_hash(); + let old_block_hash2 = cheat_block_hash_checker2.get_block_hash(); + + start_cheat_block_hash_global(123); + + let new_block_hash1 = cheat_block_hash_checker1.get_block_hash(); + let new_block_hash2 = cheat_block_hash_checker2.get_block_hash(); + + assert(new_block_hash1 == 123, 'Wrong block hash #1'); + assert(new_block_hash2 == 123, 'Wrong block hash #2'); + + stop_cheat_block_hash_global(); + + let new_block_hash1 = cheat_block_hash_checker1.get_block_hash(); + let new_block_hash2 = cheat_block_hash_checker2.get_block_hash(); + + assert(new_block_hash1 == old_block_hash1, 'Wrong block hash #1'); + assert(new_block_hash2 == old_block_hash2, 'Wrong block hash #2'); + } + "# + ), + Contract::from_code_path( + "CheatBlockhashChecker".to_string(), + Path::new("tests/data/contracts/cheat_block_hash_checker.cairo"), + ) + .unwrap() + ); + + let result = run_test_case(&test); + + assert_passed(&result); +} + +#[test] +fn cheat_block_hash_complex() { + let test = test_case!( + indoc!( + r#" + use result::ResultTrait; + use array::ArrayTrait; + use option::OptionTrait; + use traits::TryInto; + use traits::Into; + use starknet::ContractAddress; + use starknet::Felt252TryIntoContractAddress; + use snforge_std::{ declare, ContractClassTrait, DeclareResultTrait, start_cheat_block_hash, stop_cheat_block_hash, start_cheat_block_number, start_cheat_block_hash_global }; + + #[starknet::interface] + trait ICheatBlockhashChecker { + fn get_block_hash(ref self: TContractState) -> felt252; + fn get_block_hash_and_emit_event(ref self: TContractState) -> felt252; + fn get_block_hash_and_number(ref self: TContractState) -> (felt252, u64); + } + + fn deploy_cheat_block_hash_checker() -> ICheatBlockhashCheckerDispatcher { + let contract = declare("CheatBlockhashChecker").unwrap().contract_class(); + let (contract_address, _) = contract.deploy(@ArrayTrait::new()).unwrap(); + ICheatBlockhashCheckerDispatcher { contract_address } + } + + #[test] + fn cheat_block_hash_complex() { + let contract = declare("CheatBlockhashChecker").unwrap().contract_class(); + + let (contract_address1, _) = contract.deploy(@ArrayTrait::new()).unwrap(); + let (contract_address2, _) = contract.deploy(@ArrayTrait::new()).unwrap(); + + let cheat_block_hash_checker1 = ICheatBlockhashCheckerDispatcher { contract_address: contract_address1 }; + let cheat_block_hash_checker2 = ICheatBlockhashCheckerDispatcher { contract_address: contract_address2 }; + + let old_block_hash2 = cheat_block_hash_checker2.get_block_hash(); + + start_cheat_block_hash_global(123); + + let new_block_hash1 = cheat_block_hash_checker1.get_block_hash(); + let new_block_hash2 = cheat_block_hash_checker2.get_block_hash(); + + assert(new_block_hash1 == 123, 'Wrong block hash #1'); + assert(new_block_hash2 == 123, 'Wrong block hash #2'); + + start_cheat_block_hash(cheat_block_hash_checker1.contract_address, 456); + + let new_block_hash1 = cheat_block_hash_checker1.get_block_hash(); + let new_block_hash2 = cheat_block_hash_checker2.get_block_hash(); + + assert(new_block_hash1 == 456, 'Wrong block hash #3'); + assert(new_block_hash2 == 123, 'Wrong block hash #4'); + + start_cheat_block_hash(cheat_block_hash_checker1.contract_address, 789); + start_cheat_block_hash(cheat_block_hash_checker2.contract_address, 789); + + let new_block_hash1 = cheat_block_hash_checker1.get_block_hash(); + let new_block_hash2 = cheat_block_hash_checker2.get_block_hash(); + + assert(new_block_hash1 == 789, 'Wrong block hash #5'); + assert(new_block_hash2 == 789, 'Wrong block hash #6'); + + stop_cheat_block_hash(cheat_block_hash_checker2.contract_address); + + let new_block_hash1 = cheat_block_hash_checker1.get_block_hash(); + let new_block_hash2 = cheat_block_hash_checker2.get_block_hash(); + + assert(new_block_hash1 == 789, 'Wrong block hash #7'); + assert(new_block_hash2 == old_block_hash2, 'Wrong block hash #8'); + } + "# + ), + Contract::from_code_path( + "CheatBlockhashChecker".to_string(), + Path::new("tests/data/contracts/cheat_block_hash_checker.cairo"), + ) + .unwrap() + ); + + let result = run_test_case(&test); + + assert_passed(&result); +} + +#[test] +fn cheat_block_hash_with_span() { + let test = test_case!( + indoc!( + r#" + use result::ResultTrait; + use array::ArrayTrait; + use option::OptionTrait; + use traits::TryInto; + use starknet::ContractAddress; + use starknet::Felt252TryIntoContractAddress; + use snforge_std::{ test_address, declare, ContractClassTrait, DeclareResultTrait, cheat_block_hash, start_cheat_block_hash, stop_cheat_block_hash, CheatSpan }; + + #[starknet::interface] + trait ICheatBlockhashChecker { + fn get_block_hash(ref self: TContractState) -> felt252; + } + + fn deploy_cheat_block_hash_checker() -> ICheatBlockhashCheckerDispatcher { + let (contract_address, _) = declare("CheatBlockhashChecker").unwrap().contract_class().deploy(@ArrayTrait::new()).unwrap(); + ICheatBlockhashCheckerDispatcher { contract_address } + } + + #[test] + fn test_cheat_block_hash_once() { + let old_block_hash = get_block_hash(); + + let dispatcher = deploy_cheat_block_hash_checker(); + + let target_block_hash = 123; + + cheat_block_hash(dispatcher.contract_address, target_block_hash, CheatSpan::TargetCalls(1)); + + let block_hash = dispatcher.get_block_hash(); + assert_eq!(block_hash, target_block_hash.into()); + + let block_hash = dispatcher.get_block_hash(); + assert_eq!(block_hash, old_block_hash.into()); + } + + #[test] + fn test_cheat_block_hash_twice() { + let old_block_hash = get_block_hash(); + + let dispatcher = deploy_cheat_block_hash_checker(); + + let target_block_hash = 123; + + cheat_block_hash(dispatcher.contract_address, target_block_hash, CheatSpan::TargetCalls(2)); + + let block_hash = dispatcher.get_block_hash(); + assert_eq!(block_hash, target_block_hash.into()); + + let block_hash = dispatcher.get_block_hash(); + assert_eq!(block_hash, target_block_hash.into()); + + let block_hash = dispatcher.get_block_hash(); + assert_eq!(block_hash, old_block_hash.into()); + } + + #[test] + fn test_cheat_block_hash_test_address() { + let old_block_hash = get_block_hash(); + + let target_block_hash = 123; + + cheat_block_hash(test_address(), target_block_hash, CheatSpan::TargetCalls(1)); + + let block_hash = get_block_hash(); + assert_eq!(block_hash, target_block_hash.into()); + + let block_hash = get_block_hash(); + assert_eq!(block_hash, target_block_hash.into()); + + stop_cheat_block_hash(test_address()); + + let block_hash = get_block_hash(); + assert_eq!(block_hash, old_block_hash.into()); + } + + fn get_block_hash() -> felt252 { + starknet::get_block_info().unbox().block_hash + } + "# + ), + Contract::from_code_path( + "CheatBlockhashChecker".to_string(), + Path::new("tests/data/contracts/cheat_block_hash_checker.cairo"), + ) + .unwrap() + ); + + let result = run_test_case(&test); + + assert_passed(&result); +} diff --git a/crates/forge/tests/integration/mod.rs b/crates/forge/tests/integration/mod.rs index 50358ba7a3..d8cc64aa10 100644 --- a/crates/forge/tests/integration/mod.rs +++ b/crates/forge/tests/integration/mod.rs @@ -1,4 +1,5 @@ mod available_gas; +mod cheat_block_hash; mod cheat_block_number; mod cheat_block_timestamp; mod cheat_caller_address; diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 9ed93f8e27..8297c7c7dc 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -73,6 +73,7 @@ * [caller_address](appendix/cheatcodes/caller_address.md) * [block_number](appendix/cheatcodes/block_number.md) * [block_timestamp](appendix/cheatcodes/block_timestamp.md) + * [block_hash](appendix/cheatcodes/block_hash.md) * [sequencer_address](appendix/cheatcodes/sequencer_address.md) * [version](appendix/cheatcodes/transaction_version.md) * [account_contract_address](appendix/cheatcodes/account_contract_address.md) diff --git a/docs/src/appendix/cheatcodes/block_hash.md b/docs/src/appendix/cheatcodes/block_hash.md new file mode 100644 index 0000000000..33a6bb421d --- /dev/null +++ b/docs/src/appendix/cheatcodes/block_hash.md @@ -0,0 +1,29 @@ +# `block_hash` + +Cheatcodes modifying `block_hash`: + +## `cheat_block_hash` +> `fn cheat_block_hash(target: ContractAddress, block_hash: felt252, span: CheatSpan)` + +Changes the block hash for the given target and span. + +## `start_cheat_block_hash_global` +> `fn start_cheat_block_hash_global(block_hash: felt252)` + +Changes the block hash for all targets. + +## `start_cheat_block_hash` +> `fn start_cheat_block_hash(target: ContractAddress, block_hash: felt252)` + +Changes the block hash for the given target. + +## `stop_cheat_block_hash` +> `fn stop_cheat_block_hash(target: ContractAddress)` + +Cancels the `cheat_block_hash` / `start_cheat_block_hash` for the given target. + +## `stop_cheat_block_hash_global` +> `fn stop_cheat_block_hash_global()` + +Cancels the `start_cheat_block_hash_global`. + diff --git a/snforge_std/src/lib.cairo b/snforge_std/src/lib.cairo index 205d62ea04..94fdf10f0b 100644 --- a/snforge_std/src/lib.cairo +++ b/snforge_std/src/lib.cairo @@ -59,6 +59,11 @@ use cheatcodes::execution_info::block_timestamp::start_cheat_block_timestamp_glo use cheatcodes::execution_info::block_timestamp::stop_cheat_block_timestamp; use cheatcodes::execution_info::block_timestamp::stop_cheat_block_timestamp_global; use cheatcodes::execution_info::block_timestamp::start_cheat_block_timestamp; +use cheatcodes::execution_info::block_hash::cheat_block_hash; +use cheatcodes::execution_info::block_hash::start_cheat_block_hash_global; +use cheatcodes::execution_info::block_hash::stop_cheat_block_hash; +use cheatcodes::execution_info::block_hash::stop_cheat_block_hash_global; +use cheatcodes::execution_info::block_hash::start_cheat_block_hash; use cheatcodes::execution_info::sequencer_address::cheat_sequencer_address; use cheatcodes::execution_info::sequencer_address::start_cheat_sequencer_address_global; use cheatcodes::execution_info::sequencer_address::stop_cheat_sequencer_address; From 26f10c4e680d4543d21fc9569fee2ed4e05516db Mon Sep 17 00:00:00 2001 From: Pedro Rosalba Date: Fri, 8 Nov 2024 10:34:14 -0300 Subject: [PATCH 04/17] still in progress --- .../contracts/src/cheat_block_hash.cairo | 4 ++ .../src/cheat_block_hash/checker.cairo | 53 +++++++++++++++++ .../checker_library_call.cairo | 46 +++++++++++++++ .../src/cheat_block_hash/checker_proxy.cairo | 55 ++++++++++++++++++ .../constructor_checker.cairo | 37 ++++++++++++ .../contracts/cheat_block_hash_checker.cairo | 6 +- .../src/cheatcodes/execution_info.cairo | 3 + .../execution_info/block_hash.cairo | 57 +++++++++++++++++++ 8 files changed, 258 insertions(+), 3 deletions(-) create mode 100644 crates/cheatnet/tests/contracts/src/cheat_block_hash.cairo create mode 100644 crates/cheatnet/tests/contracts/src/cheat_block_hash/checker.cairo create mode 100644 crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_library_call.cairo create mode 100644 crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo create mode 100644 crates/cheatnet/tests/contracts/src/cheat_block_hash/constructor_checker.cairo create mode 100644 snforge_std/src/cheatcodes/execution_info/block_hash.cairo diff --git a/crates/cheatnet/tests/contracts/src/cheat_block_hash.cairo b/crates/cheatnet/tests/contracts/src/cheat_block_hash.cairo new file mode 100644 index 0000000000..9c5db3ed91 --- /dev/null +++ b/crates/cheatnet/tests/contracts/src/cheat_block_hash.cairo @@ -0,0 +1,4 @@ +mod checker; +mod constructor_checker; +mod checker_library_call; +mod checker_proxy; diff --git a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker.cairo b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker.cairo new file mode 100644 index 0000000000..b57e27e0c4 --- /dev/null +++ b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker.cairo @@ -0,0 +1,53 @@ +#[starknet::interface] +trait ICheatBlockHashChecker { + fn get_block_hash(ref self: TContractState) -> felt252; + fn get_block_hash_and_emit_event(ref self: TContractState) -> felt252; + fn get_block_hash_and_number(ref self: TContractState) -> (felt252, u64); +} + +#[starknet::contract] +mod CheatBlockHashChecker { + use box::BoxTrait; + use core::starknet::SyscallResultTrait; + use starknet::{get_block_info, get_block_hash_syscall}; + + #[storage] + struct Storage {} + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + BlockHashEmitted: BlockHashEmitted + } + + #[derive(Drop, starknet::Event)] + struct BlockHashEmitted { + block_hash: felt252 + } + + + #[abi(embed_v0)] + impl CheatBlockHashChecker of super::ICheatBlockHashChecker { + fn get_block_hash(ref self: ContractState) -> felt252 { + let block_info = get_block_info().unbox(); + let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + + block_hash + } + + fn get_block_hash_and_emit_event(ref self: ContractState) -> felt252 { + let block_info = get_block_info().unbox(); + let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + + self.emit(Event::BlockHashEmitted(BlockHashEmitted { block_hash })); + block_hash + } + + fn get_block_hash_and_number(ref self: ContractState) -> (felt252, u64) { + let block_info = get_block_info().unbox(); + let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + + (block_hash, block_info.block_number) + } + } +} diff --git a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_library_call.cairo b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_library_call.cairo new file mode 100644 index 0000000000..8559a04822 --- /dev/null +++ b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_library_call.cairo @@ -0,0 +1,46 @@ +use starknet::ClassHash; + +#[starknet::interface] +trait ICheatBlockHashChecker { + fn get_block_hash(ref self: TContractState) -> felt252; +} + +#[starknet::interface] +trait ICheatBlockHashCheckerLibCall { + fn get_block_hash_with_lib_call(ref self: TContractState, class_hash: ClassHash) -> felt252; + fn get_block_hash(ref self: TContractState) -> felt252; +} + +#[starknet::contract] +mod CheatBlockHashCheckerLibCall { + use super::{ + ICheatBlockHashCheckerDispatcherTrait, ICheatBlockHashCheckerLibraryDispatcher + }; + use core::starknet::SyscallResultTrait; + use starknet::ClassHash; + use starknet::{get_block_info, get_block_hash_syscall}; + + #[storage] + struct Storage {} + + #[abi(embed_v0)] + impl ICheatBlockHashCheckerLibCall of super::ICheatBlockHashCheckerLibCall< + ContractState + > { + fn get_block_hash_with_lib_call( + ref self: ContractState, class_hash: ClassHash + ) -> felt252 { + let cheat_block_hash_checker = ICheatBlockHashCheckerLibraryDispatcher { + class_hash + }; + cheat_block_hash_checker.get_block_hash() + } + + fn get_block_hash(ref self: ContractState) -> felt252 { + let block_info = get_block_info().unbox(); + let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + + block_hash + } + } +} diff --git a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo new file mode 100644 index 0000000000..5d1d6546b0 --- /dev/null +++ b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo @@ -0,0 +1,55 @@ +use starknet::ContractAddress; + +#[starknet::interface] +trait ICheatBlockHashChecker { + fn get_block_hash(self: @TContractState) -> felt252; +} + +#[starknet::interface] +trait ICheatBlockHashCheckerProxy { + fn get_cheated_block_hash(self: @TContractState, address: ContractAddress) -> felt252; + fn get_block_hash(self: @TContractState) -> felt252; + fn call_proxy(self: @TContractState, address: ContractAddress) -> (felt252, felt252); +} + +#[starknet::contract] +mod CheatBlockHashCheckerProxy { + use starknet::ContractAddress; + use super::ICheatBlockHashCheckerDispatcherTrait; + use super::ICheatBlockHashCheckerDispatcher; + use super::ICheatBlockHashCheckerProxyDispatcher; + use super::ICheatBlockHashCheckerProxyDispatcherTrait; + use starknet::get_contract_address; + use starknet::{get_block_info, get_block_hash_syscall}; + + #[storage] + struct Storage {} + + #[abi(embed_v0)] + impl ICheatBlockHashCheckerProxy of super::ICheatBlockHashCheckerProxy< + ContractState + > { + fn get_cheated_block_hash(self: @ContractState, address: ContractAddress) -> felt252 { + let cheat_block_hash_checker = ICheatBlockHashCheckerDispatcher { + contract_address: address + }; + cheat_block_hash_checker.get_block_hash() + } + + fn get_block_hash(self: @ContractState) -> felt252 { + let block_info = get_block_info().unbox(); + let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + + block_hash + } + + fn call_proxy(self: @ContractState, address: ContractAddress) -> (felt252, felt252) { + let dispatcher = ICheatBlockHashCheckerProxyDispatcher { + contract_address: address + }; + let hash = self.get_block_hash(); + let res = dispatcher.get_cheated_block_hash(get_contract_address()); + (hash, res) + } + } +} diff --git a/crates/cheatnet/tests/contracts/src/cheat_block_hash/constructor_checker.cairo b/crates/cheatnet/tests/contracts/src/cheat_block_hash/constructor_checker.cairo new file mode 100644 index 0000000000..911381533f --- /dev/null +++ b/crates/cheatnet/tests/contracts/src/cheat_block_hash/constructor_checker.cairo @@ -0,0 +1,37 @@ +#[starknet::interface] +trait IConstructorCheatBlockHashChecker { + fn get_stored_block_hash(ref self: TContractState) -> felt252; + fn get_block_hash(ref self: TContractState) -> felt252; +} + +#[starknet::contract] +mod ConstructorCheatBlockHashChecker { + use box::BoxTrait; + #[storage] + struct Storage { + blk_hash: felt252, + } + + #[constructor] + fn constructor(ref self: ContractState) { + let block_info = get_block_info().unbox(); + let blk_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + self.blk_hash.write(blk_hash); + } + + #[abi(embed_v0)] + impl IConstructorCheatBlockHashChecker of super::IConstructorCheatBlockHashChecker< + ContractState + > { + fn get_stored_block_hash(ref self: ContractState) -> felt252 { + self.blk_hash.read() + } + + fn get_block_hash(ref self: ContractState) -> felt252 { + let block_info = get_block_info().unbox(); + let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + + block_hash + } + } +} diff --git a/crates/forge/tests/data/contracts/cheat_block_hash_checker.cairo b/crates/forge/tests/data/contracts/cheat_block_hash_checker.cairo index 97697d1b7f..7a65b5abad 100644 --- a/crates/forge/tests/data/contracts/cheat_block_hash_checker.cairo +++ b/crates/forge/tests/data/contracts/cheat_block_hash_checker.cairo @@ -35,7 +35,7 @@ mod CheatBlockHashChecker { block_hash } - fn get_block_hash_and_emit_event(ref self: ContractState) -> u64 { + fn get_block_hash_and_emit_event(ref self: ContractState) -> felt252 { let block_info = get_block_info().unbox(); let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); @@ -43,11 +43,11 @@ mod CheatBlockHashChecker { block_hash } - fn get_block_hash_and_number(ref self: ContractState) -> (u64, u64) { + fn get_block_hash_and_number(ref self: ContractState) -> (felt252, u64) { let block_info = starknet::get_block_info().unbox(); let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); - (block_info.block_hash, block_info.block_number) + (block_hash, block_info.block_number) } } } diff --git a/snforge_std/src/cheatcodes/execution_info.cairo b/snforge_std/src/cheatcodes/execution_info.cairo index 32b6e68556..3665b67bd9 100644 --- a/snforge_std/src/cheatcodes/execution_info.cairo +++ b/snforge_std/src/cheatcodes/execution_info.cairo @@ -6,6 +6,7 @@ use super::super::_cheatcode::handle_cheatcode; mod caller_address; mod block_number; mod block_timestamp; +mod block_hash; mod sequencer_address; mod version; mod max_fee; @@ -96,6 +97,7 @@ impl TxInfoMockImpl of Default { struct BlockInfoMock { block_number: Operation, block_timestamp: Operation, + block_hash: Operation, sequencer_address: Operation, } @@ -106,6 +108,7 @@ impl BlockInfoMockImpl of Default { BlockInfoMock { block_number: Operation::Retain, block_timestamp: Operation::Retain, + block_hash: Operation::Retain, sequencer_address: Operation::Retain, } } diff --git a/snforge_std/src/cheatcodes/execution_info/block_hash.cairo b/snforge_std/src/cheatcodes/execution_info/block_hash.cairo new file mode 100644 index 0000000000..d051bd33a4 --- /dev/null +++ b/snforge_std/src/cheatcodes/execution_info/block_hash.cairo @@ -0,0 +1,57 @@ +use super::{ + ExecutionInfoMock, Operation, CheatArguments, CheatSpan, cheat_execution_info, ContractAddress +}; + +/// Changes the block hash for the given contract address and span. +/// - `contract_address` - instance of `ContractAddress` specifying which contract to cheat +/// - `block_hash` - block hash to be set +/// - `span` - instance of `CheatSpan` specifying the hash of contract calls with the cheat +/// applied +fn cheat_block_hash(contract_address: ContractAddress, block_hash: felt252, span: CheatSpan) { + let mut execution_info: ExecutionInfoMock = Default::default(); + + execution_info + .block_info + .block_hash = + Operation::Start( + CheatArguments { value: block_hash, span, target: contract_address, } + ); + + cheat_execution_info(execution_info); +} + +/// Changes the block hash. +/// - `block_hash` - block hash to be set +fn start_cheat_block_hash_global(block_hash: felt252) { + let mut execution_info: ExecutionInfoMock = Default::default(); + + execution_info.block_info.block_hash = Operation::StartGlobal(block_hash); + + cheat_execution_info(execution_info); +} + +/// Cancels the `start_cheat_block_hash_global`. +fn stop_cheat_block_hash_global() { + let mut execution_info: ExecutionInfoMock = Default::default(); + + execution_info.block_info.block_hash = Operation::StopGlobal; + + cheat_execution_info(execution_info); +} + +/// Changes the block hash for the given contract_address. +/// - `contract_address` - instance of `ContractAddress` specifying which contract to cheat +/// - `block_hash` - block hash to be set +fn start_cheat_block_hash(contract_address: ContractAddress, block_hash: felt252) { + cheat_block_hash(contract_address, block_hash, CheatSpan::Indefinite); +} + +/// Cancels the `cheat_block_hash` / `start_cheat_block_hash` for the given contract_address. +/// - `contract_address` - instance of `ContractAddress` specifying which contract to stop cheating +fn stop_cheat_block_hash(contract_address: ContractAddress) { + let mut execution_info: ExecutionInfoMock = Default::default(); + + execution_info.block_info.block_hash = Operation::Stop(contract_address); + + cheat_execution_info(execution_info); +} From 59c5d76af54a67167531403bb961f30b5eee39e3 Mon Sep 17 00:00:00 2001 From: pedro rosalba Date: Tue, 12 Nov 2024 09:26:20 -0300 Subject: [PATCH 05/17] minor fix --- .../tests/cheatcodes/cheat_block_hash.rs | 94 +++++++++++++------ .../src/cheat_block_hash/checker_proxy.cairo | 2 +- .../tests/integration/cheat_block_hash.rs | 48 +++++----- docs/book.toml | 27 +----- 4 files changed, 90 insertions(+), 81 deletions(-) diff --git a/crates/cheatnet/tests/cheatcodes/cheat_block_hash.rs b/crates/cheatnet/tests/cheatcodes/cheat_block_hash.rs index 73ad0aec36..efafce91bc 100644 --- a/crates/cheatnet/tests/cheatcodes/cheat_block_hash.rs +++ b/crates/cheatnet/tests/cheatcodes/cheat_block_hash.rs @@ -46,7 +46,7 @@ impl CheatBlockHashTrait for TestEnvironment { fn cheat_block_hash_simple() { let mut test_env = TestEnvironment::new(); - let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + let contract_address = test_env.deploy("CheatBlockHashChecker", &[]); test_env.start_cheat_block_hash(contract_address, Felt252::from(123)); @@ -58,7 +58,7 @@ fn cheat_block_hash_simple() { fn cheat_block_hash_with_other_syscall() { let mut test_env = TestEnvironment::new(); - let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + let contract_address = test_env.deploy("CheatBlockHashChecker", &[]); test_env.start_cheat_block_hash(contract_address, Felt252::from(123)); let selector = "get_block_hash_and_emit_event"; @@ -72,7 +72,7 @@ fn cheat_block_hash_in_constructor() { let mut test_env = TestEnvironment::new(); let contracts_data = get_contracts(); - let class_hash = test_env.declare("ConstructorCheatBlockhashChecker", &contracts_data); + let class_hash = test_env.declare("ConstructorCheatBlockHashChecker", &contracts_data); let precalculated_address = test_env.precalculate_address(&class_hash, &[]); test_env.start_cheat_block_hash(precalculated_address, Felt252::from(123)); @@ -89,7 +89,7 @@ fn cheat_block_hash_in_constructor() { fn cheat_block_hash_stop() { let mut test_env = TestEnvironment::new(); - let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + let contract_address = test_env.deploy("CheatBlockHashChecker", &[]); test_env.start_cheat_block_hash(contract_address, Felt252::from(123)); @@ -110,7 +110,7 @@ fn cheat_block_hash_stop() { fn cheat_block_hash_double() { let mut test_env = TestEnvironment::new(); - let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + let contract_address = test_env.deploy("CheatBlockHashChecker", &[]); test_env.start_cheat_block_hash(contract_address, Felt252::from(123)); test_env.start_cheat_block_hash(contract_address, Felt252::from(123)); @@ -132,8 +132,8 @@ fn cheat_block_hash_double() { fn cheat_block_hash_proxy() { let mut test_env = TestEnvironment::new(); - let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); - let proxy_address = test_env.deploy("CheatBlockhashCheckerProxy", &[]); + let contract_address = test_env.deploy("CheatBlockHashChecker", &[]); + let proxy_address = test_env.deploy("CheatBlockHashCheckerProxy", &[]); let proxy_selector = "get_cheated_block_hash"; test_env.start_cheat_block_hash(contract_address, Felt252::from(123)); @@ -156,9 +156,9 @@ fn cheat_block_hash_library_call() { let mut test_env = TestEnvironment::new(); let contracts_data = get_contracts(); - let class_hash = test_env.declare("CheatBlockhashChecker", &contracts_data); + let class_hash = test_env.declare("CheatBlockHashChecker", &contracts_data); - let lib_call_address = test_env.deploy("CheatBlockhashCheckerLibCall", &[]); + let lib_call_address = test_env.deploy("CheatBlockHashCheckerLibCall", &[]); let lib_call_selector = "get_block_hash_with_lib_call"; test_env.start_cheat_block_hash(lib_call_address, Felt252::from(123)); @@ -179,9 +179,11 @@ fn cheat_block_hash_library_call() { fn cheat_block_hash_all_simple() { let mut test_env = TestEnvironment::new(); - let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + let contract_address = test_env.deploy("CheatBlockHashChecker", &[]); - test_env.cheatnet_state.start_cheat_block_hash_global(Felt252::from(123)); + test_env + .cheatnet_state + .start_cheat_block_hash_global(Felt252::from(123)); let output = test_env.call_contract(&contract_address, "get_block_hash", &[]); assert_success(output, &[Felt252::from(123)]); @@ -191,9 +193,11 @@ fn cheat_block_hash_all_simple() { fn cheat_block_hash_all_then_one() { let mut test_env = TestEnvironment::new(); - let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + let contract_address = test_env.deploy("CheatBlockHashChecker", &[]); - test_env.cheatnet_state.start_cheat_block_hash_global(Felt252::from(321)); + test_env + .cheatnet_state + .start_cheat_block_hash_global(Felt252::from(321)); test_env.start_cheat_block_hash(contract_address, Felt252::from(123)); @@ -205,11 +209,13 @@ fn cheat_block_hash_all_then_one() { fn cheat_block_hash_one_then_all() { let mut test_env = TestEnvironment::new(); - let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + let contract_address = test_env.deploy("CheatBlockHashChecker", &[]); test_env.start_cheat_block_hash(contract_address, Felt252::from(123)); - test_env.cheatnet_state.start_cheat_block_hash_global(Felt252::from(321)); + test_env + .cheatnet_state + .start_cheat_block_hash_global(Felt252::from(321)); let output = test_env.call_contract(&contract_address, "get_block_hash", &[]); assert_success(output, &[Felt252::from(321)]); @@ -219,11 +225,13 @@ fn cheat_block_hash_one_then_all() { fn cheat_block_hash_all_stop() { let mut test_env = TestEnvironment::new(); - let cheat_block_hash_checker = test_env.declare("CheatBlockhashChecker", &get_contracts()); + let cheat_block_hash_checker = test_env.declare("CheatBlockHashChecker", &get_contracts()); let contract_address = test_env.deploy_wrapper(&cheat_block_hash_checker, &[]); - test_env.cheatnet_state.start_cheat_block_hash_global(Felt252::from(123)); + test_env + .cheatnet_state + .start_cheat_block_hash_global(Felt252::from(123)); assert_success( test_env.call_contract(&contract_address, "get_block_hash", &[]), @@ -250,7 +258,7 @@ fn cheat_block_hash_multiple() { let mut test_env = TestEnvironment::new(); let contracts_data = get_contracts(); - let class_hash = test_env.declare("CheatBlockhashChecker", &contracts_data); + let class_hash = test_env.declare("CheatBlockHashChecker", &contracts_data); let contract_address1 = test_env.deploy_wrapper(&class_hash, &[]); let contract_address2 = test_env.deploy_wrapper(&class_hash, &[]); @@ -292,9 +300,13 @@ fn cheat_block_hash_multiple() { fn cheat_block_hash_simple_with_span() { let mut test_env = TestEnvironment::new(); - let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + let contract_address = test_env.deploy("CheatBlockHashChecker", &[]); - test_env.cheat_block_hash(contract_address, Felt252::from(123), CheatSpan::TargetCalls(2)); + test_env.cheat_block_hash( + contract_address, + Felt252::from(123), + CheatSpan::TargetCalls(2), + ); assert_success( test_env.call_contract(&contract_address, "get_block_hash", &[]), @@ -315,11 +327,15 @@ fn cheat_block_hash_proxy_with_span() { let mut test_env = TestEnvironment::new(); let contracts_data = get_contracts(); - let class_hash = test_env.declare("CheatBlockhashCheckerProxy", &contracts_data); + let class_hash = test_env.declare("CheatBlockHashCheckerProxy", &contracts_data); let contract_address_1 = test_env.deploy_wrapper(&class_hash, &[]); let contract_address_2 = test_env.deploy_wrapper(&class_hash, &[]); - test_env.cheat_block_hash(contract_address_1, Felt252::from(123), CheatSpan::TargetCalls(1)); + test_env.cheat_block_hash( + contract_address_1, + Felt252::from(123), + CheatSpan::TargetCalls(1), + ); let output = test_env.call_contract( &contract_address_1, @@ -335,10 +351,14 @@ fn cheat_block_hash_in_constructor_with_span() { let contracts_data = get_contracts(); - let class_hash = test_env.declare("ConstructorCheatBlockhashChecker", &contracts_data); + let class_hash = test_env.declare("ConstructorCheatBlockHashChecker", &contracts_data); let precalculated_address = test_env.precalculate_address(&class_hash, &[]); - test_env.cheat_block_hash(precalculated_address, Felt252::from(123), CheatSpan::TargetCalls(2)); + test_env.cheat_block_hash( + precalculated_address, + Felt252::from(123), + CheatSpan::TargetCalls(2), + ); let contract_address = test_env.deploy_wrapper(&class_hash, &[]); assert_eq!(precalculated_address, contract_address); @@ -363,10 +383,14 @@ fn cheat_block_hash_no_constructor_with_span() { let contracts_data = get_contracts(); - let class_hash = test_env.declare("CheatBlockhashChecker", &contracts_data); + let class_hash = test_env.declare("CheatBlockHashChecker", &contracts_data); let precalculated_address = test_env.precalculate_address(&class_hash, &[]); - test_env.cheat_block_hash(precalculated_address, Felt252::from(123), CheatSpan::TargetCalls(1)); + test_env.cheat_block_hash( + precalculated_address, + Felt252::from(123), + CheatSpan::TargetCalls(1), + ); let contract_address = test_env.deploy_wrapper(&class_hash, &[]); assert_eq!(precalculated_address, contract_address); @@ -385,9 +409,13 @@ fn cheat_block_hash_no_constructor_with_span() { fn cheat_block_hash_override_span() { let mut test_env = TestEnvironment::new(); - let contract_address = test_env.deploy("CheatBlockhashChecker", &[]); + let contract_address = test_env.deploy("CheatBlockHashChecker", &[]); - test_env.cheat_block_hash(contract_address, Felt252::from(123), CheatSpan::TargetCalls(2)); + test_env.cheat_block_hash( + contract_address, + Felt252::from(123), + CheatSpan::TargetCalls(2), + ); assert_success( test_env.call_contract(&contract_address, "get_block_hash", &[]), @@ -418,10 +446,14 @@ fn cheat_block_hash_library_call_with_span() { let mut test_env = TestEnvironment::new(); let contracts_data = get_contracts(); - let class_hash = test_env.declare("CheatBlockhashChecker", &contracts_data); - let contract_address = test_env.deploy("CheatBlockhashCheckerLibCall", &[]); + let class_hash = test_env.declare("CheatBlockHashChecker", &contracts_data); + let contract_address = test_env.deploy("CheatBlockHashCheckerLibCall", &[]); - test_env.cheat_block_hash(contract_address, Felt252::from(123), CheatSpan::TargetCalls(1)); + test_env.cheat_block_hash( + contract_address, + Felt252::from(123), + CheatSpan::TargetCalls(1), + ); let lib_call_selector = "get_block_hash_with_lib_call"; diff --git a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo index 5d1d6546b0..1968c38f7d 100644 --- a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo +++ b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo @@ -6,7 +6,7 @@ trait ICheatBlockHashChecker { } #[starknet::interface] -trait ICheatBlockHashCheckerProxy { +trait { fn get_cheated_block_hash(self: @TContractState, address: ContractAddress) -> felt252; fn get_block_hash(self: @TContractState) -> felt252; fn call_proxy(self: @TContractState, address: ContractAddress) -> (felt252, felt252); diff --git a/crates/forge/tests/integration/cheat_block_hash.rs b/crates/forge/tests/integration/cheat_block_hash.rs index 6f2744fc9c..050408b0c5 100644 --- a/crates/forge/tests/integration/cheat_block_hash.rs +++ b/crates/forge/tests/integration/cheat_block_hash.rs @@ -19,16 +19,16 @@ fn cheat_block_hash_basic() { use snforge_std::{ declare, ContractClassTrait, DeclareResultTrait, start_cheat_block_hash, stop_cheat_block_hash, start_cheat_block_number, start_cheat_block_hash_global, stop_cheat_block_hash_global }; #[starknet::interface] - trait ICheatBlockhashChecker { + trait ICheatBlockHashChecker { fn get_block_hash(ref self: TContractState) -> felt252; fn get_block_hash_and_emit_event(ref self: TContractState) -> felt252; fn get_block_hash_and_number(ref self: TContractState) -> (felt252, u64); } - fn deploy_cheat_block_hash_checker() -> ICheatBlockhashCheckerDispatcher { - let contract = declare("CheatBlockhashChecker").unwrap().contract_class(); + fn deploy_cheat_block_hash_checker() -> ICheatBlockHashCheckerDispatcher { + let contract = declare("CheatBlockHashChecker").unwrap().contract_class(); let (contract_address, _) = contract.deploy(@ArrayTrait::new()).unwrap(); - ICheatBlockhashCheckerDispatcher { contract_address } + ICheatBlockHashCheckerDispatcher { contract_address } } #[test] @@ -67,13 +67,13 @@ fn cheat_block_hash_basic() { #[test] fn cheat_block_hash_multiple() { - let contract = declare("CheatBlockhashChecker").unwrap().contract_class(); + let contract = declare("CheatBlockHashChecker").unwrap().contract_class(); let (contract_address1, _) = contract.deploy(@ArrayTrait::new()).unwrap(); let (contract_address2, _) = contract.deploy(@ArrayTrait::new()).unwrap(); - let cheat_block_hash_checker1 = ICheatBlockhashCheckerDispatcher { contract_address: contract_address1 }; - let cheat_block_hash_checker2 = ICheatBlockhashCheckerDispatcher { contract_address: contract_address2 }; + let cheat_block_hash_checker1 = ICheatBlockHashCheckerDispatcher { contract_address: contract_address1 }; + let cheat_block_hash_checker2 = ICheatBlockHashCheckerDispatcher { contract_address: contract_address2 }; let old_block_hash1 = cheat_block_hash_checker1.get_block_hash(); let old_block_hash2 = cheat_block_hash_checker2.get_block_hash(); @@ -99,13 +99,13 @@ fn cheat_block_hash_basic() { #[test] fn cheat_block_hash_all() { - let contract = declare("CheatBlockhashChecker").unwrap().contract_class(); + let contract = declare("CheatBlockHashChecker").unwrap().contract_class(); let (contract_address1, _) = contract.deploy(@ArrayTrait::new()).unwrap(); let (contract_address2, _) = contract.deploy(@ArrayTrait::new()).unwrap(); - let cheat_block_hash_checker1 = ICheatBlockhashCheckerDispatcher { contract_address: contract_address1 }; - let cheat_block_hash_checker2 = ICheatBlockhashCheckerDispatcher { contract_address: contract_address2 }; + let cheat_block_hash_checker1 = ICheatBlockHashCheckerDispatcher { contract_address: contract_address1 }; + let cheat_block_hash_checker2 = ICheatBlockHashCheckerDispatcher { contract_address: contract_address2 }; let old_block_hash1 = cheat_block_hash_checker1.get_block_hash(); let old_block_hash2 = cheat_block_hash_checker2.get_block_hash(); @@ -129,7 +129,7 @@ fn cheat_block_hash_basic() { "# ), Contract::from_code_path( - "CheatBlockhashChecker".to_string(), + "CheatBlockHashChecker".to_string(), Path::new("tests/data/contracts/cheat_block_hash_checker.cairo"), ) .unwrap() @@ -155,27 +155,27 @@ fn cheat_block_hash_complex() { use snforge_std::{ declare, ContractClassTrait, DeclareResultTrait, start_cheat_block_hash, stop_cheat_block_hash, start_cheat_block_number, start_cheat_block_hash_global }; #[starknet::interface] - trait ICheatBlockhashChecker { + trait ICheatBlockHashChecker { fn get_block_hash(ref self: TContractState) -> felt252; fn get_block_hash_and_emit_event(ref self: TContractState) -> felt252; fn get_block_hash_and_number(ref self: TContractState) -> (felt252, u64); } - fn deploy_cheat_block_hash_checker() -> ICheatBlockhashCheckerDispatcher { - let contract = declare("CheatBlockhashChecker").unwrap().contract_class(); + fn deploy_cheat_block_hash_checker() -> ICheatBlockHashCheckerDispatcher { + let contract = declare("CheatBlockHashChecker").unwrap().contract_class(); let (contract_address, _) = contract.deploy(@ArrayTrait::new()).unwrap(); - ICheatBlockhashCheckerDispatcher { contract_address } + ICheatBlockHashCheckerDispatcher { contract_address } } #[test] fn cheat_block_hash_complex() { - let contract = declare("CheatBlockhashChecker").unwrap().contract_class(); + let contract = declare("CheatBlockHashChecker").unwrap().contract_class(); let (contract_address1, _) = contract.deploy(@ArrayTrait::new()).unwrap(); let (contract_address2, _) = contract.deploy(@ArrayTrait::new()).unwrap(); - let cheat_block_hash_checker1 = ICheatBlockhashCheckerDispatcher { contract_address: contract_address1 }; - let cheat_block_hash_checker2 = ICheatBlockhashCheckerDispatcher { contract_address: contract_address2 }; + let cheat_block_hash_checker1 = ICheatBlockHashCheckerDispatcher { contract_address: contract_address1 }; + let cheat_block_hash_checker2 = ICheatBlockHashCheckerDispatcher { contract_address: contract_address2 }; let old_block_hash2 = cheat_block_hash_checker2.get_block_hash(); @@ -215,7 +215,7 @@ fn cheat_block_hash_complex() { "# ), Contract::from_code_path( - "CheatBlockhashChecker".to_string(), + "CheatBlockHashChecker".to_string(), Path::new("tests/data/contracts/cheat_block_hash_checker.cairo"), ) .unwrap() @@ -240,13 +240,13 @@ fn cheat_block_hash_with_span() { use snforge_std::{ test_address, declare, ContractClassTrait, DeclareResultTrait, cheat_block_hash, start_cheat_block_hash, stop_cheat_block_hash, CheatSpan }; #[starknet::interface] - trait ICheatBlockhashChecker { + trait ICheatBlockHashChecker { fn get_block_hash(ref self: TContractState) -> felt252; } - fn deploy_cheat_block_hash_checker() -> ICheatBlockhashCheckerDispatcher { - let (contract_address, _) = declare("CheatBlockhashChecker").unwrap().contract_class().deploy(@ArrayTrait::new()).unwrap(); - ICheatBlockhashCheckerDispatcher { contract_address } + fn deploy_cheat_block_hash_checker() -> ICheatBlockHashCheckerDispatcher { + let (contract_address, _) = declare("CheatBlockHashChecker").unwrap().contract_class().deploy(@ArrayTrait::new()).unwrap(); + ICheatBlockHashCheckerDispatcher { contract_address } } #[test] @@ -312,7 +312,7 @@ fn cheat_block_hash_with_span() { "# ), Contract::from_code_path( - "CheatBlockhashChecker".to_string(), + "CheatBlockHashChecker".to_string(), Path::new("tests/data/contracts/cheat_block_hash_checker.cairo"), ) .unwrap() diff --git a/docs/book.toml b/docs/book.toml index 202324d063..42dbfd1959 100644 --- a/docs/book.toml +++ b/docs/book.toml @@ -1,29 +1,6 @@ [book] -authors = ["Starknet Foundry"] +authors = ["pedro rosalba"] language = "en" multilingual = false src = "src" -title = "The Starknet Foundry Book" -description = "Starknet Foundry is a toolchain for developing Starknet smart contracts. It helps with writing, deploying, and testing your smart contracts written in Cairo. It is inspired by Foundry." - -[output.linkcheck] -warning-policy = "error" -follow-web-links = true -traverse-parent-directories = false -exclude = [ - "foundry-rs.github.io/starknet-foundry/snforge_std", - "foundry-rs.github.io/starknet-foundry/sncast_std", - "starknet-faucet.vercel.app" -] - -[output.html] -git-repository-url = "https://github.com/foundry-rs/starknet-foundry/" -edit-url-template = "https://github.com/foundry-rs/starknet-foundry/edit/master/docs/{path}" -additional-js = ["count.js"] - -[output.html.playground] -runnable = false - -[output.html.fold] -enable = true -level = 0 +title = "idk" From 65b483925a7822d898edff5970454112a17070d1 Mon Sep 17 00:00:00 2001 From: pedro rosalba Date: Tue, 12 Nov 2024 09:29:32 -0300 Subject: [PATCH 06/17] minor fix: undo create book --- docs/book.toml | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/docs/book.toml b/docs/book.toml index 42dbfd1959..202324d063 100644 --- a/docs/book.toml +++ b/docs/book.toml @@ -1,6 +1,29 @@ [book] -authors = ["pedro rosalba"] +authors = ["Starknet Foundry"] language = "en" multilingual = false src = "src" -title = "idk" +title = "The Starknet Foundry Book" +description = "Starknet Foundry is a toolchain for developing Starknet smart contracts. It helps with writing, deploying, and testing your smart contracts written in Cairo. It is inspired by Foundry." + +[output.linkcheck] +warning-policy = "error" +follow-web-links = true +traverse-parent-directories = false +exclude = [ + "foundry-rs.github.io/starknet-foundry/snforge_std", + "foundry-rs.github.io/starknet-foundry/sncast_std", + "starknet-faucet.vercel.app" +] + +[output.html] +git-repository-url = "https://github.com/foundry-rs/starknet-foundry/" +edit-url-template = "https://github.com/foundry-rs/starknet-foundry/edit/master/docs/{path}" +additional-js = ["count.js"] + +[output.html.playground] +runnable = false + +[output.html.fold] +enable = true +level = 0 From 845a2d943d8436db971834ce3a9c4a902ca6a592 Mon Sep 17 00:00:00 2001 From: pedro rosalba Date: Tue, 12 Nov 2024 09:34:27 -0300 Subject: [PATCH 07/17] minor fix --- .../tests/contracts/src/cheat_block_hash/checker_proxy.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo index 1968c38f7d..5d1d6546b0 100644 --- a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo +++ b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo @@ -6,7 +6,7 @@ trait ICheatBlockHashChecker { } #[starknet::interface] -trait { +trait ICheatBlockHashCheckerProxy { fn get_cheated_block_hash(self: @TContractState, address: ContractAddress) -> felt252; fn get_block_hash(self: @TContractState) -> felt252; fn call_proxy(self: @TContractState, address: ContractAddress) -> (felt252, felt252); From 2b1690f78f7836339f505af7329f5ec240956316 Mon Sep 17 00:00:00 2001 From: pedro rosalba Date: Tue, 12 Nov 2024 13:42:19 -0300 Subject: [PATCH 08/17] ran scarbfmt.sh --- .../cheat_block_hash/checker_library_call.cairo | 16 ++++------------ .../src/cheat_block_hash/checker_proxy.cairo | 10 +++------- .../cheatcodes/execution_info/block_hash.cairo | 4 +--- 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_library_call.cairo b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_library_call.cairo index 8559a04822..c436dc9adb 100644 --- a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_library_call.cairo +++ b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_library_call.cairo @@ -13,9 +13,7 @@ trait ICheatBlockHashCheckerLibCall { #[starknet::contract] mod CheatBlockHashCheckerLibCall { - use super::{ - ICheatBlockHashCheckerDispatcherTrait, ICheatBlockHashCheckerLibraryDispatcher - }; + use super::{ICheatBlockHashCheckerDispatcherTrait, ICheatBlockHashCheckerLibraryDispatcher}; use core::starknet::SyscallResultTrait; use starknet::ClassHash; use starknet::{get_block_info, get_block_hash_syscall}; @@ -24,15 +22,9 @@ mod CheatBlockHashCheckerLibCall { struct Storage {} #[abi(embed_v0)] - impl ICheatBlockHashCheckerLibCall of super::ICheatBlockHashCheckerLibCall< - ContractState - > { - fn get_block_hash_with_lib_call( - ref self: ContractState, class_hash: ClassHash - ) -> felt252 { - let cheat_block_hash_checker = ICheatBlockHashCheckerLibraryDispatcher { - class_hash - }; + impl ICheatBlockHashCheckerLibCall of super::ICheatBlockHashCheckerLibCall { + fn get_block_hash_with_lib_call(ref self: ContractState, class_hash: ClassHash) -> felt252 { + let cheat_block_hash_checker = ICheatBlockHashCheckerLibraryDispatcher { class_hash }; cheat_block_hash_checker.get_block_hash() } diff --git a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo index 5d1d6546b0..c6e7060ea8 100644 --- a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo +++ b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo @@ -26,9 +26,7 @@ mod CheatBlockHashCheckerProxy { struct Storage {} #[abi(embed_v0)] - impl ICheatBlockHashCheckerProxy of super::ICheatBlockHashCheckerProxy< - ContractState - > { + impl ICheatBlockHashCheckerProxy of super::ICheatBlockHashCheckerProxy { fn get_cheated_block_hash(self: @ContractState, address: ContractAddress) -> felt252 { let cheat_block_hash_checker = ICheatBlockHashCheckerDispatcher { contract_address: address @@ -40,13 +38,11 @@ mod CheatBlockHashCheckerProxy { let block_info = get_block_info().unbox(); let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); - block_hash + block_hash } fn call_proxy(self: @ContractState, address: ContractAddress) -> (felt252, felt252) { - let dispatcher = ICheatBlockHashCheckerProxyDispatcher { - contract_address: address - }; + let dispatcher = ICheatBlockHashCheckerProxyDispatcher { contract_address: address }; let hash = self.get_block_hash(); let res = dispatcher.get_cheated_block_hash(get_contract_address()); (hash, res) diff --git a/snforge_std/src/cheatcodes/execution_info/block_hash.cairo b/snforge_std/src/cheatcodes/execution_info/block_hash.cairo index d051bd33a4..3d0d078abe 100644 --- a/snforge_std/src/cheatcodes/execution_info/block_hash.cairo +++ b/snforge_std/src/cheatcodes/execution_info/block_hash.cairo @@ -13,9 +13,7 @@ fn cheat_block_hash(contract_address: ContractAddress, block_hash: felt252, span execution_info .block_info .block_hash = - Operation::Start( - CheatArguments { value: block_hash, span, target: contract_address, } - ); + Operation::Start(CheatArguments { value: block_hash, span, target: contract_address, }); cheat_execution_info(execution_info); } From a450fa121fa47e42db2225e962531724f5653a3e Mon Sep 17 00:00:00 2001 From: pedro rosalba Date: Tue, 12 Nov 2024 19:28:03 -0300 Subject: [PATCH 09/17] added changelog and fix imports Felt252 --- CHANGELOG.md | 5 +++++ .../cheatcodes/cheat_execution_info.rs | 1 + 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 162a964d42..e6d20d5ab7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +#### Added + +- Cheatcode for getting block hash. + + ### Forge #### Added diff --git a/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_execution_info.rs b/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_execution_info.rs index 68e29c8092..62e8cb94ad 100644 --- a/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_execution_info.rs +++ b/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_execution_info.rs @@ -5,6 +5,7 @@ use crate::{ use conversions::serde::{deserialize::CairoDeserialize, serialize::CairoSerialize}; use starknet_api::core::ContractAddress; use starknet_types_core::felt::Felt; +use cairo_vm::Felt252; #[derive(CairoDeserialize, Clone, Debug)] pub struct CheatArguments { From 7bc764fe37ea840b2e3deb4ea582e479d995c446 Mon Sep 17 00:00:00 2001 From: pedro rosalba Date: Wed, 13 Nov 2024 14:46:24 -0300 Subject: [PATCH 10/17] added module to lib and fmt code --- .../forge_runtime_extension/cheatcodes/cheat_execution_info.rs | 2 +- crates/cheatnet/tests/contracts/src/lib.cairo | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_execution_info.rs b/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_execution_info.rs index 62e8cb94ad..70e90e7c8f 100644 --- a/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_execution_info.rs +++ b/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_execution_info.rs @@ -2,10 +2,10 @@ use crate::{ state::{CheatSpan, CheatStatus}, CheatnetState, }; +use cairo_vm::Felt252; use conversions::serde::{deserialize::CairoDeserialize, serialize::CairoSerialize}; use starknet_api::core::ContractAddress; use starknet_types_core::felt::Felt; -use cairo_vm::Felt252; #[derive(CairoDeserialize, Clone, Debug)] pub struct CheatArguments { diff --git a/crates/cheatnet/tests/contracts/src/lib.cairo b/crates/cheatnet/tests/contracts/src/lib.cairo index a11be84acf..fb27d478cc 100644 --- a/crates/cheatnet/tests/contracts/src/lib.cairo +++ b/crates/cheatnet/tests/contracts/src/lib.cairo @@ -9,6 +9,7 @@ mod cheat_tx_info; mod cheat_sequencer_address; mod starknet; mod cheat_block_timestamp; +mod cheat_block_hash; mod segment_arena_user; mod panic_call; mod store_load; From 9b770983c4d1eaa404c92d77ef5af3b245e5b1c0 Mon Sep 17 00:00:00 2001 From: Pedro Rosalba Date: Sat, 16 Nov 2024 21:39:19 -0300 Subject: [PATCH 11/17] fix: adding import --- .../contracts/src/cheat_block_hash/constructor_checker.cairo | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/cheatnet/tests/contracts/src/cheat_block_hash/constructor_checker.cairo b/crates/cheatnet/tests/contracts/src/cheat_block_hash/constructor_checker.cairo index 911381533f..6de195e31f 100644 --- a/crates/cheatnet/tests/contracts/src/cheat_block_hash/constructor_checker.cairo +++ b/crates/cheatnet/tests/contracts/src/cheat_block_hash/constructor_checker.cairo @@ -7,6 +7,8 @@ trait IConstructorCheatBlockHashChecker { #[starknet::contract] mod ConstructorCheatBlockHashChecker { use box::BoxTrait; + use starknet::{get_block_info, get_block_hash_syscall}; + #[storage] struct Storage { blk_hash: felt252, From cf6e4294793f7a3fdddf6a2b2fcb0684806421e6 Mon Sep 17 00:00:00 2001 From: Pedro Rosalba Date: Sun, 1 Dec 2024 13:03:05 -0300 Subject: [PATCH 12/17] Ignore .cargo/ and .rustup/ directories --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 8801014fc0..11ad7f9e76 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ Scarb.lock snfoundry_trace/ coverage/ **/.forge_e2e_cache/ +.cargo/ +.rustup/ From ab96aca8bcfe1456539a6ae57b4294e5b3832f13 Mon Sep 17 00:00:00 2001 From: Pedro Rosalba Date: Sun, 1 Dec 2024 13:03:34 -0300 Subject: [PATCH 13/17] updates --- .tool-versions | 2 +- .../execution/cheated_syscalls.rs | 26 ++++++++++++++++++- .../cheatable_starknet_runtime_extension.rs | 9 +++++++ crates/cheatnet/src/state.rs | 8 ++++++ .../src/cheat_block_hash/checker.cairo | 6 ++--- .../checker_library_call.cairo | 2 +- .../src/cheat_block_hash/checker_proxy.cairo | 2 +- .../constructor_checker.cairo | 4 +-- .../contracts/src/starknet/blocker.cairo | 2 +- .../data/contracts/block_hash_checker.cairo | 2 +- .../contracts/cheat_block_hash_checker.cairo | 6 ++--- crates/forge/tests/integration/test_state.rs | 2 +- 12 files changed, 56 insertions(+), 15 deletions(-) diff --git a/.tool-versions b/.tool-versions index 045dc3e7cc..ff54753330 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -scarb 2.7.0 +scarb 2.8.4 diff --git a/crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/execution/cheated_syscalls.rs b/crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/execution/cheated_syscalls.rs index 1086a0f7ed..c82d9360b4 100644 --- a/crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/execution/cheated_syscalls.rs +++ b/crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/execution/cheated_syscalls.rs @@ -2,7 +2,7 @@ use crate::runtime_extensions::call_to_blockifier_runtime_extension::execution:: use crate::runtime_extensions::call_to_blockifier_runtime_extension::CheatnetState; use blockifier::execution::syscalls::hint_processor::SyscallHintProcessor; use blockifier::execution::syscalls::{ - DeployRequest, DeployResponse, LibraryCallRequest, SyscallResponse, SyscallResult, + DeployRequest, DeployResponse, GetBlockHashRequest, GetBlockHashResponse, LibraryCallRequest, SyscallResponse, SyscallResult }; use blockifier::execution::{call_info::CallInfo, entry_point::ConstructorContext}; use blockifier::execution::{ @@ -57,6 +57,30 @@ pub fn get_execution_info_syscall( }) } +pub fn get_block_hash_syscall( + request: GetBlockHashRequest, + vm: &mut VirtualMachine, + syscall_handler: &mut SyscallHintProcessor<'_>, + cheatnet_state: &mut CheatnetState, + _remaining_gas: &mut u64, +) -> SyscallResult { + + let execution_info_ptr = syscall_handler.get_or_allocate_execution_info_segment(vm)?; + + let cheated_data = cheatnet_state.get_cheated_data(syscall_handler.storage_address()); + + let ptr_cheated_block_info = get_cheated_block_info_ptr(vm, execution_info_ptr, &cheated_data); + + //TODO: how to get the cheated block number using the ptr_cheated_block_info? + //why is the get_cheated_block_info not public? + //why is BlockHash not public? + + let cheated_block_hash = BlockHash(syscall_handler.state.get_storage_at(block_hash_contract_address, key)?); + + Ok(GetBlockHashResponse { block_hash: cheated_block_hash }) + +} + // blockifier/src/execution/syscalls/mod.rs:222 (deploy_syscall) pub fn deploy_syscall( request: DeployRequest, diff --git a/crates/cheatnet/src/runtime_extensions/cheatable_starknet_runtime_extension.rs b/crates/cheatnet/src/runtime_extensions/cheatable_starknet_runtime_extension.rs index fcb37dc59c..894165a84f 100644 --- a/crates/cheatnet/src/runtime_extensions/cheatable_starknet_runtime_extension.rs +++ b/crates/cheatnet/src/runtime_extensions/cheatable_starknet_runtime_extension.rs @@ -78,6 +78,15 @@ impl<'a> ExtensionLogic for CheatableStarknetRuntimeExtension<'a> { ) .map(|()| SyscallHandlingResult::Handled), _ => Ok(SyscallHandlingResult::Forwarded), + SyscallSelector::GetBlockHash => self + .execute_syscall( + syscall_handler, + vm, + cheated_syscalls::get_block_hash_syscall, + SyscallSelector::Deploy, + ) + .map(|()| SyscallHandlingResult::Handled), + _ => Ok(SyscallHandlingResult::Forwarded), } } diff --git a/crates/cheatnet/src/state.rs b/crates/cheatnet/src/state.rs index a557ecd694..fb61466d8f 100644 --- a/crates/cheatnet/src/state.rs +++ b/crates/cheatnet/src/state.rs @@ -419,6 +419,14 @@ impl CheatnetState { ContractAddressSalt(Felt::from(self.deploy_salt_base)) } + // #[must_use] + // pub fn get_cheated_block_hash(&mut self, address: ContractAddress) -> Option { + // self.get_cheated_execution_info_for_contract(address) + // .block_info + // .block_hash + // .as_value() + // } not sure about impl this one + #[must_use] pub fn get_cheated_block_number(&mut self, address: ContractAddress) -> Option { self.get_cheated_execution_info_for_contract(address) diff --git a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker.cairo b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker.cairo index b57e27e0c4..b656d23702 100644 --- a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker.cairo +++ b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker.cairo @@ -30,14 +30,14 @@ mod CheatBlockHashChecker { impl CheatBlockHashChecker of super::ICheatBlockHashChecker { fn get_block_hash(ref self: ContractState) -> felt252 { let block_info = get_block_info().unbox(); - let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + let block_hash = get_block_hash_syscall(block_info.block_number).unwrap_syscall(); block_hash } fn get_block_hash_and_emit_event(ref self: ContractState) -> felt252 { let block_info = get_block_info().unbox(); - let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + let block_hash = get_block_hash_syscall(block_info.block_number).unwrap_syscall(); self.emit(Event::BlockHashEmitted(BlockHashEmitted { block_hash })); block_hash @@ -45,7 +45,7 @@ mod CheatBlockHashChecker { fn get_block_hash_and_number(ref self: ContractState) -> (felt252, u64) { let block_info = get_block_info().unbox(); - let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + let block_hash = get_block_hash_syscall(block_info.block_number).unwrap_syscall(); (block_hash, block_info.block_number) } diff --git a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_library_call.cairo b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_library_call.cairo index c436dc9adb..69826bb3c3 100644 --- a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_library_call.cairo +++ b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_library_call.cairo @@ -30,7 +30,7 @@ mod CheatBlockHashCheckerLibCall { fn get_block_hash(ref self: ContractState) -> felt252 { let block_info = get_block_info().unbox(); - let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + let block_hash = get_block_hash_syscall(block_info.block_number).unwrap_syscall(); block_hash } diff --git a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo index c6e7060ea8..931df0dba5 100644 --- a/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo +++ b/crates/cheatnet/tests/contracts/src/cheat_block_hash/checker_proxy.cairo @@ -36,7 +36,7 @@ mod CheatBlockHashCheckerProxy { fn get_block_hash(self: @ContractState) -> felt252 { let block_info = get_block_info().unbox(); - let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + let block_hash = get_block_hash_syscall(block_info.block_number).unwrap_syscall(); block_hash } diff --git a/crates/cheatnet/tests/contracts/src/cheat_block_hash/constructor_checker.cairo b/crates/cheatnet/tests/contracts/src/cheat_block_hash/constructor_checker.cairo index 6de195e31f..dcaa20498f 100644 --- a/crates/cheatnet/tests/contracts/src/cheat_block_hash/constructor_checker.cairo +++ b/crates/cheatnet/tests/contracts/src/cheat_block_hash/constructor_checker.cairo @@ -17,7 +17,7 @@ mod ConstructorCheatBlockHashChecker { #[constructor] fn constructor(ref self: ContractState) { let block_info = get_block_info().unbox(); - let blk_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + let blk_hash = get_block_hash_syscall(block_info.block_number).unwrap_syscall(); self.blk_hash.write(blk_hash); } @@ -31,7 +31,7 @@ mod ConstructorCheatBlockHashChecker { fn get_block_hash(ref self: ContractState) -> felt252 { let block_info = get_block_info().unbox(); - let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + let block_hash = get_block_hash_syscall(block_info.block_number).unwrap_syscall(); block_hash } diff --git a/crates/cheatnet/tests/contracts/src/starknet/blocker.cairo b/crates/cheatnet/tests/contracts/src/starknet/blocker.cairo index 42161c8b50..e6bf62bd61 100644 --- a/crates/cheatnet/tests/contracts/src/starknet/blocker.cairo +++ b/crates/cheatnet/tests/contracts/src/starknet/blocker.cairo @@ -33,7 +33,7 @@ mod Blocker { self.block_timestamp.write(block_info.block_timestamp); self.sequencer_address.write(block_info.sequencer_address); - let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + let block_hash = get_block_hash_syscall(block_info.block_number).unwrap_syscall(); self.block_hash.write(block_hash); } diff --git a/crates/forge/tests/data/contracts/block_hash_checker.cairo b/crates/forge/tests/data/contracts/block_hash_checker.cairo index 80d02f81b7..b82fea5671 100644 --- a/crates/forge/tests/data/contracts/block_hash_checker.cairo +++ b/crates/forge/tests/data/contracts/block_hash_checker.cairo @@ -24,7 +24,7 @@ mod BlockHashChecker { fn write_block(ref self: ContractState) { let block_info = get_block_info().unbox(); - let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + let block_hash = get_block_hash_syscall(block_info.block_number).unwrap_syscall(); self.block_hash.write(block_hash); } diff --git a/crates/forge/tests/data/contracts/cheat_block_hash_checker.cairo b/crates/forge/tests/data/contracts/cheat_block_hash_checker.cairo index 7a65b5abad..d486f7cb04 100644 --- a/crates/forge/tests/data/contracts/cheat_block_hash_checker.cairo +++ b/crates/forge/tests/data/contracts/cheat_block_hash_checker.cairo @@ -30,14 +30,14 @@ mod CheatBlockHashChecker { impl CheatBlockHashChecker of super::ICheatBlockHashChecker { fn get_block_hash(ref self: ContractState) -> felt252 { let block_info = get_block_info().unbox(); - let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + let block_hash = get_block_hash_syscall(block_info.block_number).unwrap_syscall(); block_hash } fn get_block_hash_and_emit_event(ref self: ContractState) -> felt252 { let block_info = get_block_info().unbox(); - let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + let block_hash = get_block_hash_syscall(block_info.block_number).unwrap_syscall(); self.emit(Event::BlockHashEmitted(BlockHashEmitted { block_hash })); block_hash @@ -45,7 +45,7 @@ mod CheatBlockHashChecker { fn get_block_hash_and_number(ref self: ContractState) -> (felt252, u64) { let block_info = starknet::get_block_info().unbox(); - let block_hash = get_block_hash_syscall(block_info.block_number - 10).unwrap_syscall(); + let block_hash = get_block_hash_syscall(block_info.block_number).unwrap_syscall(); (block_hash, block_info.block_number) } diff --git a/crates/forge/tests/integration/test_state.rs b/crates/forge/tests/integration/test_state.rs index 5b39c4e42f..015b7a0a54 100644 --- a/crates/forge/tests/integration/test_state.rs +++ b/crates/forge/tests/integration/test_state.rs @@ -320,7 +320,7 @@ fn get_block_hash() { #[test] fn get_block_hash() { let block_info = get_block_info().unbox(); - let hash = get_block_hash_syscall(block_info.block_number - 10).unwrap(); + let hash = get_block_hash_syscall(block_info.block_number.unwrap(); assert(hash == 0, 'Hash not zero'); } " From 8b75ef50652a990065ac77f7c2d8501cfaa67863 Mon Sep 17 00:00:00 2001 From: Pedro Rosalba Date: Wed, 4 Dec 2024 16:07:52 -0300 Subject: [PATCH 14/17] updating. should I get the contractAddress from the cheated block number? if so, how? --- .../execution/cheated_syscalls.rs | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/execution/cheated_syscalls.rs b/crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/execution/cheated_syscalls.rs index c82d9360b4..033ccf2813 100644 --- a/crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/execution/cheated_syscalls.rs +++ b/crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/execution/cheated_syscalls.rs @@ -1,3 +1,19 @@ +use crate::abi::constants; +use self::hint_processor::{ + create_retdata_segment, + execute_inner_call, + execute_library_call, + felt_to_bool, + read_call_params, + read_calldata, + read_felt_array, + write_segment, + EmitEventError, + SyscallExecutionError, + SyscallHintProcessor, + BLOCK_NUMBER_OUT_OF_RANGE_ERROR, +}; + use crate::runtime_extensions::call_to_blockifier_runtime_extension::execution::entry_point::execute_constructor_entry_point; use crate::runtime_extensions::call_to_blockifier_runtime_extension::CheatnetState; use blockifier::execution::syscalls::hint_processor::SyscallHintProcessor; @@ -65,15 +81,30 @@ pub fn get_block_hash_syscall( _remaining_gas: &mut u64, ) -> SyscallResult { - let execution_info_ptr = syscall_handler.get_or_allocate_execution_info_segment(vm)?; + // let execution_info_ptr = syscall_handler.get_or_allocate_execution_info_segment(vm)?; - let cheated_data = cheatnet_state.get_cheated_data(syscall_handler.storage_address()); + // let cheated_data = cheatnet_state.get_cheated_data(syscall_handler.storage_address()); + + // let ptr_cheated_block_info = get_cheated_block_info_ptr(vm, execution_info_ptr, &cheated_data); + + let cheated_block_number = cheatnet_state.block_info.block_number; + + let requested_block_number = request.block_number; + + if cheated_block_number < constants::STORED_BLOCK_HASH_BUFFER + || requested_block_number > cheated_block_number - constants::STORED_BLOCK_HASH_BUFFER + { + let out_of_range_error = + Felt::from_hex(BLOCK_NUMBER_OUT_OF_RANGE_ERROR).map_err(SyscallExecutionError::from)?; + return Err(SyscallExecutionError::SyscallError { error_data: vec![out_of_range_error] }); + } + + let key = StorageKey::try_from(Felt::from(requested_block_number))?; - let ptr_cheated_block_info = get_cheated_block_info_ptr(vm, execution_info_ptr, &cheated_data); + let block_hash_contract_address = + ContractAddress::try_from(Felt::from(constants::BLOCK_HASH_CONTRACT_ADDRESS))?; - //TODO: how to get the cheated block number using the ptr_cheated_block_info? - //why is the get_cheated_block_info not public? - //why is BlockHash not public? + //should I get the contractAddress from the cheated block number? how do I do that? let cheated_block_hash = BlockHash(syscall_handler.state.get_storage_at(block_hash_contract_address, key)?); From 634bb446495b8653b6cbbd23f4cd605882750442 Mon Sep 17 00:00:00 2001 From: Pedro Rosalba Date: Fri, 13 Dec 2024 12:00:27 -0300 Subject: [PATCH 15/17] updating --- .../cheatcodes/cheat_execution_info.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_execution_info.rs b/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_execution_info.rs index 70e90e7c8f..ff760943de 100644 --- a/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_execution_info.rs +++ b/crates/cheatnet/src/runtime_extensions/forge_runtime_extension/cheatcodes/cheat_execution_info.rs @@ -2,7 +2,6 @@ use crate::{ state::{CheatSpan, CheatStatus}, CheatnetState, }; -use cairo_vm::Felt252; use conversions::serde::{deserialize::CairoDeserialize, serialize::CairoSerialize}; use starknet_api::core::ContractAddress; use starknet_types_core::felt::Felt; @@ -52,7 +51,6 @@ pub struct TxInfoMock { pub struct BlockInfoMock { pub block_number: CheatStatus, pub block_timestamp: CheatStatus, - pub block_hash: CheatStatus, pub sequencer_address: CheatStatus, } @@ -84,7 +82,6 @@ pub struct TxInfoMockOperations { pub struct BlockInfoMockOperations { pub block_number: Operation, pub block_timestamp: Operation, - pub block_hash: Operation, pub sequencer_address: Operation, } @@ -101,7 +98,6 @@ macro_rules! for_all_fields { $macro!(block_info.block_number); $macro!(block_info.block_timestamp); - $macro!(block_info.block_hash); $macro!(block_info.sequencer_address); $macro!(tx_info.version); @@ -182,4 +178,4 @@ impl CheatnetState { for_all_fields!(decrement!); } -} +} \ No newline at end of file From cb477c1e706c2e1580214f4beb2701fe2e33f9fc Mon Sep 17 00:00:00 2001 From: kkawula <57270771+kkawula@users.noreply.github.com> Date: Fri, 20 Dec 2024 16:24:27 +0100 Subject: [PATCH 16/17] Apply suggestions from code review --- .../src/cheatcodes/execution_info/block_hash.cairo | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/snforge_std/src/cheatcodes/execution_info/block_hash.cairo b/snforge_std/src/cheatcodes/execution_info/block_hash.cairo index 3d0d078abe..3d887efab4 100644 --- a/snforge_std/src/cheatcodes/execution_info/block_hash.cairo +++ b/snforge_std/src/cheatcodes/execution_info/block_hash.cairo @@ -7,7 +7,7 @@ use super::{ /// - `block_hash` - block hash to be set /// - `span` - instance of `CheatSpan` specifying the hash of contract calls with the cheat /// applied -fn cheat_block_hash(contract_address: ContractAddress, block_hash: felt252, span: CheatSpan) { +pub fn cheat_block_hash(contract_address: ContractAddress, block_hash: felt252, span: CheatSpan) { let mut execution_info: ExecutionInfoMock = Default::default(); execution_info @@ -20,7 +20,7 @@ fn cheat_block_hash(contract_address: ContractAddress, block_hash: felt252, span /// Changes the block hash. /// - `block_hash` - block hash to be set -fn start_cheat_block_hash_global(block_hash: felt252) { +pub fn start_cheat_block_hash_global(block_hash: felt252) { let mut execution_info: ExecutionInfoMock = Default::default(); execution_info.block_info.block_hash = Operation::StartGlobal(block_hash); @@ -29,7 +29,7 @@ fn start_cheat_block_hash_global(block_hash: felt252) { } /// Cancels the `start_cheat_block_hash_global`. -fn stop_cheat_block_hash_global() { +pub fn stop_cheat_block_hash_global() { let mut execution_info: ExecutionInfoMock = Default::default(); execution_info.block_info.block_hash = Operation::StopGlobal; @@ -40,13 +40,13 @@ fn stop_cheat_block_hash_global() { /// Changes the block hash for the given contract_address. /// - `contract_address` - instance of `ContractAddress` specifying which contract to cheat /// - `block_hash` - block hash to be set -fn start_cheat_block_hash(contract_address: ContractAddress, block_hash: felt252) { +pub fn start_cheat_block_hash(contract_address: ContractAddress, block_hash: felt252) { cheat_block_hash(contract_address, block_hash, CheatSpan::Indefinite); } /// Cancels the `cheat_block_hash` / `start_cheat_block_hash` for the given contract_address. /// - `contract_address` - instance of `ContractAddress` specifying which contract to stop cheating -fn stop_cheat_block_hash(contract_address: ContractAddress) { +pub fn stop_cheat_block_hash(contract_address: ContractAddress) { let mut execution_info: ExecutionInfoMock = Default::default(); execution_info.block_info.block_hash = Operation::Stop(contract_address); From 9d48bb06f1ee9422db10878856640c6b27cea6f4 Mon Sep 17 00:00:00 2001 From: Pedro Rosalba Date: Wed, 8 Jan 2025 19:39:23 -0300 Subject: [PATCH 17/17] updating --- .gitignore | 3 +-- .tool-versions | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 11ad7f9e76..5955faea55 100644 --- a/.gitignore +++ b/.gitignore @@ -15,5 +15,4 @@ Scarb.lock snfoundry_trace/ coverage/ **/.forge_e2e_cache/ -.cargo/ -.rustup/ + diff --git a/.tool-versions b/.tool-versions index ff54753330..4b769bfe06 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -scarb 2.8.4 +scarb 2.7.0 \ No newline at end of file