Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cheatcode for getting hash of the block #2648

Open
wants to merge 16 commits into
base: master
Choose a base branch
from

Conversation

PedroRosalba
Copy link

@PedroRosalba PedroRosalba commented Nov 6, 2024

Closes #684

Introduced changes

Checklist

  • Linked relevant issue
  • Updated relevant documentation
  • Added relevant tests
  • Performed self-review of the code
  • Added changes to CHANGELOG.md

Copy link
Collaborator

@kkawula kkawula left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @PedroRosalba, unfortunately, your solution isn't proper.
Please study other pr's that introduce cheatcode e.g. #2634 or many other you can find in our repo history.
Your solution should contain:

  • cheatcode implementation
  • entry in snfoundry_std
  • e2e tests (on cairo side)
  • documentation

@kkawula
Copy link
Collaborator

kkawula commented Nov 7, 2024

Hints for development:

  • run cargo test e2e to test locally
  • run cargo lint to check stylistic errors or deviations from a coding standard
  • run cargo fmt to format your code

If your tests pass, please submit your PR as ready to review.
Good luck!

@kkawula kkawula marked this pull request as draft November 7, 2024 08:35
@PedroRosalba PedroRosalba marked this pull request as ready for review November 8, 2024 02:49
@PedroRosalba
Copy link
Author

hey, can you review for some feedback? unfortunately I could not test the code (my computer even with no other tasks running cannot run cargo test e2e). sorry for the inconvenience. looking forward to continue working on this. sorry again.

@PedroRosalba
Copy link
Author

Do I have to deploy the contracts manually or smth like that? in the tests of CheatBlockHashChecker, I am getting an error that
---- cheatcodes::cheat_block_hash::cheat_block_hash_simple stdout ----
thread 'cheatcodes::cheat_block_hash::cheat_block_hash_simple' panicked at crates/cheatnet/tests/common/mod.rs:95:10:
called Result::unwrap() on an Err value: Unrecoverable(Anyhow(Failed to get contract artifact for name = CheatBlockHashChecker.

it is unable to find the contract.

@PedroRosalba
Copy link
Author

I have another question, is it allowed to 'request' changes in core lib files?

//I thought of creating an attribute block_hash in get_block_info using the

// pub extern fn get_block_hash_syscall(
// block_number: u64
// ) -> SyscallResult implicits(GasBuiltin, System) nopanic;

// //Is this allowed? Modifiying the core lib

for example this.

@PedroRosalba
Copy link
Author

failures:
e2e::build_profile::simple_package_build_profile
e2e::build_profile::simple_package_build_profile_and_pass_args
e2e::running::simple_package_with_git_dependency
e2e::steps::should_allow_more_than_10m

Hey, the only tests that I am getting errors are these, which are files that I havent modified (and I guess I should not, also). Do you have any ideas of why?

@PedroRosalba
Copy link
Author

Hey, mind reviewing for the feedback? Sorry for the inconvenience again.

@PedroRosalba
Copy link
Author

Hey, I don't understand the log of the errors.

In scarb fmt, it says Scarb.lock can't be find. Do you know why?

---- cheatcodes::cheat_block_hash::cheat_block_hash_simple stdout ----
thread 'cheatcodes::cheat_block_hash::cheat_block_hash_simple' panicked at crates/cheatnet/tests/common/mod.rs:95:10:
called Result::unwrap() on an Err value: Unrecoverable(Anyhow(Failed to get contract artifact for name = CheatBlockHashChecker.

In this second error, it is unable to find the contract. As I have already asked, is it necessary to declare or deploy these contracts separately?

@kkawula
Copy link
Collaborator

kkawula commented Nov 12, 2024

Hi! I will take a look today!

@PedroRosalba
Copy link
Author

alright, now I ran the scarbfmt scripts, things should be working properly. looking forward to the feedback, thx.

Copy link
Collaborator

@kkawula kkawula left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty good job so far! We are almost done.

  1. Add an entry to CHANGELOG.md
  2. In this Unify Felt usage #2655 pr, we unified felts in the entire repo, that's why some of your tests are failing, please replace it

@PedroRosalba
Copy link
Author

alright now I believe its pretty done

@kkawula
Copy link
Collaborator

kkawula commented Nov 13, 2024

Are your questions still blocking?

Copy link
Collaborator

@kkawula kkawula left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests are failing, because you didn't add the entry into lib.cairo -> crates/cheatnet/tests/contracts/src/lib.cairo
Please format the code before committing :))

Copy link
Collaborator

@kkawula kkawula left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are still some tests failing, could you take a look at it?

Copy link
Member

@cptartur cptartur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take a look at failing tests below. Seems there's a problem with some cairo code introduced as well as with rust.

@PedroRosalba
Copy link
Author

I'm trying to figure out what is failing. Still didn't. Sorry for late response.

@PedroRosalba
Copy link
Author

I can't understand why only some of the tests from the file crates/forge/tests/integration/cheat_block_hash.rs are failing and not all of them. I can't see issues w the code

@PedroRosalba
Copy link
Author

PedroRosalba commented Nov 14, 2024

Failure data:
0x57726f6e6720626c6f636b2068617368202331 ('Wrong block hash #1')

This is the output referent to the code

#[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');

why is it outputting this random address?


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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PedroRosalba Is there a reason block_number - 10 is used here? I think that's what causing problems, you're not checking the block hash of this block but 10 blocks in the past.

@PedroRosalba
Copy link
Author

I don't believe that is the issue. Took off this -10 and got this error

  • Executing task: cargo test --package forge --test main -- integration::cheat_block_hash::cheat_block_hash_complex --exact --show-output

    Finished test profile [unoptimized + debuginfo] target(s) in 1.65s
    Running tests/main.rs (target/debug/deps/main-700b4c329e997377)

running 1 test
Compiling snforge_scarb_plugin v0.33.1 (/home/pedrorosalba/For-Pull-Requests/starknet-foundry/crates/snforge-scarb-plugin/Scarb.toml)
Finished release profile [optimized] target(s) in 0.53s
Compiling test(test_package_unittest) test_package v0.1.0 (/tmp/.tmpenqdzd/Scarb.toml)
Compiling test(test_package_integrationtest) test_package_integrationtest v0.1.0 (/tmp/.tmpenqdzd/Scarb.toml)
warn: external contracts not found for selectors: test_package::*
Finished dev profile target(s) in 24 seconds
Compiling contract v0.1.0 (/tmp/.tmpN4ViUx/Scarb.toml)
Finished dev profile target(s) in 9 seconds
test integration::cheat_block_hash::cheat_block_hash_complex ... FAILED

successes:

successes:

failures:

---- integration::cheat_block_hash::cheat_block_hash_complex stdout ----

Collected 1 test(s) from test_package package
Running 0 test(s) from src/
Running 1 test(s) from tests/
[FAIL] test_package_integrationtest::test_case::cheat_block_hash_complex

Failure data:
0x426c6f636b206e756d626572206f7574206f662072616e6765 ('Block number out of range')

Tests: 0 passed, 1 failed, 0 skipped, 0 ignored, 0 filtered out
thread 'integration::cheat_block_hash::cheat_block_hash_complex' panicked at crates/forge/test_utils/src/runner.rs:241:5:
Some tests didn't pass
stack backtrace:
0: rust_begin_unwind
at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/std/src/panicking.rs:662:5
1: core::panicking::panic_fmt
at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/panicking.rs:74:14
2: test_utils::runner::assert_passed
at ./test_utils/src/runner.rs:241:5
3: main::integration::cheat_block_hash::cheat_block_hash_complex
at ./tests/integration/cheat_block_hash.rs:226:5
4: main::integration::cheat_block_hash::cheat_block_hash_complex::{{closure}}
at ./tests/integration/cheat_block_hash.rs:144:30
5: core::ops::function::FnOnce::call_once
at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/ops/function.rs:250:5
6: core::ops::function::FnOnce::call_once
at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with RUST_BACKTRACE=full for a verbose backtrace.

failures:
integration::cheat_block_hash::cheat_block_hash_complex

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 276 filtered out; finished in 39.45s

error: test failed, to rerun pass -p forge --test main

  • The terminal process "cargo 'test', '--package', 'forge', '--test', 'main', '--', 'integration::cheat_block_hash::cheat_block_hash_complex', '--exact', '--show-output'" terminated with exit code: 101.
  • Terminal will be reused by tasks, press any key to close it.

This -10 was being used in a similar context before I started working on this pull request, so I just followed this pattern. And as you can see I don't think thats the issue.

@cptartur
Copy link
Member

@PedroRosalba Verified this in depth:

current block - 10 in syscall is okay, it won't work with more recent ones according to docs https://docs.starknet.io/architecture-and-concepts/smart-contracts/system-calls-cairo1/#get_block_hash

However, the code you wrote is changing the block execution info that is fetched by the block execution info syscall however you want to change the result of get_block_hash syscall. So this changes won't work

You have to match this selector here

and add new logic to cheated_syscalls.rs that is handling it similarly to how other cheated syscalls work.

@PedroRosalba
Copy link
Author

Sorry, I did not understand the issue.

pub fn get_block_hash(
request: GetBlockHashRequest,
vm: &mut VirtualMachine,
syscall_handler: &mut SyscallHintProcessor<'
>,
_remaining_gas: &mut u64,
) -> SyscallResult {
if syscall_handler.is_validate_mode() {
return Err(SyscallExecutionError::InvalidSyscallInExecutionMode {
syscall_name: "get_block_hash".to_string(),
execution_mode: syscall_handler.execution_mode(),
});
}

let requested_block_number = request.block_number.0;
let current_block_number =
    syscall_handler.context.tx_context.block_context.block_info.block_number.0;

if current_block_number < constants::STORED_BLOCK_HASH_BUFFER
    || requested_block_number > current_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 block_hash_contract_address =
    ContractAddress::try_from(Felt::from(constants::BLOCK_HASH_CONTRACT_ADDRESS))?;
let block_hash =
    BlockHash(syscall_handler.state.get_storage_at(block_hash_contract_address, key)?);
Ok(GetBlockHashResponse { block_hash })

}

this is the impl of the function get_block_hash. see it is calling the correct get_block_hash. furthemrore the implementations of the funciton get_block_hash that I created all utilize the get_block_hash_syscall, which is the function that u use with the -10; and not the block execution info, as you described. So I did not understand, can you explain in a lil more details?

@PedroRosalba
Copy link
Author

basically I need to create a get_block_hash_syscall function inside this cheated_syscalls.rs file? and then add the correspondent logic to the match selector? but why do I need to do that if my functions get_block_hash are all defined to call get_block_hash_syscall ? that is what I am not understanding very well

@PedroRosalba
Copy link
Author

Don't know if I got it: the thing is, to get the block hash, I need to get the block number, and for that, I need to access the function get_block_info, which is implemented via the block execution info syscall. What I got from what u said is that I need to define my function to get the block hash differently, without utilizing the block info execution syscall; instead use the get block hash syscall. but to use the block hash syscall I need to have the block number, which I get from the block info execution syscall, so I need to use it anyways. Where am I misunderstanding?

@cptartur
Copy link
Member

Don't know if I got it: the thing is, to get the block hash, I need to get the block number, and for that, I need to access the function get_block_info, which is implemented via the block execution info syscall. What I got from what u said is that I need to define my function to get the block hash differently, without utilizing the block info execution syscall; instead use the get block hash syscall. but to use the block hash syscall I need to have the block number, which I get from the block info execution syscall, so I need to use it anyways. Where am I misunderstanding?

@PedroRosalba You can still use the block execution info syscall in Cairo tests to get the block number first.

The problem is that in your implementation, you are changing the block hash stored in execution info. However, to check the hash of the block, you need to call the get_block_hash_syscall which is a different syscall.

That's why, even though you change the block hash in execution info, the get_block_hash_syscall doesn't know anything about the change and is returning the original (not cheated) block hash.
This is what is causing the tests to fail.

For the result of the get_block_hash_syscall to change, you need to create the logic for cheating it as I've outlined in my previous message.

@cptartur
Copy link
Member

In the cheatable_starknet_runtime_extension.rs, take a look at code match selector.

The get_block_info calls get_execution_info syscall under the hood:
https://github.com/starkware-libs/cairo/blob/1d9c6645f0e953fc12f28e7cbfa6efa3a7f38492/corelib/src/starknet/info.cairo#L81C8-L81C22

We handle this syscall in SyscallSelector::GetExecutionInfo case we handle this syscall and insert our cheated data into it.
However, in case of GetBlockHash we do not handle it and instead default implementation is used. This one doesn't have our cheated data so if you call get_block_hash_syscall you will still get the original hash, not the cheated one.

@kkawula
Copy link
Collaborator

kkawula commented Nov 26, 2024

HI @PedroRosalba any updates here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cheatcode mocking get_block_hash_syscall
3 participants