Skip to content

Commit

Permalink
Merge branch 'main' into fix-jrigada-script-not-failing-when-no-fork-url
Browse files Browse the repository at this point in the history
  • Loading branch information
Jrigada authored Sep 23, 2024
2 parents e4588b2 + e2e2d57 commit 70a95b1
Show file tree
Hide file tree
Showing 15 changed files with 294 additions and 56 deletions.
43 changes: 22 additions & 21 deletions .github/workflows/bump-forge-std.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
# Daily CI job to update forge-std version used for tests if new release has been published
# Disabled as we update it via upstream sync or manually

name: bump-forge-std
# name: bump-forge-std

on:
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
# on:
# schedule:
# - cron: "0 0 * * *"
# workflow_dispatch:

jobs:
update-tag:
name: update forge-std tag
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Fetch and update forge-std tag
run: curl 'https://api.github.com/repos/foundry-rs/forge-std/tags' | jq '.[0].commit.sha' -jr > testdata/forge-std-rev
- name: Create pull request
uses: peter-evans/create-pull-request@v5
with:
commit-message: "chore: bump forge-std version used for tests"
title: "chore(tests): bump forge-std version"
body: |
New release of forge-std has been published, bump forge-std version used in tests. Likely some fixtures need to be updated.
branch: chore/bump-forge-std
# jobs:
# update-tag:
# name: update forge-std tag
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - name: Fetch and update forge-std tag
# run: curl 'https://api.github.com/repos/foundry-rs/forge-std/tags' | jq '.[0].commit.sha' -jr > testdata/forge-std-rev
# - name: Create pull request
# uses: peter-evans/create-pull-request@v5
# with:
# commit-message: "chore: bump forge-std version used for tests"
# title: "chore(tests): bump forge-std version"
# body: |
# New release of forge-std has been published, bump forge-std version used in tests. Likely some fixtures need to be updated.
# branch: chore/bump-forge-std
18 changes: 12 additions & 6 deletions crates/cheatcodes/src/inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ use revm::{
},
primitives::{
AccountInfo, BlockEnv, Bytecode, CreateScheme, EVMError, Env, EvmStorageSlot,
ExecutionResult, HashMap as rHashMap, Output, TransactTo, KECCAK_EMPTY,
ExecutionResult, HashMap as rHashMap, Output, KECCAK_EMPTY,
},
EvmContext, InnerEvmContext, Inspector,
};
Expand Down Expand Up @@ -1547,11 +1547,17 @@ impl Cheatcodes {
return None;
}

if let TransactTo::Call(test_contract) = ecx.env.tx.transact_to {
if call.bytecode_address == test_contract {
info!("running call in EVM, instead of zkEVM (Test Contract) {:#?}", ecx.env.tx);
return None
}
if ecx
.db
.get_test_contract_address()
.map(|addr| call.bytecode_address == addr)
.unwrap_or_default()
{
info!(
"running call in EVM, instead of zkEVM (Test Contract) {:#?}",
call.bytecode_address
);
return None
}

info!("running call in zkEVM {:#?}", call);
Expand Down
14 changes: 1 addition & 13 deletions crates/evm/core/src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use revm::{
precompile::{PrecompileSpecId, Precompiles},
primitives::{
Account, AccountInfo, Bytecode, Env, EnvWithHandlerCfg, EvmState, EvmStorageSlot,
HashMap as Map, Log, ResultAndState, SpecId, TxKind, KECCAK_EMPTY,
HashMap as Map, Log, ResultAndState, SpecId, KECCAK_EMPTY,
},
Database, DatabaseCommit, JournaledState,
};
Expand Down Expand Up @@ -771,18 +771,6 @@ impl Backend {
pub(crate) fn initialize(&mut self, env: &EnvWithHandlerCfg) {
self.set_caller(env.tx.caller);
self.set_spec_id(env.handler_cfg.spec_id);

let test_contract = match env.tx.transact_to {
TxKind::Call(to) => to,
TxKind::Create => {
let nonce = self
.basic_ref(env.tx.caller)
.map(|b| b.unwrap_or_default().nonce)
.unwrap_or_default();
env.tx.caller.create(nonce)
}
};
self.set_test_contract(test_contract);
}

/// Returns the `EnvWithHandlerCfg` with the current `spec_id` set.
Expand Down
2 changes: 1 addition & 1 deletion crates/evm/evm/src/executors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ impl Executor {
trace!(?from, ?to, "setting up contract");

let from = from.unwrap_or(CALLER);
self.backend_mut().set_test_contract(to).set_caller(from);
self.backend_mut().set_caller(from);
let calldata = Bytes::from_static(&ITest::setUpCall::SELECTOR);
let mut res = self.transact_raw(from, to, calldata, U256::ZERO)?;
res = res.into_result(rd)?;
Expand Down
13 changes: 12 additions & 1 deletion crates/forge/bin/cmd/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub struct InitArgs {
impl InitArgs {
pub fn run(self) -> Result<()> {
let Self { root, template, branch, opts, offline, force, vscode } = self;
let DependencyInstallOpts { shallow, no_git, no_commit, quiet } = opts;
let DependencyInstallOpts { shallow, no_git, no_commit, quiet, zksync } = opts;

// create the root dir if it does not exist
if !root.exists() {
Expand Down Expand Up @@ -153,6 +153,17 @@ impl InitArgs {
}
}

// install forge-zksync-std
if zksync && !offline {
if root.join("lib/forge-zksync-std").exists() {
p_println!(!quiet => "\"lib/forge-zksync-std\" already exists, skipping install....");
self.opts.install(&mut config, vec![])?;
} else {
let dep = "https://github.com/Moonsong-Labs/forge-zksync-std".parse()?;
self.opts.install(&mut config, vec![dep])?;
}
}

// init vscode settings
if vscode {
init_vscode(&root)?;
Expand Down
4 changes: 4 additions & 0 deletions crates/forge/bin/cmd/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ pub struct DependencyInstallOpts {
/// Do not print any messages.
#[arg(short, long)]
pub quiet: bool,

/// Install ZKsync specific libraries.
#[arg(long)]
pub zksync: bool,
}

impl DependencyInstallOpts {
Expand Down
1 change: 1 addition & 0 deletions crates/forge/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ impl<'a> ContractRunner<'a> {
}

let address = self.sender.create(self.executor.get_nonce(self.sender)?);
self.executor.backend_mut().set_test_contract(address);

// Set the contracts initial balance before deployment, so it is available during
// construction
Expand Down
2 changes: 1 addition & 1 deletion crates/forge/tests/cli/test_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1048,7 +1048,7 @@ contract CallEmptyCode is Test {
"#,
)
.unwrap();
cmd.args(["test", "--zksync", "--evm-version", "shanghai"]);
cmd.args(["test", "--zksync", "--evm-version", "shanghai", "--mc", "CallEmptyCode"]);

let output = cmd.stdout_lossy();
assert!(output.contains("call may fail or behave unexpectedly due to empty code"));
Expand Down
10 changes: 8 additions & 2 deletions crates/forge/tests/it/zk/invariant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ use foundry_test_utils::Filter;

#[tokio::test(flavor = "multi_thread")]
async fn test_zk_invariant_deposit() {
let runner = TEST_DATA_DEFAULT.runner_zksync();
let filter = Filter::new("testZkInvariantDeposit", "ZkInvariantTest", ".*");
let mut runner = TEST_DATA_DEFAULT.runner_zksync();

// FIXME: just use the inline config
runner.test_options.invariant.no_zksync_reserved_addresses = true;
runner.test_options.invariant.fail_on_revert = true;
runner.test_options.invariant.runs = 10;

let filter = Filter::new(".*", "ZkInvariantTest", ".*");

TestConfig::with_filter(runner, filter).evm_spec(SpecId::SHANGHAI).run().await;
}
7 changes: 7 additions & 0 deletions crates/forge/tests/it/zk/repros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,10 @@ async fn repro_config(

// https://github.com/matter-labs/foundry-zksync/issues/497
test_repro!(497);

test_repro!(565; |cfg| {
// FIXME: just use the inline config
cfg.runner.test_options.invariant.no_zksync_reserved_addresses = true;
cfg.runner.test_options.invariant.fail_on_revert = true;
cfg.runner.test_options.invariant.runs = 2;
});
1 change: 1 addition & 0 deletions crates/script/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ impl ScriptRunner {
};

let address = CALLER.create(self.executor.get_nonce(CALLER)?);
self.executor.backend_mut().set_test_contract(address);

self.executor.backend_mut().set_test_contract(address);
// Set the contracts initial balance before deployment, so it is available during the
Expand Down
2 changes: 2 additions & 0 deletions testdata/zk/Globals.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ library Globals {
string public constant ETHEREUM_MAINNET_URL =
"https://eth-mainnet.alchemyapi.io/v2/Lc7oIGYeL_QvInzI0Wiu_pOZZDEKBrdf"; // trufflehog:ignore
string public constant ZKSYNC_MAINNET_URL = "mainnet";

address public constant SYSTEM_CONTEXT_ADDR = address(0x000000000000000000000000000000000000800B);
}
31 changes: 31 additions & 0 deletions testdata/zk/InZkVm.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.7 <0.9.0;

import {Globals} from "./Globals.sol";

// excerpt from system-contracts
interface ISystemContext {
function chainId() external view returns (uint256);
}

library InZkVmLib {
function _inZkVm() internal returns (bool) {
(bool success, bytes memory retdata) =
Globals.SYSTEM_CONTEXT_ADDR.call(abi.encodeWithSelector(ISystemContext.chainId.selector));

return success;
}
}

abstract contract InZkVm {
modifier inZkVm() {
require(InZkVmLib._inZkVm(), "must be executed in zkVM");
_;
}
}

abstract contract DeployOnlyInZkVm is InZkVm {
constructor() {
require(InZkVmLib._inZkVm(), "must be deployed in zkVM");
}
}
53 changes: 42 additions & 11 deletions testdata/zk/InvariantDeposit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,56 @@ import "ds-test/test.sol";
import "../cheats/Vm.sol";
import "./Deposit.sol";

contract ZkInvariantTest is DSTest {
// partial from forge-std/StdInvariant.sol
abstract contract StdInvariant {
struct FuzzSelector {
address addr;
bytes4[] selectors;
}

address[] internal _targetedContracts;

function targetContracts() public view returns (address[] memory) {
return _targetedContracts;
}

FuzzSelector[] internal _targetedSelectors;

function targetSelectors() public view returns (FuzzSelector[] memory) {
return _targetedSelectors;
}

address[] internal _targetedSenders;

function targetSenders() public view returns (address[] memory) {
return _targetedSenders;
}
}

contract ZkInvariantTest is DSTest, StdInvariant {
Vm constant vm = Vm(HEVM_ADDRESS);
// forge-config: default.invariant.runs = 2
Deposit deposit;

uint256 constant dealAmount = 1 ether;

function setUp() external {
// to fund for fees
_targetedSenders.push(address(65536 + 1));
_targetedSenders.push(address(65536 + 12));
_targetedSenders.push(address(65536 + 123));
_targetedSenders.push(address(65536 + 1234));

for (uint256 i = 0; i < _targetedSenders.length; i++) {
vm.deal(_targetedSenders[i], dealAmount); // to pay fees
}

deposit = new Deposit();
vm.deal(address(deposit), 100 ether);
_targetedContracts.push(address(deposit));
}

//FIXME: seems to not be detected, forcing values in test config
// forge-config: default.invariant.runs = 2
function testZkInvariantDeposit() external payable {
deposit.deposit{value: 1 ether}();
uint256 balanceBefore = deposit.balance(address(this));
assertEq(balanceBefore, 1 ether);
deposit.withdraw();
uint256 balanceAfter = deposit.balance(address(this));
assertGt(balanceBefore, balanceAfter);
}
function invariant_itWorks() external payable {}

receive() external payable {}
}
Loading

0 comments on commit 70a95b1

Please sign in to comment.