Skip to content

blockhash returns zero value if rolled beyond type(uint64).max value #10367

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

Open
2 tasks done
pcaversaccio opened this issue Apr 24, 2025 · 2 comments
Open
2 tasks done
Labels
T-bug Type: bug T-needs-triage Type: this issue needs to be labelled

Comments

@pcaversaccio
Copy link
Contributor

pcaversaccio commented Apr 24, 2025

Component

Forge

Have you ensured that all of these are up to date?

  • Foundry
  • Foundryup

What version of Foundry are you on?

55802bad5f9068d969df4273b5c2a960332e8e42

What version of Foundryup are you on?

1.0.1

What command(s) is the bug in?

No response

Operating System

Linux

Describe the bug

// SPDX-License-Identifier: WTFPL
pragma solidity ^0.8.29;

import {Test} from "forge-std/Test.sol";

contract SimpleTest is Test {
    function testBlockHashSimple() public {
        vm.roll(type(uint72).max); // If you replace this with `vm.roll(type(uint64).max);` (or below) it will work properly.
        uint256 blockNumber = vm.getBlockNumber() - 1;
        vm.setBlockhash(blockNumber, keccak256("vyper"));
        emit log_bytes32(blockhash(blockNumber));
    }
}
Logs:
  0x0000000000000000000000000000000000000000000000000000000000000000

Traces:
  [4964] SimpleTest::testBlockHashSimple()
    ├─ [0] VM::roll(4722366482869645213695 [4.722e21])
    │   └─ ← [Return]
    ├─ [0] VM::getBlockNumber() [staticcall]
    │   └─ ← [Return] 4722366482869645213695 [4.722e21]
    ├─ [0] VM::setBlockhash(4722366482869645213694 [4.722e21], 0xcde04c9d98738375f7f1bbf067b84e35f9327a84c3d709815de017a16d090c11)
    │   └─ ← [Return]
    ├─ emit log_bytes32(val: 0x0000000000000000000000000000000000000000000000000000000000000000)
    └─ ← [Stop]

The correct output should be:

[PASS] testBlockHashSimple() (gas: 4964)
Logs:
  0xcde04c9d98738375f7f1bbf067b84e35f9327a84c3d709815de017a16d090c11

Traces:
  [4964] SimpleTest::testBlockHashSimple()
    ├─ [0] VM::roll(18446744073709551615 [1.844e19])
    │   └─ ← [Return]
    ├─ [0] VM::getBlockNumber() [staticcall]
    │   └─ ← [Return] 18446744073709551615 [1.844e19]
    ├─ [0] VM::setBlockhash(18446744073709551614 [1.844e19], 0xcde04c9d98738375f7f1bbf067b84e35f9327a84c3d709815de017a16d090c11)
    │   └─ ← [Return]
    ├─ emit log_bytes32(val: 0xcde04c9d98738375f7f1bbf067b84e35f9327a84c3d709815de017a16d090c11)
    └─ ← [Stop]
@pcaversaccio pcaversaccio added T-bug Type: bug T-needs-triage Type: this issue needs to be labelled labels Apr 24, 2025
@github-project-automation github-project-automation bot moved this to Backlog in Foundry Apr 24, 2025
@pcaversaccio
Copy link
Contributor Author

pcaversaccio commented Apr 25, 2025

So this happens because revm internally uses a saturated conversion from U256 to u64 for the block number in the block_hash function (see as_u64_saturated!). So if both env.block.number and the requested block number are ≥ u64::MAX, they get clamped to u64::MAX. This causes requested_number >= block_number to evaluate true, which triggers an early return of U256::ZERO without querying the DB. As a result, even though the original U256 values may differ, revm treats them as equal at the u64 level. To avoid this, it's safer for now to work with u64 block numbers when interacting with block_hash().

@pcaversaccio
Copy link
Contributor Author

@grandizzy @DaniPopes I think Foundry should raise an informative error if 2**64-1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-bug Type: bug T-needs-triage Type: this issue needs to be labelled
Projects
Status: Backlog
Development

No branches or pull requests

1 participant