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

bug(cheatcodes): slot of contract with arbitrary storage set to 0 in setUp, but goes back to being arbitrary in the test #10108

Closed
2 tasks done
lucasmt opened this issue Mar 18, 2025 · 1 comment
Labels
A-cheatcodes Area: cheatcodes T-bug Type: bug T-to-investigate Type: to investigate

Comments

@lucasmt
Copy link

lucasmt commented Mar 18, 2025

Component

Forge

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

  • Foundry
  • Foundryup

What version of Foundry are you on?

forge Version: 1.0.0-stable
Commit SHA: e144b82
Build Timestamp: 2025-02-13T20:03:31.026474817Z (1739477011)
Build Profile: maxperf

What version of Foundryup are you on?

foundryup: 1.0.1

What command(s) is the bug in?

forge test

Operating System

Linux

Describe the bug

Copied from foundry-rs/forge-std#667

I'm trying to write a setUp function that first uses the setArbitraryStorage cheatcode to make the storage of a contract arbitrary, then uses store to set a single storage slot to 0. This seems to work inside the setUp, but when the test itself is executed, the value of the storage slot goes back to being a random number. This seems to only happen when the value is 0.

Minimal Example

pragma solidity ^0.8.25;

import "../lib/forge-std/src/Test.sol";

contract StorageContract {
    uint256 public value;
}

contract ArbitraryStorageTest is Test {
    uint256 constant DEFAULT_VALUE = 0;

    StorageContract target;

    function setUp() public {
        target = new StorageContract();
        vm.setArbitraryStorage(address(target));

        bytes32 valueSlot = bytes32(uint256(0));
        vm.store(address(target), valueSlot, bytes32(DEFAULT_VALUE));
        emit log_named_uint("value in setUp", target.value());
    }

    function test_stored_value() public {
        emit log_named_uint("value in test", target.value());

        assertEq(target.value(), DEFAULT_VALUE);
    }
}

The test fails and this is what the logs show:

[FAIL: assertion failed: 36440280036344177981963967840477496355477405577495123809133350823800994840471 != 0] test_stored_value() (gas: 10093)
Logs:
  value in setUp: 0
  value in test: 36440280036344177981963967840477496355477405577495123809133350823800994840471

However, if DEFAULT_VALUE is changed to 1, the result is correct:

[PASS] test_stored_value() (gas: 10090)
Logs:
  value in setUp: 1
  value in test: 1
@lucasmt lucasmt added T-bug Type: bug T-needs-triage Type: this issue needs to be labelled labels Mar 18, 2025
@github-project-automation github-project-automation bot moved this to Todo in Foundry Mar 18, 2025
@zerosnacks zerosnacks added A-cheatcodes Area: cheatcodes and removed T-needs-triage Type: this issue needs to be labelled labels Mar 18, 2025
@zerosnacks zerosnacks changed the title Slot of contract with arbitrary storage set to 0 in setUp, but goes back to being arbitrary in the test bug(cheatcodes): slot of contract with arbitrary storage set to 0 in setUp, but goes back to being arbitrary in the test Mar 18, 2025
@zerosnacks zerosnacks added the T-to-investigate Type: to investigate label Mar 18, 2025
@grandizzy
Copy link
Collaborator

@lucasmt thanks for your report. Indeed, how this works is that we generate random value if storage is cold and data is zero. Since the storage is set in setup (different tx) then in test tx the storage is cold and zero, so a new random is generated (for default value set to 1 we can figure out it was changed in a prev tx and not overwrite as the value != 0). What you could do is move the vm.store call in an internal function and call it in your tests, something like

contract ArbitraryStorageTest is Test {
    uint256 constant DEFAULT_VALUE = 0;

    StorageContract target;

    function _setMyTest() internal {
        target = new StorageContract();
        vm.setArbitraryStorage(address(target));

        bytes32 valueSlot = bytes32(uint256(0));
        vm.store(address(target), valueSlot, bytes32(DEFAULT_VALUE));
        emit log_named_uint("value in setUp", target.value());
    }

    function test_stored_value() public {
        _setMyTest();
        emit log_named_uint("value in test", target.value());

        assertEq(target.value(), DEFAULT_VALUE);
    }
}

Hope this helps, please reopen otherwise. Thank you!

@grandizzy grandizzy closed this as not planned Won't fix, can't repro, duplicate, stale Mar 19, 2025
@github-project-automation github-project-automation bot moved this from Todo to Done in Foundry Mar 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-cheatcodes Area: cheatcodes T-bug Type: bug T-to-investigate Type: to investigate
Projects
Status: Done
Development

No branches or pull requests

3 participants