Adds support for the EVM version "Paris".

Deprecates `block.difficulty` and disallow `difficulty()` in inline assembly for EVM versions >= paris.
The change is due to the renaming introduced by EIP-4399 (see: https://eips.ethereum.org/EIPS/eip-4399).
Introduces `block.prevrandao` in Solidity and `prevrandao()` in inline assembly for EVM versions >= paris.

Co-authored-by: Alex Beregszaszi <alex@rtfs.hu>
Co-authored-by: Daniel <daniel@ekpyron.org>
Co-authored-by: matheusaaguiar <95899911+matheusaaguiar@users.noreply.github.com>
Co-authored-by: Nikola Matić <nikola.matic@ethereum.org>
This commit is contained in:
Rodrigo Q. Saramago
2023-01-23 18:50:36 +00:00
co-authored by Alex Beregszaszi Daniel matheusaaguiar Nikola Matić
parent d70d79af4a
commit ef6ff2f055
114 changed files with 842 additions and 221 deletions
@@ -0,0 +1 @@
--no-cbor-metadata --via-ir --optimize --opcodes --asm --debug-info none --evm-version paris
@@ -0,0 +1,5 @@
Warning: Since the VM version paris, "difficulty" was replaced by "prevrandao", which now returns a random number based on the beacon chain.
--> evmasm_difficulty_post_paris/input.sol:6:21:
|
6 | uint256 x = block.difficulty;
| ^^^^^^^^^^^^^^^^
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.0.0;
contract C {
constructor() payable {
uint256 x = block.difficulty;
assembly {
sstore(0, x)
stop()
}
}
fallback() external payable {
assembly {
stop()
}
}
}
@@ -0,0 +1,13 @@
======= evmasm_difficulty_post_paris/input.sol:C =======
EVM assembly:
sstore(0x00, prevrandao)
stop
stop
sub_0: assembly {
stop
}
Opcodes:
PREVRANDAO PUSH1 0x0 SSTORE STOP INVALID
@@ -0,0 +1 @@
--no-cbor-metadata --via-ir --optimize --opcodes --asm --debug-info none --evm-version london
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.0.0;
contract C {
constructor() payable {
uint256 x = block.difficulty;
assembly {
sstore(0, x)
stop()
}
}
fallback() external payable {
assembly {
stop()
}
}
}
@@ -0,0 +1,13 @@
======= evmasm_difficulty_pre_paris/input.sol:C =======
EVM assembly:
sstore(0x00, difficulty)
stop
stop
sub_0: assembly {
stop
}
Opcodes:
DIFFICULTY PUSH1 0x0 SSTORE STOP INVALID
@@ -0,0 +1 @@
--no-cbor-metadata --via-ir --optimize --opcodes --asm --debug-info none --evm-version paris
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.0.0;
contract C {
constructor() payable {
uint256 x = block.prevrandao;
assembly {
sstore(0, x)
stop()
}
}
fallback() external payable {
assembly {
stop()
}
}
}
@@ -0,0 +1,13 @@
======= evmasm_prevrandao_post_paris/input.sol:C =======
EVM assembly:
sstore(0x00, prevrandao)
stop
stop
sub_0: assembly {
stop
}
Opcodes:
PREVRANDAO PUSH1 0x0 SSTORE STOP INVALID
@@ -0,0 +1 @@
--no-cbor-metadata --via-ir --optimize --opcodes --asm --debug-info none --evm-version london
@@ -0,0 +1,5 @@
Warning: "prevrandao" is not supported by the VM version and will be treated as "difficulty".
--> evmasm_prevrandao_pre_paris/input.sol:6:21:
|
6 | uint256 x = block.prevrandao;
| ^^^^^^^^^^^^^^^^
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.0.0;
contract C {
constructor() payable {
uint256 x = block.prevrandao;
assembly {
sstore(0, x)
stop()
}
}
fallback() external payable {
assembly {
stop()
}
}
}
@@ -0,0 +1,13 @@
======= evmasm_prevrandao_pre_paris/input.sol:C =======
EVM assembly:
sstore(0x00, difficulty)
stop
stop
sub_0: assembly {
stop
}
Opcodes:
DIFFICULTY PUSH1 0x0 SSTORE STOP INVALID
+16 -11
View File
@@ -20,6 +20,7 @@
* @date 2018
* Tests for the assembler.
*/
#include <test/Common.h>
#include <libevmasm/Assembly.h>
#include <libsolutil/JSON.h>
@@ -59,15 +60,16 @@ BOOST_AUTO_TEST_CASE(all_assembly_items)
{ "sub.asm", 1 },
{ "verbatim.asm", 2 }
};
Assembly _assembly{false, {}};
EVMVersion evmVersion = solidity::test::CommonOptions::get().evmVersion();
Assembly _assembly{evmVersion, false, {}};
auto root_asm = make_shared<string>("root.asm");
_assembly.setSourceLocation({1, 3, root_asm});
Assembly _subAsm{false, {}};
Assembly _subAsm{evmVersion, false, {}};
auto sub_asm = make_shared<string>("sub.asm");
_subAsm.setSourceLocation({6, 8, sub_asm});
Assembly _verbatimAsm(true, "");
Assembly _verbatimAsm(evmVersion, true, "");
auto verbatim_asm = make_shared<string>("verbatim.asm");
_verbatimAsm.setSourceLocation({8, 18, verbatim_asm});
@@ -215,6 +217,7 @@ BOOST_AUTO_TEST_CASE(all_assembly_items)
BOOST_AUTO_TEST_CASE(immutables_and_its_source_maps)
{
EVMVersion evmVersion = solidity::test::CommonOptions::get().evmVersion();
// Tests for 1, 2, 3 number of immutables.
for (int numImmutables = 1; numImmutables <= 3; ++numImmutables)
{
@@ -243,7 +246,7 @@ BOOST_AUTO_TEST_CASE(immutables_and_its_source_maps)
{ *subName, 1 }
};
auto subAsm = make_shared<Assembly>(false, string{});
auto subAsm = make_shared<Assembly>(evmVersion, false, string{});
for (char i = 0; i < numImmutables; ++i)
{
for (int r = 0; r < numActualRefs; ++r)
@@ -253,7 +256,7 @@ BOOST_AUTO_TEST_CASE(immutables_and_its_source_maps)
}
}
Assembly assembly{true, {}};
Assembly assembly{evmVersion, true, {}};
for (char i = 1; i <= numImmutables; ++i)
{
assembly.setSourceLocation({10*i, 10*i + 3+i, assemblyName});
@@ -270,7 +273,7 @@ BOOST_AUTO_TEST_CASE(immutables_and_its_source_maps)
auto const numberOfMappings = std::count(sourceMappings.begin(), sourceMappings.end(), ';');
LinkerObject const& obj = assembly.assemble();
string const disassembly = disassemble(obj.bytecode, "\n");
string const disassembly = disassemble(obj.bytecode, evmVersion, "\n");
auto const numberOfOpcodes = std::count(disassembly.begin(), disassembly.end(), '\n');
#if 0 // {{{ debug prints
@@ -302,11 +305,12 @@ BOOST_AUTO_TEST_CASE(immutable)
{ "root.asm", 0 },
{ "sub.asm", 1 }
};
Assembly _assembly{true, {}};
EVMVersion evmVersion = solidity::test::CommonOptions::get().evmVersion();
Assembly _assembly{evmVersion, true, {}};
auto root_asm = make_shared<string>("root.asm");
_assembly.setSourceLocation({1, 3, root_asm});
Assembly _subAsm{false, {}};
Assembly _subAsm{evmVersion, false, {}};
auto sub_asm = make_shared<string>("sub.asm");
_subAsm.setSourceLocation({6, 8, sub_asm});
_subAsm.appendImmutable("someImmutable");
@@ -395,10 +399,11 @@ BOOST_AUTO_TEST_CASE(immutable)
BOOST_AUTO_TEST_CASE(subobject_encode_decode)
{
Assembly assembly{true, {}};
EVMVersion evmVersion = solidity::test::CommonOptions::get().evmVersion();
Assembly assembly{evmVersion, true, {}};
shared_ptr<Assembly> subAsmPtr = make_shared<Assembly>(false, string{});
shared_ptr<Assembly> subSubAsmPtr = make_shared<Assembly>(false, string{});
shared_ptr<Assembly> subAsmPtr = make_shared<Assembly>(evmVersion, false, string{});
shared_ptr<Assembly> subSubAsmPtr = make_shared<Assembly>(evmVersion, false, string{});
assembly.appendSubroutine(subAsmPtr);
subAsmPtr->appendSubroutine(subSubAsmPtr);
+12 -12
View File
@@ -1250,8 +1250,18 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies)
// tag unifications (due to block deduplication) is also
// visible at the super-assembly.
Assembly main{false, {}};
AssemblyPointer sub = make_shared<Assembly>(true, string{});
Assembly::OptimiserSettings settings;
settings.runInliner = false;
settings.runJumpdestRemover = true;
settings.runPeephole = true;
settings.runDeduplicate = true;
settings.runCSE = true;
settings.runConstantOptimiser = true;
settings.evmVersion = solidity::test::CommonOptions::get().evmVersion();
settings.expectedExecutionsPerDeployment = OptimiserSettings{}.expectedExecutionsPerDeployment;
Assembly main{settings.evmVersion, false, {}};
AssemblyPointer sub = make_shared<Assembly>(settings.evmVersion, true, string{});
sub->append(u256(1));
auto t1 = sub->newTag();
@@ -1277,16 +1287,6 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies)
main.append(t1.toSubAssemblyTag(subId));
main.append(u256(8));
Assembly::OptimiserSettings settings;
settings.runInliner = false;
settings.runJumpdestRemover = true;
settings.runPeephole = true;
settings.runDeduplicate = true;
settings.runCSE = true;
settings.runConstantOptimiser = true;
settings.evmVersion = solidity::test::CommonOptions::get().evmVersion();
settings.expectedExecutionsPerDeployment = OptimiserSettings{}.expectedExecutionsPerDeployment;
main.optimise(settings);
AssemblyItems expectationMain{
+3 -3
View File
@@ -109,7 +109,7 @@ public:
bytes realCode = bytecodeSansMetadata(_bytecode);
BOOST_REQUIRE_MESSAGE(!realCode.empty(), "Invalid or missing metadata in bytecode.");
size_t instructions = 0;
evmasm::eachInstruction(realCode, [&](Instruction _instr, u256 const&) {
evmasm::eachInstruction(realCode, m_evmVersion, [&](Instruction _instr, u256 const&) {
if (!_which || *_which == _instr)
instructions++;
});
@@ -287,7 +287,7 @@ BOOST_AUTO_TEST_CASE(retain_information_in_branches)
bytes optimizedBytecode = compileAndRunWithOptimizer(sourceCode, 0, "c", true);
size_t numSHA3s = 0;
eachInstruction(optimizedBytecode, [&](Instruction _instr, u256 const&) {
eachInstruction(optimizedBytecode, m_evmVersion, [&](Instruction _instr, u256 const&) {
if (_instr == Instruction::KECCAK256)
numSHA3s++;
});
@@ -330,7 +330,7 @@ BOOST_AUTO_TEST_CASE(store_tags_as_unions)
bytes optimizedBytecode = compileAndRunWithOptimizer(sourceCode, 0, "test", true);
size_t numSHA3s = 0;
eachInstruction(optimizedBytecode, [&](Instruction _instr, u256 const&) {
eachInstruction(optimizedBytecode, m_evmVersion, [&](Instruction _instr, u256 const&) {
if (_instr == Instruction::KECCAK256)
numSHA3s++;
});
@@ -1860,6 +1860,7 @@ BOOST_AUTO_TEST_CASE(builtins)
block.chainid;
block.coinbase;
block.difficulty;
block.prevrandao;
block.gaslimit;
block.number;
block.timestamp;
@@ -0,0 +1,12 @@
contract C {
function f() public view returns (uint ret) {
assembly {
ret := difficulty()
}
}
}
// ====
// compileToEwasm: also
// EVMVersion: <paris
// ----
// f() -> 200000000
@@ -0,0 +1,12 @@
contract C {
function f() public view returns (uint ret) {
assembly {
ret := prevrandao()
}
}
}
// ====
// compileToEwasm: also
// EVMVersion: >=paris
// ----
// f() -> 0xa86c2e601b6c44eb4848f7d23d9df3113fbcac42041c49cbed5000cb4f118777
@@ -0,0 +1,10 @@
contract C {
function f() public view returns (uint) {
return block.prevrandao;
}
}
// ====
// compileToEwasm: also
// EVMVersion: >=paris
// ----
// f() -> 0xa86c2e601b6c44eb4848f7d23d9df3113fbcac42041c49cbed5000cb4f118777
@@ -0,0 +1,10 @@
contract C {
function f() public view returns (uint) {
return block.prevrandao;
}
}
// ====
// compileToEwasm: also
// EVMVersion: <paris
// ----
// f() -> 200000000
@@ -0,0 +1,14 @@
contract C {
function f() public view returns (uint256) {
return block.difficulty;
}
function g() public view returns (uint256 ret) {
assembly {
ret := difficulty()
}
}
}
// ====
// EVMVersion: <paris
// ----
@@ -0,0 +1,21 @@
contract C {
function f() public view returns (uint256 ret) {
assembly {
let difficulty := sload(0)
ret := difficulty
}
}
function g() public pure returns (uint256 ret) {
assembly {
function difficulty() -> r {
r := 1000
}
ret := difficulty()
}
}
}
// ====
// EVMVersion: <paris
// ----
// ParserError 5568: (101-111): Cannot use builtin function name "difficulty" as identifier name.
@@ -0,0 +1,9 @@
contract C {
function f() public view returns (uint256) {
return block.difficulty;
}
}
// ====
// EVMVersion: >=paris
// ----
// Warning 8417: (77-93): Since the VM version paris, "difficulty" was replaced by "prevrandao", which now returns a random number based on the beacon chain.
@@ -0,0 +1,12 @@
contract C {
function f() public {
assembly {
pop(difficulty())
}
}
}
// ====
// EVMVersion: >=paris
// ----
// DeclarationError 4619: (74-84): Function "difficulty" not found.
// TypeError 3950: (74-86): Expected expression to evaluate to one value, but got 0 values instead.
@@ -0,0 +1,22 @@
contract C {
function f() public view returns (uint256 ret) {
assembly {
let difficulty := sload(0)
ret := difficulty
}
}
function g() public pure returns (uint256 ret) {
assembly {
function difficulty() -> r {
r := 1000
}
ret := difficulty()
}
}
}
// ====
// EVMVersion: >=paris
// ----
// DeclarationError 5017: (101-111): The identifier "difficulty" is reserved and can not be used.
// DeclarationError 5017: (255-323): The identifier "difficulty" is reserved and can not be used.
@@ -0,0 +1,20 @@
contract C {
function f() public view returns (uint256 ret) {
assembly {
let prevrandao := sload(0)
ret := prevrandao
}
}
function g() public pure returns (uint256 ret) {
assembly {
function prevrandao() -> r {
r := 1000
}
ret := prevrandao()
}
}
}
// ====
// EVMVersion: <paris
// ----
@@ -0,0 +1,14 @@
contract C {
function f() public view returns (uint256) {
return block.prevrandao;
}
function g() public view returns (uint256 ret) {
assembly {
ret := prevrandao()
}
}
}
// ====
// EVMVersion: >=paris
// ----
@@ -0,0 +1,21 @@
contract C {
function f() public view returns (uint256 ret) {
assembly {
let prevrandao := sload(0)
ret := prevrandao
}
}
function g() public pure returns (uint256 ret) {
assembly {
function prevrandao() -> r {
r := 1000
}
ret := prevrandao()
}
}
}
// ====
// EVMVersion: >=paris
// ----
// ParserError 5568: (101-111): Cannot use builtin function name "prevrandao" as identifier name.
@@ -0,0 +1,9 @@
contract C {
function f() public view returns (uint256) {
return block.prevrandao;
}
}
// ====
// EVMVersion: <paris
// ----
// Warning 9432: (77-93): "prevrandao" is not supported by the VM version and will be treated as "difficulty".
@@ -0,0 +1,12 @@
contract C {
function f() public {
assembly {
pop(prevrandao())
}
}
}
// ====
// EVMVersion: <paris
// ----
// DeclarationError 4619: (74-84): Function "prevrandao" not found.
// TypeError 3950: (74-86): Expected expression to evaluate to one value, but got 0 values instead.
@@ -8,6 +8,6 @@ contract C {
}
}
// ====
// EVMVersion: <byzantium
// EVMVersion: =homestead
// ----
// TypeError 9908: (73-106): This catch clause type cannot be used on the selected EVM version (homestead). You need at least a Byzantium-compatible EVM or use `catch { ... }`.
@@ -0,0 +1,13 @@
contract C {
function f() public {
try this.f() {
} catch (bytes memory) {
}
}
}
// ====
// EVMVersion: =spuriousDragon
// ----
// TypeError 9908: (73-106): This catch clause type cannot be used on the selected EVM version (spuriousDragon). You need at least a Byzantium-compatible EVM or use `catch { ... }`.
@@ -0,0 +1,13 @@
contract C {
function f() public {
try this.f() {
} catch (bytes memory) {
}
}
}
// ====
// EVMVersion: =tangerineWhistle
// ----
// TypeError 9908: (73-106): This catch clause type cannot be used on the selected EVM version (tangerineWhistle). You need at least a Byzantium-compatible EVM or use `catch { ... }`.
@@ -8,6 +8,6 @@ contract C {
}
}
// ====
// EVMVersion: <byzantium
// EVMVersion: =homestead
// ----
// TypeError 1812: (73-112): This catch clause type cannot be used on the selected EVM version (homestead). You need at least a Byzantium-compatible EVM or use `catch { ... }`.
@@ -0,0 +1,13 @@
contract C {
function f() public {
try this.f() {
} catch Error(string memory) {
}
}
}
// ====
// EVMVersion: =spuriousDragon
// ----
// TypeError 1812: (73-112): This catch clause type cannot be used on the selected EVM version (spuriousDragon). You need at least a Byzantium-compatible EVM or use `catch { ... }`.
@@ -0,0 +1,13 @@
contract C {
function f() public {
try this.f() {
} catch Error(string memory) {
}
}
}
// ====
// EVMVersion: =tangerineWhistle
// ----
// TypeError 1812: (73-112): This catch clause type cannot be used on the selected EVM version (tangerineWhistle). You need at least a Byzantium-compatible EVM or use `catch { ... }`.
@@ -3,15 +3,12 @@ contract C {
return block.coinbase;
}
function g() public view returns (uint) {
return block.difficulty;
}
function h() public view returns (uint) {
return block.gaslimit;
}
function i() public view returns (uint) {
function h() public view returns (uint) {
return block.timestamp;
}
function j() public view returns (uint) {
function i() public view returns (uint) {
return block.chainid;
}
}
@@ -0,0 +1,13 @@
contract C {
function f() public view returns (uint) {
return block.prevrandao;
}
function g() public view returns (uint ret) {
assembly {
ret := prevrandao()
}
}
}
// ====
// EVMVersion: >=paris
// ----
@@ -73,7 +73,7 @@ contract C {
pop(coinbase())
pop(timestamp())
pop(number())
pop(difficulty())
pop(prevrandao())
pop(gaslimit())
// NOTE: msize() is allowed only with optimizer disabled
@@ -83,7 +83,7 @@ contract C {
}
}
// ====
// EVMVersion: >=london
// EVMVersion: >=paris
// ----
// Warning 5740: (89-1716): Unreachable code.
// Warning 5740: (1729-1741): Unreachable code.
@@ -0,0 +1,11 @@
contract C {
function f() public {
assembly {
pop(difficulty())
}
}
}
// ====
// EVMVersion: <=london
// ----
// Warning 2018: (17-103): Function state mutability can be restricted to view
@@ -73,7 +73,6 @@ contract C {
//pop(coinbase())
//pop(timestamp())
//pop(number())
//pop(difficulty())
//pop(gaslimit())
// NOTE: msize() is allowed only with optimizer disabled
@@ -73,7 +73,7 @@ contract C {
pop(coinbase())
pop(timestamp())
pop(number())
pop(difficulty())
pop(prevrandao())
pop(gaslimit())
// NOTE: msize() is allowed only with optimizer disabled
@@ -83,7 +83,7 @@ contract C {
}
}
// ====
// EVMVersion: >=london
// EVMVersion: >=paris
// ----
// Warning 5740: (94-1733): Unreachable code.
// Warning 5740: (1746-1758): Unreachable code.
@@ -0,0 +1,10 @@
contract C {
function f() public view {
assembly {
pop(difficulty())
}
}
}
// ====
// EVMVersion: <=london
// ----
@@ -6,33 +6,26 @@ contract C {
pop(gas())
pop(address())
pop(balance(0))
pop(selfbalance())
pop(caller())
pop(callvalue())
pop(extcodesize(0))
extcodecopy(0, 1, 2, 3)
pop(extcodehash(0))
pop(create(0, 1, 2))
pop(create2(0, 1, 2, 3))
pop(call(0, 1, 2, 3, 4, 5, 6))
pop(callcode(0, 1, 2, 3, 4, 5, 6))
pop(delegatecall(0, 1, 2, 3, 4, 5))
pop(staticcall(0, 1, 2, 3, 4, 5))
selfdestruct(0)
log0(0, 1)
log1(0, 1, 2)
log2(0, 1, 2, 3)
log3(0, 1, 2, 3, 4)
log4(0, 1, 2, 3, 4, 5)
pop(chainid())
pop(basefee())
pop(origin())
pop(gasprice())
pop(blockhash(0))
pop(coinbase())
pop(timestamp())
pop(number())
pop(difficulty())
pop(gaslimit())
// These two are disallowed too but the error suppresses other errors.
@@ -41,40 +34,31 @@ contract C {
}
}
}
// ====
// EVMVersion: >=london
// ----
// Warning 5740: (672-1083): Unreachable code.
// Warning 5740: (526-853): Unreachable code.
// TypeError 2527: (79-87): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 8961: (101-113): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 2527: (130-135): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (153-162): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (180-190): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (208-221): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (239-247): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (265-276): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (294-308): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (322-345): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (362-376): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 8961: (394-409): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (427-446): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (464-489): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (507-536): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (554-584): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 2527: (602-630): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 8961: (644-659): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (672-682): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (695-708): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (721-737): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (750-769): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (782-804): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 2527: (821-830): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (848-857): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (875-883): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (901-911): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (929-941): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (959-969): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (987-998): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (1016-1024): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (1042-1054): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (1072-1082): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (208-216): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (234-245): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (263-277): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (291-314): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 8961: (331-346): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (364-389): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (407-436): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (454-484): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (498-513): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (526-536): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (549-562): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (575-591): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (604-623): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 8961: (636-658): Function cannot be declared as pure because this expression (potentially) modifies the state.
// TypeError 2527: (675-683): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (701-711): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (729-741): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (759-769): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (787-798): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (816-824): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (842-852): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
@@ -0,0 +1,11 @@
contract C {
function f() public pure {
assembly {
pop(staticcall(0, 1, 2, 3, 4, 5))
}
}
}
// ====
// EVMVersion: >=byzantium
// ----
// TypeError 2527: (79-107): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
@@ -0,0 +1,13 @@
contract C {
function f() public pure {
assembly {
pop(extcodehash(0))
pop(create2(0, 1, 2, 3))
}
}
}
// ====
// EVMVersion: >=constantinople
// ----
// TypeError 2527: (79-93): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 8961: (111-130): Function cannot be declared as pure because this expression (potentially) modifies the state.
@@ -0,0 +1,13 @@
contract C {
function f() public pure {
assembly {
pop(selfbalance())
pop(chainid())
}
}
}
// ====
// EVMVersion: >=istanbul
// ----
// TypeError 2527: (79-92): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (110-119): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
@@ -0,0 +1,11 @@
contract C {
function f() public pure {
assembly {
pop(basefee())
}
}
}
// ====
// EVMVersion: >=london
// ----
// TypeError 2527: (79-88): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
@@ -0,0 +1,11 @@
contract C {
function f() public pure {
assembly {
pop(prevrandao())
}
}
}
// ====
// EVMVersion: >=paris
// ----
// TypeError 2527: (79-91): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
@@ -0,0 +1,11 @@
contract C {
function f() public pure {
assembly {
pop(difficulty())
}
}
}
// ====
// EVMVersion: <=london
// ----
// TypeError 2527: (79-91): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
+3 -1
View File
@@ -19,6 +19,8 @@
#include <test/libyul/EVMCodeTransformTest.h>
#include <test/libyul/Common.h>
#include <test/Common.h>
#include <libyul/YulStack.h>
#include <libyul/backends/evm/EthAssemblyAdapter.h>
#include <libyul/backends/evm/EVMObjectCompiler.h>
@@ -66,7 +68,7 @@ TestCase::TestResult EVMCodeTransformTest::run(ostream& _stream, string const& _
return TestResult::FatalError;
}
evmasm::Assembly assembly{false, {}};
evmasm::Assembly assembly{solidity::test::CommonOptions::get().evmVersion(), false, {}};
EthAssemblyAdapter adapter(assembly);
EVMObjectCompiler::compile(
*stack.parserResult(),
+3 -1
View File
@@ -20,6 +20,8 @@
#include <test/libsolidity/util/SoltestErrors.h>
#include <test/Common.h>
#include <libsolutil/AnsiColorized.h>
#include <libyul/YulStack.h>
@@ -101,7 +103,7 @@ TestCase::TestResult ObjectCompilerTest::run(ostream& _stream, string const& _li
"Bytecode: " +
util::toHex(obj.bytecode->bytecode) +
"\nOpcodes: " +
boost::trim_copy(evmasm::disassemble(obj.bytecode->bytecode)) +
boost::trim_copy(evmasm::disassemble(obj.bytecode->bytecode, solidity::test::CommonOptions::get().evmVersion())) +
"\nSourceMappings:" +
(obj.sourceMappings->empty() ? "" : " " + *obj.sourceMappings) +
"\n";
+1 -1
View File
@@ -98,7 +98,7 @@ string YulInterpreterTest::interpret()
{
Interpreter::run(
state,
EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion{}),
EVMDialect::strictAssemblyForEVMObjects(solidity::test::CommonOptions::get().evmVersion()),
*m_ast,
/*disableExternalCalls=*/ !m_simulateExternalCallsToSelf,
/*disableMemoryTracing=*/ false
@@ -1,6 +1,8 @@
{
sstore(0, difficulty())
}
// ====
// EVMVersion: <paris
// ----
// Trace:
// Memory dump:
@@ -0,0 +1,10 @@
{
sstore(0, difficulty())
}
// ====
// EVMVersion: <paris
// ----
// Trace:
// Memory dump:
// Storage dump:
// 0000000000000000000000000000000000000000000000000000000000000000: 0000000000000000000000000000000000000000000000000000000009999999
@@ -0,0 +1,10 @@
{
sstore(0, prevrandao())
}
// ====
// EVMVersion: >=paris
// ----
// Trace:
// Memory dump:
// Storage dump:
// 0000000000000000000000000000000000000000000000000000000000000000: 0000000000000000000000000000000000000000000000010000000000000001
+1 -1
View File
@@ -189,7 +189,7 @@ void FuzzerUtil::testConstantOptimizer(string const& _input, bool _quiet)
for (bool isCreation: {false, true})
{
Assembly assembly{isCreation, {}};
Assembly assembly{langutil::EVMVersion{}, isCreation, {}};
for (u256 const& n: numbers)
{
if (!_quiet)
@@ -98,7 +98,7 @@ u256 EVMInstructionInterpreter::eval(
using namespace solidity::evmasm;
using evmasm::Instruction;
auto info = instructionInfo(_instruction);
auto info = instructionInfo(_instruction, m_evmVersion);
yulAssert(static_cast<size_t>(info.args) == _arguments.size(), "");
auto const& arg = _arguments;
@@ -268,8 +268,8 @@ u256 EVMInstructionInterpreter::eval(
return m_state.timestamp;
case Instruction::NUMBER:
return m_state.blockNumber;
case Instruction::DIFFICULTY:
return m_state.difficulty;
case Instruction::PREVRANDAO:
return (m_evmVersion < langutil::EVMVersion::paris()) ? m_state.difficulty : m_state.prevrandao;
case Instruction::GASLIMIT:
return m_state.gaslimit;
// --------------- memory / storage / logs ---------------
@@ -543,7 +543,7 @@ void EVMInstructionInterpreter::logTrace(
)
{
logTrace(
evmasm::instructionInfo(_instruction).name,
evmasm::instructionInfo(_instruction, m_evmVersion).name,
SemanticInformation::memory(_instruction) == SemanticInformation::Effect::Write,
_arguments,
_data
@@ -26,6 +26,8 @@
#include <libsolutil/CommonData.h>
#include <libsolutil/Numeric.h>
#include <liblangutil/EVMVersion.h>
#include <vector>
namespace solidity::evmasm
@@ -74,7 +76,8 @@ struct InterpreterState;
class EVMInstructionInterpreter
{
public:
explicit EVMInstructionInterpreter(InterpreterState& _state, bool _disableMemWriteTrace):
explicit EVMInstructionInterpreter(langutil::EVMVersion _evmVersion, InterpreterState& _state, bool _disableMemWriteTrace):
m_evmVersion(_evmVersion),
m_state(_state),
m_disableMemoryWriteInstructions(_disableMemWriteTrace)
{}
@@ -128,6 +131,7 @@ private:
return m_disableMemoryWriteInstructions;
}
langutil::EVMVersion m_evmVersion;
InterpreterState& m_state;
/// Flag to disable trace of instructions that write to memory.
bool m_disableMemoryWriteInstructions;
@@ -597,7 +597,7 @@ u256 EwasmBuiltinInterpreter::readU256(uint64_t _offset, size_t _croppedTo)
void EwasmBuiltinInterpreter::logTrace(evmasm::Instruction _instruction, std::vector<u256> const& _arguments, bytes const& _data)
{
logTrace(evmasm::instructionInfo(_instruction).name, _arguments, _data);
logTrace(evmasm::instructionInfo(_instruction, langutil::EVMVersion()).name, _arguments, _data);
}
void EwasmBuiltinInterpreter::logTrace(std::string const& _pseudoInstruction, std::vector<u256> const& _arguments, bytes const& _data)
+1 -1
View File
@@ -314,7 +314,7 @@ void ExpressionEvaluator::operator()(FunctionCall const& _funCall)
{
if (BuiltinFunctionForEVM const* fun = dialect->builtin(_funCall.functionName.name))
{
EVMInstructionInterpreter interpreter(m_state, m_disableMemoryTrace);
EVMInstructionInterpreter interpreter(dialect->evmVersion(), m_state, m_disableMemoryTrace);
u256 const value = interpreter.evalBuiltin(*fun, _funCall.arguments, values());
+1
View File
@@ -94,6 +94,7 @@ struct InterpreterState
u256 timestamp = 0x88888888;
u256 blockNumber = 1024;
u256 difficulty = 0x9999999;
u256 prevrandao = (u256(1) << 64) + 1;
u256 gaslimit = 4000000;
u256 chainid = 0x01;
/// The minimum value of basefee: 7 wei.