Skip to content

Commit

Permalink
feat(forge): Implement vm.Sleep (#5519)
Browse files Browse the repository at this point in the history
* implement vm sleep

* forge fmt

* remove println
  • Loading branch information
pistomat authored Aug 4, 2023
1 parent 2d87c0c commit 8d1dd30
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 0 deletions.
2 changes: 2 additions & 0 deletions abi/abi/HEVM.sol
Original file line number Diff line number Diff line change
Expand Up @@ -217,3 +217,5 @@ stopMappingRecording()
getMappingLength(address,bytes32)
getMappingSlotAt(address,bytes32,uint256)
getMappingKeyAndParentOf(address,bytes32)

sleep(uint256)
52 changes: 52 additions & 0 deletions abi/src/bindings/hevm.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions evm/src/executor/inspector/cheatcodes/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,14 @@ fn key_exists(json_str: &str, key: &str) -> Result {
Ok(exists)
}

/// Sleeps for a given amount of milliseconds.
fn sleep(milliseconds: &U256) -> Result {
let sleep_duration = std::time::Duration::from_millis(milliseconds.as_u64());
std::thread::sleep(sleep_duration);

Ok(Default::default())
}

#[instrument(level = "error", name = "ext", target = "evm::cheatcodes", skip_all)]
pub fn apply(state: &mut Cheatcodes, call: &HEVMCalls) -> Option<Result> {
Some(match call {
Expand Down Expand Up @@ -592,6 +600,7 @@ pub fn apply(state: &mut Cheatcodes, call: &HEVMCalls) -> Option<Result> {
HEVMCalls::SerializeBytes1(inner) => {
serialize_json(state, &inner.0, &inner.1, &array_str_to_str(&inner.2))
}
HEVMCalls::Sleep(inner) => sleep(&inner.0),
HEVMCalls::WriteJson0(inner) => write_json(state, &inner.0, &inner.1, None),
HEVMCalls::WriteJson1(inner) => write_json(state, &inner.0, &inner.1, Some(&inner.2)),
HEVMCalls::KeyExists(inner) => key_exists(&inner.0, &inner.1),
Expand Down
51 changes: 51 additions & 0 deletions testdata/cheats/Sleep.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.18;

import "ds-test/test.sol";
import "./Vm.sol";

contract SleepTest is DSTest {
Vm constant vm = Vm(HEVM_ADDRESS);

function testSleep() public {
uint256 milliseconds = 1234;

string[] memory inputs = new string[](2);
inputs[0] = "date";
// OS X does not support precision more than 1 second
inputs[1] = "+%s000";

bytes memory res = vm.ffi(inputs);
uint256 start = vm.parseUint(string(res));

vm.sleep(milliseconds);

res = vm.ffi(inputs);
uint256 end = vm.parseUint(string(res));

// Limit precision to 1000 ms
assertGe(end - start, milliseconds / 1000 * 1000, "sleep failed");
}

/// forge-config: default.fuzz.runs = 10
function testSleepFuzzed(uint256 _milliseconds) public {
// Limit sleep time to 2 seconds to decrease test time
uint256 milliseconds = _milliseconds % 2000;

string[] memory inputs = new string[](2);
inputs[0] = "date";
// OS X does not support precision more than 1 second
inputs[1] = "+%s000";

bytes memory res = vm.ffi(inputs);
uint256 start = vm.parseUint(string(res));

vm.sleep(milliseconds);

res = vm.ffi(inputs);
uint256 end = vm.parseUint(string(res));

// Limit precision to 1000 ms
assertGe(end - start, milliseconds / 1000 * 1000, "sleep failed");
}
}
3 changes: 3 additions & 0 deletions testdata/cheats/Vm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ interface Vm {
// Skips a test.
function skip(bool) external;

// Sleeps for a given number of milliseconds.
function sleep(uint256) external;

// Expects an error on next call
function expectRevert() external;

Expand Down

0 comments on commit 8d1dd30

Please sign in to comment.