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

hevm: enchanced control over blockchain context #716

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions nix/build-dapp-package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ in
, deps ? []
, solc ? "${pkgs.solc}/bin/solc"
, shouldFail ? false
, dappFlags ? ""
, doCheck ? true
, dapprc ? ""
, testFlags ? ""
, ... }@args:
pkgs.stdenv.mkDerivation ( rec {
inherit doCheck;
Expand All @@ -47,6 +48,7 @@ in
'')
passthru.libPaths;
buildPhase = ''
source ${pkgs.writeText "dapprc" dapprc}
d-xo marked this conversation as resolved.
Show resolved Hide resolved
mkdir -p out
export DAPP_SOLC=${solc}
export DAPP_REMAPPINGS="$REMAPPINGS"
Expand All @@ -59,7 +61,7 @@ in
'';

checkPhase = let
cmd = "DAPP_SKIP_BUILD=1 dapp test ${dappFlags}";
cmd = "DAPP_SKIP_BUILD=1 dapp test ${testFlags}";
in
if shouldFail
then "${cmd} && exit 1 || echo 0"
Expand Down
39 changes: 33 additions & 6 deletions src/dapp-tests/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,10 @@ let
deps = [ ds-test ds-thing ];
};

runTest = { dir, shouldFail, name, dappFlags?"" }: pkgs.buildDappPackage {
inherit name shouldFail;
runTest = { dir, shouldFail, name, dapprc ? "", testFlags ? "" }: pkgs.buildDappPackage {
inherit name shouldFail testFlags dapprc;
solc=solc-0_6_7;
src = dir;
dappFlags = "${dappFlags}";
deps = [ ds-test ds-token ds-math ];
checkInputs = with pkgs; [ hevm jq seth dapp solc ];
};
Expand All @@ -128,15 +127,43 @@ in
dir = ./pass;
name = "dappTestsShouldPass";
shouldFail = false;
dappFlags = "--max-iterations 50 --smttimeout 600000 --ffi";
testFlags = "--max-iterations 50 --smttimeout 600000 --ffi";
};

envVars = let
envVarTest = match : dapprc : runTest {
testFlags = "--match ${match}";
dir = ./env;
name = "dappTestEnvVar";
shouldFail = false;
inherit dapprc;
};
seth = "${pkgs.seth}/bin/seth";
in pkgs.recurseIntoAttrs {
# we get "hevm: insufficient balance for gas cost" if we run these together...
origin = envVarTest "origin.sol" "export DAPP_TEST_ORIGIN=$(${seth} --to-hex 256)";
rest = envVarTest "rest.sol" ''
export DAPP_TEST_BALANCE=$(${seth} --to-wei 998877665544 ether)
export DAPP_TEST_ADDRESS=$(${seth} --to-hex 256)
export DAPP_TEST_CALLER=$(${seth} --to-hex 100)
export DAPP_TEST_GAS_CREATE=$(${seth} --to-wei 4.20 ether)
export DAPP_TEST_GAS_CALL=$(${seth} --to-wei 0.69 ether)
export DAPP_TEST_NONCE=100
export DAPP_TEST_COINBASE=$(${seth} --to-hex 666)
export DAPP_TEST_NUMBER=420
export DAPP_TEST_TIMESTAMP=69
export DAPP_TEST_GAS_LIMIT=$(${seth} --to-wei 4206966 ether)
export DAPP_TEST_GAS_PRICE=100
export DAPP_TEST_DIFFICULTY=600
'';
};

shouldFail = let
fail = match : runTest {
dir = ./fail;
shouldFail = true;
name = "dappTestsShouldFail-${match}";
dappFlags = "--match ${match} --smttimeout 600000";
testFlags = "--match ${match} --smttimeout 600000";
};
in pkgs.recurseIntoAttrs {
prove-add = fail "prove_add";
Expand All @@ -155,7 +182,7 @@ in
solc = solc-0_6_7;
src = dss-src;
name = "dss";
dappFlags = "--match '[^dai].t.sol'";
testFlags = "--match '[^dai].t.sol'";
deps = [ ds-test ds-token ds-value ];
};
}
8 changes: 8 additions & 0 deletions src/dapp-tests/env/origin.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import "ds-test/test.sol";

contract Env is DSTest {
// DAPP_TEST_ORIGIN
function testOrigin() public {
assertEq(tx.origin, address(256));
}
}
72 changes: 72 additions & 0 deletions src/dapp-tests/env/rest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import "ds-test/test.sol";

contract Env is DSTest {
uint creationGas;
constructor() public {
creationGas = gasleft();
}

// TODO: why does this fail when address == 0?
// DAPP_TEST_BALANCE
function testBalance() public {
assertEq(address(this).balance, 998877665544 ether);
}
// DAPP_TEST_ADDRESS
function testAddress() public {
assertEq(address(this), address(256));
}
// DAPP_TEST_NONCE
// we can't test the nonce directly, but can instead check the address of a newly deployed contract
function testNonce() public {
uint8 nonce = 100;
bytes memory payload = abi.encodePacked(hex"d694", address(this), nonce);

address expected = address(uint160(uint256(keccak256(payload))));
address actual = address(new Trivial());
assertEq(actual, expected);

}
// DAPP_TEST_CALLER
function testCaller() public {
assertEq(msg.sender, address(100));
}
// DAPP_TEST_GAS_CREATE
function testGasCreate() public {
// we can't be exact since we had to spend some gas to write to storage...
assertLt(creationGas, 4.20 ether);
assertGt(creationGas, 4.1999999999999 ether);
}
// DAPP_TEST_GAS_CALL
function testGasCall() public {
uint gas = gasleft();
// we can't be exact since we had to spend some gas to get here...
assertLt(gas, 0.69 ether);
assertGt(gas, 0.689999999999999 ether);
}
// DAPP_TEST_COINBASE
function testCoinbase() public {
assertEq(block.coinbase, address(666));
}
// DAPP_TEST_NUMBER
function testBlockNumber() public {
assertEq(block.number, 420);
}
// DAPP_TEST_TIMESTAMP
function testTimestamp() public {
assertEq(block.timestamp, 69);
}
// DAPP_TEST_GAS_LIMIT
function testGasLimit() public {
assertEq(block.gaslimit, 4206966 ether);
}
// DAPP_TEST_GAS_PRICE
function testGasPrice() public {
assertEq(tx.gasprice, 100);
}
// DAPP_TEST_DIFFICULTY
function testDifficulty() public {
assertEq(block.difficulty, 600);
}
}

contract Trivial {}
4 changes: 4 additions & 0 deletions src/hevm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Added
Copy link
Contributor Author

@d-xo d-xo Aug 2, 2021

Choose a reason for hiding this comment

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

TODO: document new cheatcodes....


- A new configuration variable `DAPP_TEST_NONCE` has been added that allows control over the nonce of the testing contract

### Changed

- The configuration variable `DAPP_TEST_BALANCE_CREATE` has been renamed to `DAPP_TEST_BALANCE`
Expand Down
1 change: 1 addition & 0 deletions src/hevm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ These environment variables can be used to control block parameters:
| `DAPP_TEST_GAS_CREATE` | `0xffffffffffff` | The gas to provide when creating the testing contract |
| `DAPP_TEST_GAS_CALL` | `0xffffffffffff` | The gas to provide to each call made to the testing contract |
| `DAPP_TEST_BALANCE` | `0xffffffffffffffffffffffff` | The balance to provide to `DAPP_TEST_ADDRESS` |
| `DAPP_TEST_NONCE ` | `1` | The initial nonce to use for `DAPP_TEST_ADDRESS` |
| `DAPP_TEST_COINBASE` | `0x0000000000000000000000000000000000000000` | The coinbase address. Will be set to the coinbase for the block at `DAPP_TEST_NUMBER` if rpc is enabled |
| `DAPP_TEST_NUMBER` | `0` | The block number. Will be set to the latest block if rpc is enabled |
| `DAPP_TEST_TIMESTAMP` | `0` | The block timestamp. Will be set to the timestamp for the block at `DAPP_TEST_NUMBER` if rpc is enabled |
Expand Down
42 changes: 25 additions & 17 deletions src/hevm/src/EVM/UnitTest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -87,20 +87,21 @@ data UnitTestOptions = UnitTestOptions
}

data TestVMParams = TestVMParams
{ testAddress :: Addr
, testCaller :: Addr
, testOrigin :: Addr
, testGasCreate :: W256
, testGasCall :: W256
, testBalanceCreate :: W256
, testCoinbase :: Addr
, testNumber :: W256
, testTimestamp :: W256
, testGaslimit :: W256
, testGasprice :: W256
, testMaxCodeSize :: W256
, testDifficulty :: W256
, testChainId :: W256
{ testAddress :: Addr
, testNonce :: W256
, testCaller :: Addr
, testOrigin :: Addr
, testGasCreate :: W256
, testGasCall :: W256
, testBalance :: W256
, testCoinbase :: Addr
, testNumber :: W256
, testTimestamp :: W256
, testGaslimit :: W256
, testGasprice :: W256
, testMaxCodeSize :: W256
, testDifficulty :: W256
, testChainId :: W256
}

defaultGasForCreating :: W256
Expand All @@ -112,6 +113,9 @@ defaultGasForInvoking = 0xffffffffffff
defaultBalanceForTestContract :: W256
defaultBalanceForTestContract = 0xffffffffffffffffffffffff

defaultNonceForTestContract :: W256
defaultNonceForTestContract = 1

defaultMaxCodeSize :: W256
defaultMaxCodeSize = 0xffffffff

Expand All @@ -135,7 +139,10 @@ initializeUnitTest UnitTestOptions { .. } theContract = do

Stepper.evm $ do
-- Give a balance to the test target
env . contracts . ix addr . balance += w256 (testBalanceCreate testParams)
env . contracts . ix addr . balance += w256 (testBalance testParams)

-- Set the test targets nonce
env . contracts . ix addr . nonce .= w256 (testNonce testParams)

-- call setUp(), if it exists, to initialize the test contract
let theAbi = view abiMap theContract
Expand Down Expand Up @@ -927,8 +934,8 @@ initialUnitTestVm (UnitTestOptions {..}) theContract =
}
creator =
initialContract (RuntimeCode mempty)
& set nonce 1
& set balance (w256 testBalanceCreate)
& set nonce (w256 testNonce)
& set balance (w256 testBalance)
in vm
& set (env . contracts . at ethrunAddress) (Just creator)

Expand Down Expand Up @@ -967,6 +974,7 @@ getParametersFromEnvironmentVariables rpc = do

TestVMParams
<$> getAddr "DAPP_TEST_ADDRESS" (createAddress ethrunAddress 1)
<*> getWord "DAPP_TEST_NONCE" defaultNonceForTestContract
<*> getAddr "DAPP_TEST_CALLER" ethrunAddress
<*> getAddr "DAPP_TEST_ORIGIN" ethrunAddress
<*> getWord "DAPP_TEST_GAS_CREATE" defaultGasForCreating
Expand Down