diff --git a/run_contests.sh b/run_contests.sh index 3ccf8f960..1cf09b6d3 100755 --- a/run_contests.sh +++ b/run_contests.sh @@ -7,6 +7,7 @@ cd "$root_dir" bash ./contest.sh test/examples/dispatch/basic.json bash ./contest.sh test/examples/dispatch/neg.json +bash ./contest.sh test/examples/dispatch/context.json bash ./contest.sh test/examples/dispatch/miniERC20.json bash ./contest.sh test/examples/dispatch/Revert.json bash ./contest.sh test/examples/dispatch/ownable.json diff --git a/src/Solcore/Primitives/Primitives.hs b/src/Solcore/Primitives/Primitives.hs index 1b67c6920..fd448e4c8 100644 --- a/src/Solcore/Primitives/Primitives.hs +++ b/src/Solcore/Primitives/Primitives.hs @@ -321,6 +321,7 @@ yulPrimOps = (Name "log4", monotype (funtype (words 6) unit)), (Name "chainid", monotype word), (Name "basefee", monotype word), + (Name "blobbasefee", monotype word), (Name "origin", monotype word), (Name "gasprice", monotype word), (Name "blockhash", monotype (word :-> word)), diff --git a/std/std.solc b/std/std.solc index b8704155e..26b4f741a 100644 --- a/std/std.solc +++ b/std/std.solc @@ -55,6 +55,7 @@ export { bytes32(*), bandWord, borWord, + block, bxorWord, bnotWord, bshlWord, @@ -84,6 +85,7 @@ export { maxVal, memberAccessBase, memory(*), + msg, memory_ref, mload, mstore, @@ -119,6 +121,7 @@ export { toWord, to_bytes, tobool, + tx, uint256(*), unimplemented, zeroize_memory @@ -788,6 +791,156 @@ forall t . instance calldata(t) : Typedef(word) { } } +forall t . class t:msg { + // Currently copies calldata into memory. + // Will change once calldata(bytes) is operational. + function calldata() -> memory(bytes); + function sender() -> address; + function sig() -> bytes4; + function value() -> uint256; +} + +forall t . default instance t:msg { + function calldata() -> memory(bytes) { + let size: word; + assembly { + size := calldatasize() + } + let rounded = round_up_to_mul_of_32(size); + let ptr = allocate_memory(32 + rounded); + mstore(ptr, size); + assembly { + calldatacopy(add(ptr, 32), 0, size) + } + zeroize_memory(ptr + 32 + size, rounded - size); + return memory(ptr); + } + + function sender() -> address { + let res: word; + assembly { + res := caller() + } + return address(res); + } + + function sig() -> bytes4 { + let res: word; + assembly { + res := shr(224, calldataload(0)) + } + return bytes4(res); + } + + function value() -> uint256 { + let res: word; + assembly { + res := callvalue() + } + return uint256(res); + } +} + +forall t . class t:block { + function basefee() -> uint256; + function blobbasefee() -> uint256; + function chainid() -> uint256; + function coinbase() -> address; + function gaslimit() -> uint256; + function number() -> uint256; + function prevrandao() -> uint256; + function timestamp() -> uint256; +} + +forall t . default instance t:block { + function basefee() -> uint256 { + let res: word; + assembly { + res := basefee() + } + return uint256(res); + } + + function blobbasefee() -> uint256 { + let res: word; + assembly { + res := blobbasefee() + } + return uint256(res); + } + + function chainid() -> uint256 { + let res: word; + assembly { + res := chainid() + } + return uint256(res); + } + + function coinbase() -> address { + let res: word; + assembly { + res := coinbase() + } + return address(res); + } + + function gaslimit() -> uint256 { + let res: word; + assembly { + res := gaslimit() + } + return uint256(res); + } + + function number() -> uint256 { + let res: word; + assembly { + res := number() + } + return uint256(res); + } + + function prevrandao() -> uint256 { + let res: word; + assembly { + res := prevrandao() + } + return uint256(res); + } + + function timestamp() -> uint256 { + let res: word; + assembly { + res := timestamp() + } + return uint256(res); + } +} + +forall t . class t:tx { + function gasprice() -> uint256; + function origin() -> address; +} + +forall t . default instance t:tx { + function gasprice() -> uint256 { + let res: word; + assembly { + res := gasprice() + } + return uint256(res); + } + + function origin() -> address { + let res: word; + assembly { + res := origin() + } + return address(res); + } +} + data returndata(t) = returndata(word); forall t . instance returndata(t) : Typedef(word) { function abs(x: word) -> returndata(t) { diff --git a/test/Cases.hs b/test/Cases.hs index 5da75eba0..5f68f1373 100644 --- a/test/Cases.hs +++ b/test/Cases.hs @@ -113,6 +113,7 @@ dispatches = "Files for dispatch cases" [ runDispatchTest "basic.solc", runDispatchTest "stringid.solc", + runDispatchTest "context.solc", runDispatchTest "miniERC20.solc", runDispatchTest "Revert.solc", runDispatchTest "hashes.solc", @@ -205,6 +206,9 @@ imports = runImportSuccess "external_lib_main.solc", runImportSuccess "external_lib_alias_main.solc", runImportSuccess "import_std_minimal.solc", + runImportSuccess "std_context_select.solc", + runImportSuccess "std_context_wildcard.solc", + runImportFailure "std_context_data_fail.solc", runImportSuccess "select_alias_item_ok.solc", runImportSuccess "select_alias_multi_ok.solc", runImportFailure "select_alias_tail_fail.solc", diff --git a/test/examples/cases/monomorphic-require.solc b/test/examples/cases/monomorphic-require.solc index df7b1a2a9..ec91bd710 100644 --- a/test/examples/cases/monomorphic-require.solc +++ b/test/examples/cases/monomorphic-require.solc @@ -1,6 +1,6 @@ // This should trigger a warning and an error in the specialiser // due to unability to resolve result type of require -import std.{uint256,lt,not,Eq,ne,Proxy,bytes4,string}; +import std.{uint256,lt,not,Eq,ne,Proxy,address,bytes,bytes4,memory,string,msg}; import std.dispatch.{*}; forall a. @@ -16,21 +16,13 @@ function require(cond: bool) -> () { } } -function callvalue() -> uint256 { - let res : word; - assembly { - res := callvalue() - } - return uint256(res); -} - contract Deposit { public function deposit() -> () { - require(callvalue() != uint256(0)); + require(msg.value() != uint256(0)); return (); } public function main() -> () { deposit(); } -} \ No newline at end of file +} diff --git a/test/examples/cases/polymorphic-require.solc b/test/examples/cases/polymorphic-require.solc index dbab329e2..5dc08ad59 100644 --- a/test/examples/cases/polymorphic-require.solc +++ b/test/examples/cases/polymorphic-require.solc @@ -1,6 +1,6 @@ // This should trigger a warning and an error in the specialiser // due to unability to resolve result type of require -import std.{uint256,lt,not,Eq,ne,Proxy,bytes4,string}; +import std.{uint256,lt,not,Eq,ne,Proxy,address,bytes,bytes4,memory,string,msg}; import std.dispatch.{*}; forall a. @@ -12,21 +12,13 @@ function require(cond: bool) -> a { } } -function callvalue() -> uint256 { - let res : word; - assembly { - res := callvalue() - } - return uint256(res); -} - contract Deposit { public function deposit() -> () { - require(callvalue() != uint256(0)); + require(msg.value() != uint256(0)); return (); } public function main() -> () { deposit(); } -} \ No newline at end of file +} diff --git a/test/examples/cases/yul-deposit-example.solc b/test/examples/cases/yul-deposit-example.solc index 150a5487a..316e16b06 100644 --- a/test/examples/cases/yul-deposit-example.solc +++ b/test/examples/cases/yul-deposit-example.solc @@ -1,10 +1,7 @@ import std.{*}; function deposit(pubkey: memory(string), withdrawal_credentials: memory(string), signature: memory(string), deposit_data_root: uint256) -> () { - let msg_value : uint256 = uint256(0); - assembly { - msg_value := callvalue() - } + let msg_value : uint256 = msg.value(); } contract Foo { diff --git a/test/examples/dispatch/context.json b/test/examples/dispatch/context.json new file mode 100644 index 000000000..818511a6c --- /dev/null +++ b/test/examples/dispatch/context.json @@ -0,0 +1,244 @@ +{ + "context": { + "bytecode": "", + "contract": "ContextTest", + "tests": [ + { + "input": { + "comment": "constructor()", + "calldata": "", + "value": "0" + }, + "kind": "constructor" + }, + { + "input": { + "comment": "msgCalldata()(bytes) - full calldata", + "calldata": "a11a65ff", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004a11a65ff00000000000000000000000000000000000000000000000000000000", + "status": "success" + } + }, + { + "input": { + "comment": "msgCalldataFirstWordAfterDirtyMemory()(bytes32) - selector-only calldata zeroes first-word padding", + "calldata": "15f1891b", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "15f1891b00000000000000000000000000000000000000000000000000000000", + "status": "success" + } + }, + { + "input": { + "comment": "msgCalldataFirstWordAfterDirtyMemory()(bytes32) - 31-byte calldata zeroes final byte", + "calldata": "15f1891baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "15f1891baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa00", + "status": "success" + } + }, + { + "input": { + "comment": "msgCalldataFirstWordAfterDirtyMemory()(bytes32) - 32-byte calldata leaves no padding", + "calldata": "15f1891bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "15f1891bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "status": "success" + } + }, + { + "input": { + "comment": "msgCalldataSecondWordAfterDirtyMemory()(bytes32) - 33-byte calldata zeroes second-word padding", + "calldata": "f1e4985edddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "dd00000000000000000000000000000000000000000000000000000000000000", + "status": "success" + } + }, + { + "input": { + "comment": "msgCalldataSecondWordAfterDirtyMemory()(bytes32) - 64-byte calldata leaves second word fully copied", + "calldata": "f1e4985eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "status": "success" + } + }, + { + "input": { + "comment": "msgSender()(address) - caller account", + "calldata": "d737d0c7", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "0000000000000000000000001212121212121212121212121212120000000012", + "status": "success" + } + }, + { + "input": { + "comment": "msgSig()(uint256) - current selector", + "calldata": "ec3e88cf", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "00000000000000000000000000000000000000000000000000000000ec3e88cf", + "status": "success" + } + }, + { + "input": { + "comment": "msgValue()(uint256) - call value", + "calldata": "ddf363d7", + "value": "1234" + }, + "kind": "call", + "output": { + "returndata": "00000000000000000000000000000000000000000000000000000000000004d2", + "status": "success" + } + }, + { + "input": { + "comment": "txGasprice()(uint256)", + "calldata": "c824f6dc", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "00000000000000000000000000000000000000000000000000000000b2d05e00", + "status": "success" + } + }, + { + "input": { + "comment": "txOrigin()(address)", + "calldata": "f96757d1", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "0000000000000000000000009292929292929292929292929292929292929292", + "status": "success" + } + }, + { + "input": { + "comment": "blockBasefee()(uint256)", + "calldata": "e5c47e1d", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "0000000000000000000000000000000000000000000000000000000000000007", + "status": "success" + } + }, + { + "input": { + "comment": "blockBlobbasefee()(uint256)", + "calldata": "3e8d64c6", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "0000000000000000000000000000000000000000000000000000000000000001", + "status": "success" + } + }, + { + "input": { + "comment": "blockChainid()(uint256)", + "calldata": "ca8db37e", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "0000000000000000000000000000000000000000000000000000000000000001", + "status": "success" + } + }, + { + "input": { + "comment": "blockCoinbase()(address)", + "calldata": "cebcbba9", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "0000000000000000000000007878787878787878787878787878787878787878", + "status": "success" + } + }, + { + "input": { + "comment": "blockGaslimit()(uint256)", + "calldata": "4b0e0815", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "0000000000000000000000000000000000000000000000000000000001312d00", + "status": "success" + } + }, + { + "input": { + "comment": "blockNumber()(uint256)", + "calldata": "57e871e7", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "000000000000000000000000000000000000000000000000000000000000001c", + "status": "success" + } + }, + { + "input": { + "comment": "blockPrevrandao()(uint256)", + "calldata": "3c112c57", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "a86c2e601b6c44eb4848f7d23d9df3113fbcac42041c49cbed5000cb4f118777", + "status": "success" + } + }, + { + "input": { + "comment": "blockTimestamp()(uint256)", + "calldata": "adb61832", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "000000000000000000000000000000000000000000000000000000000000f12c", + "status": "success" + } + } + ] + } +} diff --git a/test/examples/dispatch/context.solc b/test/examples/dispatch/context.solc new file mode 100644 index 000000000..9d28509fe --- /dev/null +++ b/test/examples/dispatch/context.solc @@ -0,0 +1,79 @@ +import std.{*}; +import std.dispatch.{*}; +pragma no-patterson-condition ; +pragma no-coverage-condition ; +pragma no-bounded-variable-condition ; + +contract ContextTest { + constructor() {} + + function msgCalldata() -> memory(bytes) { + return msg.calldata(); + } + + function msgCalldataFirstWordAfterDirtyMemory() -> bytes32 { + let ptr = get_free_memory(); + mstore(ptr + 32, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + let callData : memory(bytes) = msg.calldata(); + return bytes32(mload(Typedef.rep(callData) + 32)); + } + + function msgCalldataSecondWordAfterDirtyMemory() -> bytes32 { + let ptr = get_free_memory(); + mstore(ptr + 64, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + let callData : memory(bytes) = msg.calldata(); + return bytes32(mload(Typedef.rep(callData) + 64)); + } + + function msgSender() -> address { + return msg.sender(); + } + + function msgSig() -> uint256 { + return uint256(toWord(msg.sig())); + } + + payable function msgValue() -> uint256 { + return msg.value(); + } + + function txGasprice() -> uint256 { + return tx.gasprice(); + } + + function txOrigin() -> address { + return tx.origin(); + } + + function blockBasefee() -> uint256 { + return block.basefee(); + } + + function blockBlobbasefee() -> uint256 { + return block.blobbasefee(); + } + + function blockChainid() -> uint256 { + return block.chainid(); + } + + function blockCoinbase() -> address { + return block.coinbase(); + } + + function blockGaslimit() -> uint256 { + return block.gaslimit(); + } + + function blockNumber() -> uint256 { + return block.number(); + } + + function blockPrevrandao() -> uint256 { + return block.prevrandao(); + } + + function blockTimestamp() -> uint256 { + return block.timestamp(); + } +} diff --git a/test/examples/dispatch/miniERC20.solc b/test/examples/dispatch/miniERC20.solc index e7455ea83..765c6cccb 100644 --- a/test/examples/dispatch/miniERC20.solc +++ b/test/examples/dispatch/miniERC20.solc @@ -5,14 +5,6 @@ pragma no-patterson-condition ; pragma no-coverage-condition ; pragma no-bounded-variable-condition ; -function caller() -> address { - let res: word; - assembly { - res := caller() - } - return address(res); -} - contract MiniERC20 { name : string; symbol : string; @@ -25,7 +17,7 @@ contract MiniERC20 { constructor(name_ : memory(string), symbol_ : memory(string), totalSupply_:uint256) { name = name_; symbol = symbol_; - owner = caller(); + owner = msg.sender(); decimals = uint256(18); mint(totalSupply_); } @@ -61,11 +53,11 @@ contract MiniERC20 { } public function transfer(dst : address, amt : uint256) -> bool { - return transferFrom(caller(), dst, amt); + return transferFrom(msg.sender(), dst, amt); } public function transferFrom(src:address, dst:address, amt:uint256) -> bool { - let msg_sender = caller(); + let msg_sender = msg.sender(); require(balances[src] >= amt, Error(0xf4d678b8)); // InsufficientBalance() if (src != msg_sender && allowance[src][msg_sender] != (Num.maxVal():uint256)) { @@ -80,7 +72,7 @@ contract MiniERC20 { } public function approve(usr: address, amt: uint256) -> bool { - let msg_sender = caller(); + let msg_sender = msg.sender(); allowance[msg_sender][usr] = amt; // emit Approval(msg.sender, usr, amt); return true; @@ -89,12 +81,12 @@ contract MiniERC20 { // testing public function getMyBalance() -> uint256 { - return balances[caller()]; + return balances[msg.sender()]; } public function test() -> uint256 { approve(address(0), uint256(10)); - transferFrom(caller(), address(0), uint256(958)); + transferFrom(msg.sender(), address(0), uint256(958)); return getMyBalance(); } diff --git a/test/examples/dispatch/ownable.solc b/test/examples/dispatch/ownable.solc index 8a4e3edf1..cbb28c4e1 100644 --- a/test/examples/dispatch/ownable.solc +++ b/test/examples/dispatch/ownable.solc @@ -4,22 +4,11 @@ pragma no-patterson-condition ; pragma no-coverage-condition ; pragma no-bounded-variable-condition ; -// caller() is not in the std library yet, -// so every contract must define its own - -function caller() -> address { - let res: word; - assembly { - res := caller() - } - return address(res); -} - contract Ownable { owner : address; constructor() { - owner = caller(); + owner = msg.sender(); } // named getOwner() instead of owner() to avoid collision with the field name @@ -28,7 +17,7 @@ contract Ownable { } public function changeOwner(newOwner : address) -> () { - require(caller() == owner, Error(0x12b0c500)); // OwnableUnauthorizedAccount() + require(msg.sender() == owner, Error(0x12b0c500)); // OwnableUnauthorizedAccount() owner = newOwner; } } diff --git a/test/examples/dispatch/payable.solc b/test/examples/dispatch/payable.solc index 553275b1d..84d32c750 100644 --- a/test/examples/dispatch/payable.solc +++ b/test/examples/dispatch/payable.solc @@ -5,11 +5,7 @@ contract PayableTest { constructor() {} public payable function deposit() -> uint256 { - let value; - assembly { - value := callvalue() - } - return uint256(value); + return msg.value(); } public function balance() -> uint256 { @@ -21,11 +17,7 @@ contract PayableTest { } payable fallback() -> () { - let value; - assembly { - value := callvalue() - } - if (value == 0) { + if (msg.value() == uint256(0)) { revertLit("fallback-was-called-no-value"); } } diff --git a/test/examples/spec/126nanoerc20.solc b/test/examples/spec/126nanoerc20.solc index 865965a7a..1c0e30523 100644 --- a/test/examples/spec/126nanoerc20.solc +++ b/test/examples/spec/126nanoerc20.solc @@ -4,14 +4,6 @@ pragma no-patterson-condition ; pragma no-coverage-condition ; pragma no-bounded-variable-condition ; -function caller() -> address { - let res: word; - assembly { - res := caller() - } - return address(res); -} - function myrevert( msg: (word, word) ) -> () { match msg { | (str, len) => @@ -68,7 +60,7 @@ contract Uint { public function init() -> () { owner = address(0x123456789abcdef); - msg_sender = caller(); + msg_sender = msg.sender(); decimals = uint256(18); } diff --git a/test/examples/spec/127microerc20.solc b/test/examples/spec/127microerc20.solc index 339205819..b97bdcbed 100644 --- a/test/examples/spec/127microerc20.solc +++ b/test/examples/spec/127microerc20.solc @@ -4,14 +4,6 @@ pragma no-patterson-condition ; pragma no-coverage-condition ; pragma no-bounded-variable-condition ; -function caller() -> address { - let res: word; - assembly { - res := caller() - } - return address(res); -} - function require1fail() -> () { let res: word; assembly { @@ -92,7 +84,7 @@ contract Mini { public function init() -> () { owner = address(0x123456789abcdef); - msg_sender = caller(); + msg_sender = msg.sender(); decimals = uint256(18); } diff --git a/test/examples/spec/128minierc20.solc b/test/examples/spec/128minierc20.solc index a3c21a15e..e048b50d7 100644 --- a/test/examples/spec/128minierc20.solc +++ b/test/examples/spec/128minierc20.solc @@ -4,14 +4,6 @@ pragma no-patterson-condition ; pragma no-coverage-condition ; pragma no-bounded-variable-condition ; -function caller() -> address { - let res: word; - assembly { - res := caller() - } - return address(res); -} - function myrevert(msg: word) -> () { assembly { mstore(0, msg) revert(0, 32) } } @@ -49,7 +41,7 @@ contract MiniERC20 { */ public function transferFrom(src:address, dst:address, amt:uint256) -> bool { - let msg_sender = caller(); + let msg_sender = msg.sender(); myrequire( balances[src] >= amt /* "token/insufficient-balance" */ , 0x746f6b656e2f696e73756666696369656e742d62616c616e6365 ); @@ -74,7 +66,7 @@ contract MiniERC20 { */ public function approve(usr: address, amt: uint256) -> bool { - let msg_sender = caller(); + let msg_sender = msg.sender(); allowance[msg_sender][usr] = amt; // emit Approval(msg.sender, usr, amt); return true; @@ -87,7 +79,7 @@ contract MiniERC20 { } public function main() -> uint256 { - let msg_sender = caller(); + let msg_sender = msg.sender(); init(); mint(uint256(1000)); allowance[owner][msg_sender] = uint256(1000); diff --git a/test/imports/std_context_data_fail.solc b/test/imports/std_context_data_fail.solc new file mode 100644 index 000000000..961b3a92c --- /dev/null +++ b/test/imports/std_context_data_fail.solc @@ -0,0 +1,5 @@ +import std.{msg, bytes, memory}; + +function callData() -> memory(bytes) { + return msg.data(); +} diff --git a/test/imports/std_context_select.solc b/test/imports/std_context_select.solc new file mode 100644 index 000000000..dbb8d787d --- /dev/null +++ b/test/imports/std_context_select.solc @@ -0,0 +1,25 @@ +import std.{msg, block, tx, address, bytes, bytes4, memory, uint256}; + +function sender() -> address { + return msg.sender(); +} + +function value() -> uint256 { + return msg.value(); +} + +function selector() -> bytes4 { + return msg.sig(); +} + +function callData() -> memory(bytes) { + return msg.calldata(); +} + +function timestamp() -> uint256 { + return block.timestamp(); +} + +function originator() -> address { + return tx.origin(); +} diff --git a/test/imports/std_context_wildcard.solc b/test/imports/std_context_wildcard.solc new file mode 100644 index 000000000..d737438ed --- /dev/null +++ b/test/imports/std_context_wildcard.solc @@ -0,0 +1,13 @@ +import std.{*}; + +function sender() -> address { + return msg.sender(); +} + +function blockNumber() -> uint256 { + return block.number(); +} + +function gasPrice() -> uint256 { + return tx.gasprice(); +} diff --git a/test/testrunner/EVMHost.cpp b/test/testrunner/EVMHost.cpp index 5d15b9d20..4b0ea52ec 100644 --- a/test/testrunner/EVMHost.cpp +++ b/test/testrunner/EVMHost.cpp @@ -169,6 +169,7 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm): void EVMHost::reset() { + resetBlockContext(); accounts.clear(); // Clear self destruct records recorded_selfdestructs.clear(); diff --git a/test/testrunner/EVMHost.h b/test/testrunner/EVMHost.h index 8e4faf1ec..38fedff25 100644 --- a/test/testrunner/EVMHost.h +++ b/test/testrunner/EVMHost.h @@ -97,6 +97,13 @@ class EVMHost: public evmc::MockedHost /// Reset entire state (including accounts). void reset(); + /// Reset block fields that should not depend on test ordering. + void resetBlockContext() + { + tx_context.block_number = 10; + tx_context.block_timestamp = 0xF000; + } + /// Start new block. void newBlock() { diff --git a/test/testrunner/testrunner.cpp b/test/testrunner/testrunner.cpp index 01d79d35d..bb8b1ccc4 100644 --- a/test/testrunner/testrunner.cpp +++ b/test/testrunner/testrunner.cpp @@ -74,6 +74,7 @@ int main(int argc, char** argv) langutil::EVMVersion const evmVersion{}; evmcHost = std::make_unique(evmVersion, vm); + evmcHost->resetBlockContext(); auto account = [](size_t i) { return h160(h256(u256{"0x1212121212121212121212121212120000000012"} + i * 0x1000), h160::AlignRight);