wipAdd VM Version Paris and new built in function `prevrandaoAdd VM Version Paris and new built in function prevrandao`

This commit is contained in:
Marenz 2022-09-27 19:39:17 +02:00
parent 70b0fb6366
commit 2dc5435c19
32 changed files with 249 additions and 34 deletions

View File

@ -31,7 +31,7 @@ REPODIR="$(realpath "$(dirname "$0")"/..)"
# shellcheck source=scripts/common.sh # shellcheck source=scripts/common.sh
source "${REPODIR}/scripts/common.sh" source "${REPODIR}/scripts/common.sh"
EVM_VALUES=(homestead byzantium constantinople petersburg istanbul berlin london) EVM_VALUES=(homestead byzantium constantinople petersburg istanbul berlin london paris)
DEFAULT_EVM=london DEFAULT_EVM=london
[[ " ${EVM_VALUES[*]} " =~ $DEFAULT_EVM ]] [[ " ${EVM_VALUES[*]} " =~ $DEFAULT_EVM ]]
OPTIMIZE_VALUES=(0 1) OPTIMIZE_VALUES=(0 1)

View File

@ -1,12 +1,13 @@
### 0.8.18 (unreleased) ### 0.8.18 (unreleased)
Language Features: Language Features:
* Add support for ``prevrandao()`` which was introduced in EVM version to "Paris", supplanting ``difficulty`` in the process. Both can be used interchangeably.
Compiler Features: Compiler Features:
* Commandline Interface: Add `--no-cbor-metadata` that skips CBOR metadata from getting appended at the end of the bytecode. * Commandline Interface: Add `--no-cbor-metadata` that skips CBOR metadata from getting appended at the end of the bytecode.
* Standard JSON: Add a boolean field `settings.metadata.appendCBOR` that skips CBOR metadata from getting appended at the end of the bytecode. * Standard JSON: Add a boolean field `settings.metadata.appendCBOR` that skips CBOR metadata from getting appended at the end of the bytecode.
* Yul Optimizer: Allow replacing the previously hard-coded cleanup sequence by specifying custom steps after a colon delimiter (``:``) in the sequence string. * Yul Optimizer: Allow replacing the previously hard-coded cleanup sequence by specifying custom steps after a colon delimiter (``:``) in the sequence string.
Bugfixes: Bugfixes:

View File

@ -8,7 +8,7 @@ Order of Precedence of Operators
================================ ================================
.. include:: types/operator-precedence-table.rst .. include:: types/operator-precedence-table.rst
.. index:: assert, block, coinbase, difficulty, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, gas price, origin, revert, require, keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, codehash, send .. index:: assert, block, coinbase, difficulty, prevrandao, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, gas price, origin, revert, require, keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, codehash, send
Global Variables Global Variables
================ ================
@ -33,6 +33,7 @@ Global Variables
- ``block.chainid`` (``uint``): current chain id - ``block.chainid`` (``uint``): current chain id
- ``block.coinbase`` (``address payable``): current block miner's address - ``block.coinbase`` (``address payable``): current block miner's address
- ``block.difficulty`` (``uint``): current block difficulty - ``block.difficulty`` (``uint``): current block difficulty
- ``block.prevrandao`` (``uint``): randomness provided by the beacon chain
- ``block.gaslimit`` (``uint``): current block gaslimit - ``block.gaslimit`` (``uint``): current block gaslimit
- ``block.number`` (``uint``): current block number - ``block.number`` (``uint``): current block number
- ``block.timestamp`` (``uint``): current block timestamp in seconds since Unix epoch - ``block.timestamp`` (``uint``): current block timestamp in seconds since Unix epoch

View File

@ -291,8 +291,8 @@ YulEVMBuiltin:
| 'returndatacopy' | 'extcodehash' | 'create' | 'create2' | 'call' | 'callcode' | 'returndatacopy' | 'extcodehash' | 'create' | 'create2' | 'call' | 'callcode'
| 'delegatecall' | 'staticcall' | 'return' | 'revert' | 'selfdestruct' | 'invalid' | 'delegatecall' | 'staticcall' | 'return' | 'revert' | 'selfdestruct' | 'invalid'
| 'log0' | 'log1' | 'log2' | 'log3' | 'log4' | 'chainid' | 'origin' | 'gasprice' | 'log0' | 'log1' | 'log2' | 'log3' | 'log4' | 'chainid' | 'origin' | 'gasprice'
| 'blockhash' | 'coinbase' | 'timestamp' | 'number' | 'difficulty' | 'gaslimit' | 'blockhash' | 'coinbase' | 'timestamp' | 'number' | 'difficulty' | 'prevrandao'
| 'basefee'; | 'gaslimit' | 'basefee';
YulLBrace: '{' -> pushMode(YulMode); YulLBrace: '{' -> pushMode(YulMode);
YulRBrace: '}' -> popMode; YulRBrace: '}' -> popMode;

View File

@ -65,7 +65,7 @@ There are special variables and functions which always exist in the global
namespace and are mainly used to provide information about the blockchain namespace and are mainly used to provide information about the blockchain
or are general-use utility functions. or are general-use utility functions.
.. index:: abi, block, coinbase, difficulty, encode, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, gas price, origin .. index:: abi, block, coinbase, difficulty, prevrandao, encode, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, gas price, origin
Block and Transaction Properties Block and Transaction Properties
@ -76,6 +76,7 @@ Block and Transaction Properties
- ``block.chainid`` (``uint``): current chain id - ``block.chainid`` (``uint``): current chain id
- ``block.coinbase`` (``address payable``): current block miner's address - ``block.coinbase`` (``address payable``): current block miner's address
- ``block.difficulty`` (``uint``): current block difficulty - ``block.difficulty`` (``uint``): current block difficulty
- ``block.prevrandao`` (``uint``): randomness provided by the beacon chain
- ``block.gaslimit`` (``uint``): current block gaslimit - ``block.gaslimit`` (``uint``): current block gaslimit
- ``block.number`` (``uint``): current block number - ``block.number`` (``uint``): current block number
- ``block.timestamp`` (``uint``): current block timestamp as seconds since unix epoch - ``block.timestamp`` (``uint``): current block timestamp as seconds since unix epoch

View File

@ -172,6 +172,9 @@ at each version. Backward compatibility is not guaranteed between each version.
the optimizer. the optimizer.
- ``london`` (**default**) - ``london`` (**default**)
- The block's base fee (`EIP-3198 <https://eips.ethereum.org/EIPS/eip-3198>`_ and `EIP-1559 <https://eips.ethereum.org/EIPS/eip-1559>`_) can be accessed via the global ``block.basefee`` or ``basefee()`` in inline assembly. - The block's base fee (`EIP-3198 <https://eips.ethereum.org/EIPS/eip-3198>`_ and `EIP-1559 <https://eips.ethereum.org/EIPS/eip-1559>`_) can be accessed via the global ``block.basefee`` or ``basefee()`` in inline assembly.
- ``paris``
- The ``difficulty`` opcode was supplanted by the new opcode ``prevrandao`` (`EIP-4399 <https://eips.ethereum.org/EIPS/eip-4399>`_).
Both can be used interchangeably. ``prevrandao`` is a reserved keyword in yul code.
.. index:: ! standard JSON, ! --standard-json .. index:: ! standard JSON, ! --standard-json

View File

@ -755,8 +755,8 @@ This document does not want to be a full description of the Ethereum virtual mac
Please refer to a different document if you are interested in the precise semantics. Please refer to a different document if you are interested in the precise semantics.
Opcodes marked with ``-`` do not return a result and all others return exactly one value. Opcodes marked with ``-`` do not return a result and all others return exactly one value.
Opcodes marked with ``F``, ``H``, ``B``, ``C``, ``I`` and ``L`` are present since Frontier, Homestead, Opcodes marked with ``F``, ``H``, ``B``, ``C``, ``I``, ``L`` and ``P`` are present since Frontier, Homestead,
Byzantium, Constantinople, Istanbul or London respectively. Byzantium, Constantinople, Istanbul, London or Paris respectively.
In the following, ``mem[a...b)`` signifies the bytes of memory starting at position ``a`` up to In the following, ``mem[a...b)`` signifies the bytes of memory starting at position ``a`` up to
but not including position ``b`` and ``storage[p]`` signifies the storage contents at slot ``p``. but not including position ``b`` and ``storage[p]`` signifies the storage contents at slot ``p``.
@ -933,7 +933,11 @@ the ``dup`` and ``swap`` instructions as well as ``jump`` instructions, labels a
+-------------------------+-----+---+-----------------------------------------------------------------+ +-------------------------+-----+---+-----------------------------------------------------------------+
| number() | | F | current block number | | number() | | F | current block number |
+-------------------------+-----+---+-----------------------------------------------------------------+ +-------------------------+-----+---+-----------------------------------------------------------------+
| difficulty() | | F | difficulty of the current block | | difficulty() | | F | difficulty of the current block, supplanted by ``prevrandao()`` |
| | | | in evm version paris |
+-------------------------+-----+---+-----------------------------------------------------------------+
| prevrandao() | | P | randomness provided by the beacon chain, supplants |
| | | | ``difficulty()`` starting with evm version paris |
+-------------------------+-----+---+-----------------------------------------------------------------+ +-------------------------+-----+---+-----------------------------------------------------------------+
| gaslimit() | | F | block gas limit of the current block | | gaslimit() | | F | block gas limit of the current block |
+-------------------------+-----+---+-----------------------------------------------------------------+ +-------------------------+-----+---+-----------------------------------------------------------------+

View File

@ -77,6 +77,7 @@ std::map<std::string, Instruction> const solidity::evmasm::c_instructions =
{ "TIMESTAMP", Instruction::TIMESTAMP }, { "TIMESTAMP", Instruction::TIMESTAMP },
{ "NUMBER", Instruction::NUMBER }, { "NUMBER", Instruction::NUMBER },
{ "DIFFICULTY", Instruction::DIFFICULTY }, { "DIFFICULTY", Instruction::DIFFICULTY },
{ "PREVRANDAO", Instruction::PREVRANDAO },
{ "GASLIMIT", Instruction::GASLIMIT }, { "GASLIMIT", Instruction::GASLIMIT },
{ "CHAINID", Instruction::CHAINID }, { "CHAINID", Instruction::CHAINID },
{ "SELFBALANCE", Instruction::SELFBALANCE }, { "SELFBALANCE", Instruction::SELFBALANCE },
@ -223,6 +224,8 @@ static std::map<Instruction, InstructionInfo> const c_instructionInfo =
{ Instruction::COINBASE, { "COINBASE", 0, 0, 1, false, Tier::Base } }, { Instruction::COINBASE, { "COINBASE", 0, 0, 1, false, Tier::Base } },
{ Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1, false, Tier::Base } }, { Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1, false, Tier::Base } },
{ Instruction::NUMBER, { "NUMBER", 0, 0, 1, false, Tier::Base } }, { Instruction::NUMBER, { "NUMBER", 0, 0, 1, false, Tier::Base } },
// { Instruction::PREVRANDAO, { "PREVRANDAO", 0, 0, 1, false, Tier::Base } },
// TODO Replace with PREVRANDAO in the next breaking release
{ Instruction::DIFFICULTY, { "DIFFICULTY", 0, 0, 1, false, Tier::Base } }, { Instruction::DIFFICULTY, { "DIFFICULTY", 0, 0, 1, false, Tier::Base } },
{ Instruction::GASLIMIT, { "GASLIMIT", 0, 0, 1, false, Tier::Base } }, { Instruction::GASLIMIT, { "GASLIMIT", 0, 0, 1, false, Tier::Base } },
{ Instruction::CHAINID, { "CHAINID", 0, 0, 1, false, Tier::Base } }, { Instruction::CHAINID, { "CHAINID", 0, 0, 1, false, Tier::Base } },

View File

@ -84,7 +84,8 @@ enum class Instruction: uint8_t
TIMESTAMP, ///< get the block's timestamp TIMESTAMP, ///< get the block's timestamp
NUMBER, ///< get the block's number NUMBER, ///< get the block's number
DIFFICULTY, ///< get the block's difficulty DIFFICULTY, ///< get the block's difficulty
GASLIMIT, ///< get the block's gas limit PREVRANDAO = DIFFICULTY, ///< get randomness provided by the beacon chain
GASLIMIT = 0x45, ///< get the block's gas limit
CHAINID, ///< get the config's chainid param CHAINID, ///< get the config's chainid param
SELFBALANCE, ///< get balance of the current account SELFBALANCE, ///< get balance of the current account
BASEFEE, ///< get the block's basefee BASEFEE, ///< get the block's basefee

View File

@ -123,6 +123,7 @@ struct EVMBuiltins
static auto constexpr TIMESTAMP = PatternGenerator<Instruction::TIMESTAMP>{}; static auto constexpr TIMESTAMP = PatternGenerator<Instruction::TIMESTAMP>{};
static auto constexpr NUMBER = PatternGenerator<Instruction::NUMBER>{}; static auto constexpr NUMBER = PatternGenerator<Instruction::NUMBER>{};
static auto constexpr DIFFICULTY = PatternGenerator<Instruction::DIFFICULTY>{}; static auto constexpr DIFFICULTY = PatternGenerator<Instruction::DIFFICULTY>{};
static auto constexpr PREVRANDAO = PatternGenerator<Instruction::PREVRANDAO>{};
static auto constexpr GASLIMIT = PatternGenerator<Instruction::GASLIMIT>{}; static auto constexpr GASLIMIT = PatternGenerator<Instruction::GASLIMIT>{};
static auto constexpr CHAINID = PatternGenerator<Instruction::CHAINID>{}; static auto constexpr CHAINID = PatternGenerator<Instruction::CHAINID>{};
static auto constexpr SELFBALANCE = PatternGenerator<Instruction::SELFBALANCE>{}; static auto constexpr SELFBALANCE = PatternGenerator<Instruction::SELFBALANCE>{};

View File

@ -52,10 +52,11 @@ public:
static EVMVersion istanbul() { return {Version::Istanbul}; } static EVMVersion istanbul() { return {Version::Istanbul}; }
static EVMVersion berlin() { return {Version::Berlin}; } static EVMVersion berlin() { return {Version::Berlin}; }
static EVMVersion london() { return {Version::London}; } static EVMVersion london() { return {Version::London}; }
static EVMVersion paris() { return {Version::Paris}; }
static std::optional<EVMVersion> fromString(std::string const& _version) static std::optional<EVMVersion> fromString(std::string const& _version)
{ {
for (auto const& v: {homestead(), tangerineWhistle(), spuriousDragon(), byzantium(), constantinople(), petersburg(), istanbul(), berlin(), london()}) for (auto const& v: {homestead(), tangerineWhistle(), spuriousDragon(), byzantium(), constantinople(), petersburg(), istanbul(), berlin(), london(), paris()})
if (_version == v.name()) if (_version == v.name())
return v; return v;
return std::nullopt; return std::nullopt;
@ -77,6 +78,7 @@ public:
case Version::Istanbul: return "istanbul"; case Version::Istanbul: return "istanbul";
case Version::Berlin: return "berlin"; case Version::Berlin: return "berlin";
case Version::London: return "london"; case Version::London: return "london";
case Version::Paris: return "paris";
} }
return "INVALID"; return "INVALID";
} }
@ -90,6 +92,8 @@ public:
bool hasChainID() const { return *this >= istanbul(); } bool hasChainID() const { return *this >= istanbul(); }
bool hasSelfBalance() const { return *this >= istanbul(); } bool hasSelfBalance() const { return *this >= istanbul(); }
bool hasBaseFee() const { return *this >= london(); } bool hasBaseFee() const { return *this >= london(); }
bool hasPrevRandao() const { return *this >= paris(); }
bool hasDifficulty() const { return *this < paris(); }
bool hasOpcode(evmasm::Instruction _opcode) const; bool hasOpcode(evmasm::Instruction _opcode) const;
@ -98,11 +102,11 @@ public:
bool canOverchargeGasForCall() const { return *this >= tangerineWhistle(); } bool canOverchargeGasForCall() const { return *this >= tangerineWhistle(); }
private: private:
enum class Version { Homestead, TangerineWhistle, SpuriousDragon, Byzantium, Constantinople, Petersburg, Istanbul, Berlin, London }; enum class Version { Homestead, TangerineWhistle, SpuriousDragon, Byzantium, Constantinople, Petersburg, Istanbul, Berlin, London, Paris };
EVMVersion(Version _version): m_version(_version) {} EVMVersion(Version _version): m_version(_version) {}
Version m_version = Version::London; Version m_version = Version::Paris;
}; };
} }

View File

@ -3286,18 +3286,33 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
(memberName == "min" || memberName == "max") (memberName == "min" || memberName == "max")
) )
annotation.isPure = true; annotation.isPure = true;
else if (magicType->kind() == MagicType::Kind::Block && memberName == "chainid" && !m_evmVersion.hasChainID()) else if (magicType->kind() == MagicType::Kind::Block)
{
if (memberName == "chainid" && !m_evmVersion.hasChainID())
m_errorReporter.typeError( m_errorReporter.typeError(
3081_error, 3081_error,
_memberAccess.location(), _memberAccess.location(),
"\"chainid\" is not supported by the VM version." "\"chainid\" is not supported by the VM version."
); );
else if (magicType->kind() == MagicType::Kind::Block && memberName == "basefee" && !m_evmVersion.hasBaseFee()) else if (memberName == "basefee" && !m_evmVersion.hasBaseFee())
m_errorReporter.typeError( m_errorReporter.typeError(
5921_error, 5921_error,
_memberAccess.location(), _memberAccess.location(),
"\"basefee\" is not supported by the VM version." "\"basefee\" is not supported by the VM version."
); );
else if (memberName == "difficulty" && m_evmVersion.hasPrevRandao())
m_errorReporter.warning(
8417_error,
_memberAccess.location(),
"\"difficulty\" was renamed and supplanted by \"prevrandao\" in the VM version paris."
);
else if (memberName == "prevrandao" && !m_evmVersion.hasPrevRandao())
m_errorReporter.warning(
9432_error,
_memberAccess.location(),
"\"prevrandao\" is not supported by the VM version and will be treated like \"difficulty\"."
);
}
} }
if ( if (

View File

@ -4059,6 +4059,7 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
{"timestamp", TypeProvider::uint256()}, {"timestamp", TypeProvider::uint256()},
{"blockhash", TypeProvider::function(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, StateMutability::View)}, {"blockhash", TypeProvider::function(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, StateMutability::View)},
{"difficulty", TypeProvider::uint256()}, {"difficulty", TypeProvider::uint256()},
{"prevrandao", TypeProvider::uint256()},
{"number", TypeProvider::uint256()}, {"number", TypeProvider::uint256()},
{"gaslimit", TypeProvider::uint256()}, {"gaslimit", TypeProvider::uint256()},
{"chainid", TypeProvider::uint256()}, {"chainid", TypeProvider::uint256()},

View File

@ -1810,6 +1810,8 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
m_context << Instruction::TIMESTAMP; m_context << Instruction::TIMESTAMP;
else if (member == "difficulty") else if (member == "difficulty")
m_context << Instruction::DIFFICULTY; m_context << Instruction::DIFFICULTY;
else if (member == "prevrandao")
m_context << Instruction::PREVRANDAO;
else if (member == "number") else if (member == "number")
m_context << Instruction::NUMBER; m_context << Instruction::NUMBER;
else if (member == "gaslimit") else if (member == "gaslimit")

View File

@ -1822,8 +1822,13 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
define(_memberAccess) << "coinbase()\n"; define(_memberAccess) << "coinbase()\n";
else if (member == "timestamp") else if (member == "timestamp")
define(_memberAccess) << "timestamp()\n"; define(_memberAccess) << "timestamp()\n";
else if (member == "difficulty") else if (member == "difficulty" || member == "prevrandao")
{
if (m_context.evmVersion().hasPrevRandao())
define(_memberAccess) << "prevrandao()\n";
else
define(_memberAccess) << "difficulty()\n"; define(_memberAccess) << "difficulty()\n";
}
else if (member == "number") else if (member == "number")
define(_memberAccess) << "number()\n"; define(_memberAccess) << "number()\n";
else if (member == "gaslimit") else if (member == "gaslimit")

View File

@ -118,12 +118,19 @@ set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion)
{ {
return _instr == evmasm::Instruction::BASEFEE && _evmVersion < langutil::EVMVersion::london(); return _instr == evmasm::Instruction::BASEFEE && _evmVersion < langutil::EVMVersion::london();
}; };
// TODO remove this in 0.9.0. We allow creating functions or identifiers in Yul with the name
// prevrandao for VMs before paris.
auto prevRandAOException = [&](string const& _instrName) -> bool
{
// Using string comparison as the opcode is the same as for "difficulty"
return _instrName == "prevrandao" && _evmVersion < langutil::EVMVersion::paris();
};
set<YulString> reserved; set<YulString> reserved;
for (auto const& instr: evmasm::c_instructions) for (auto const& instr: evmasm::c_instructions)
{ {
string name = toLower(instr.first); string name = toLower(instr.first);
if (!baseFeeException(instr.second)) if (!baseFeeException(instr.second) && !prevRandAOException(name))
reserved.emplace(name); reserved.emplace(name);
} }
reserved += vector<YulString>{ reserved += vector<YulString>{
@ -139,6 +146,17 @@ set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion)
map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVersion, bool _objectAccess) map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVersion, bool _objectAccess)
{ {
auto hasOpCode = [&](evmasm::Instruction _instr, string const& _instrName) -> bool
{
if (
_instr == evmasm::Instruction::PREVRANDAO &&
_instrName == "prevrandao"
)
return _evmVersion.hasPrevRandao();
return _evmVersion.hasOpcode(_instr);
};
map<YulString, BuiltinFunctionForEVM> builtins; map<YulString, BuiltinFunctionForEVM> builtins;
for (auto const& instr: evmasm::c_instructions) for (auto const& instr: evmasm::c_instructions)
{ {
@ -152,7 +170,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
opcode != evmasm::Instruction::JUMP && opcode != evmasm::Instruction::JUMP &&
opcode != evmasm::Instruction::JUMPI && opcode != evmasm::Instruction::JUMPI &&
opcode != evmasm::Instruction::JUMPDEST && opcode != evmasm::Instruction::JUMPDEST &&
_evmVersion.hasOpcode(opcode) hasOpCode(opcode, name)
) )
builtins.emplace(createEVMFunction(name, opcode)); builtins.emplace(createEVMFunction(name, opcode));
} }

View File

@ -121,6 +121,9 @@ done < <(
grep -v -E 'revertStatement/non_called.sol' | grep -v -E 'revertStatement/non_called.sol' |
# Skipping a test with "let basefee := ..." # Skipping a test with "let basefee := ..."
grep -v -E 'inlineAssembly/basefee_berlin_function.sol' | grep -v -E 'inlineAssembly/basefee_berlin_function.sol' |
# Skipping tests with "let prevrandao := ..."
grep -v -E 'inlineAssembly/prevrandao_pre_paris_function.sol' |
grep -v -E 'inlineAssembly/prevrandao_reserved_paris.sol' |
# Skipping license error, unrelated to the grammar # Skipping license error, unrelated to the grammar
grep -v -E 'license/license_double5.sol' | grep -v -E 'license/license_double5.sol' |
grep -v -E 'license/license_hidden_unicode.sol' | grep -v -E 'license/license_hidden_unicode.sol' |

View File

@ -122,6 +122,8 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm):
m_evmRevision = EVMC_BERLIN; m_evmRevision = EVMC_BERLIN;
else if (_evmVersion == langutil::EVMVersion::london()) else if (_evmVersion == langutil::EVMVersion::london())
m_evmRevision = EVMC_LONDON; m_evmRevision = EVMC_LONDON;
else if (_evmVersion == langutil::EVMVersion::paris())
m_evmRevision = EVMC_PARIS;
else else
assertThrow(false, Exception, "Unsupported EVM version"); assertThrow(false, Exception, "Unsupported EVM version");

View File

@ -832,12 +832,19 @@ enum evmc_revision
*/ */
EVMC_LONDON = 9, EVMC_LONDON = 9,
/**
* The Paris revision.
*
* https://github.com/ethereum/eth1.0-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md
*/
EVMC_PARIS = 10,
/** /**
* The Shanghai revision. * The Shanghai revision.
* *
* https://github.com/ethereum/eth1.0-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md * https://github.com/ethereum/eth1.0-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md
*/ */
EVMC_SHANGHAI = 10, EVMC_SHANGHAI = 11,
/** The maximum EVM revision supported. */ /** The maximum EVM revision supported. */
EVMC_MAX_REVISION = EVMC_SHANGHAI, EVMC_MAX_REVISION = EVMC_SHANGHAI,

View File

@ -0,0 +1,21 @@
contract C {
function f() public view returns (uint ret) {
assembly {
let prevrandao := sload(0)
ret := prevrandao
}
}
function g() public pure returns (uint ret) {
assembly {
function prevrandao() -> r {
r := 1000
}
ret := prevrandao()
}
}
}
// ====
// EVMVersion: <paris
// ----
// f() -> 0
// g() -> 1000

View File

@ -0,0 +1,6 @@
function f() view returns (uint) {
return block.difficulty;
}
// ====
// EVMVersion: <paris
// ----

View File

@ -0,0 +1,18 @@
contract C {
function f() public view returns (uint ret) {
assembly {
let difficulty := sload(0)
ret := difficulty
}
}
function g() public pure returns (uint ret) {
assembly {
function difficulty() -> r {
r := 1000
}
ret := difficulty()
}
}
}
// ----
// ParserError 5568: (98-108): Cannot use builtin function name "difficulty" as identifier name.

View File

@ -0,0 +1,7 @@
function f() view returns (uint) {
return block.difficulty;
}
// ====
// EVMVersion: >=paris
// ----
// Warning 8417: (43-59): "difficulty" was renamed and supplanted by "prevrandao" in the VM version paris.

View File

@ -0,0 +1,6 @@
function f() view returns (uint) {
return block.prevrandao;
}
// ====
// EVMVersion: >=paris
// ----

View File

@ -0,0 +1,20 @@
contract C {
function f() public view returns (uint ret) {
assembly {
let prevrandao := sload(0)
ret := prevrandao
}
}
function g() public pure returns (uint ret) {
assembly {
function prevrandao() -> r {
r := 1000
}
ret := prevrandao()
}
}
}
// ====
// EVMVersion: >=paris
// ----
// ParserError 5568: (98-108): Cannot use builtin function name "prevrandao" as identifier name.

View File

@ -0,0 +1,7 @@
function f() view returns (uint) {
return block.prevrandao;
}
// ====
// EVMVersion: <paris
// ----
// Warning 9432: (43-59): "prevrandao" is not supported by the VM version and will be treated like "difficulty".

View File

@ -2,9 +2,6 @@ contract C {
function f() public view returns (address payable) { function f() public view returns (address payable) {
return block.coinbase; return block.coinbase;
} }
function g() public view returns (uint) {
return block.difficulty;
}
function h() public view returns (uint) { function h() public view returns (uint) {
return block.gaslimit; return block.gaslimit;
} }

View File

@ -74,6 +74,7 @@ contract C {
//pop(timestamp()) //pop(timestamp())
//pop(number()) //pop(number())
//pop(difficulty()) //pop(difficulty())
//pop(prevrandao())
//pop(gaslimit()) //pop(gaslimit())
// NOTE: msize() is allowed only with optimizer disabled // NOTE: msize() is allowed only with optimizer disabled

View File

@ -73,7 +73,7 @@ contract C {
pop(coinbase()) pop(coinbase())
pop(timestamp()) pop(timestamp())
pop(number()) pop(number())
pop(difficulty()) pop(prevrandao())
pop(gaslimit()) pop(gaslimit())
// NOTE: msize() is allowed only with optimizer disabled // 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: (94-1733): Unreachable code.
// Warning 5740: (1746-1758): Unreachable code. // Warning 5740: (1746-1758): Unreachable code.

View File

@ -0,0 +1,15 @@
contract C {
function f() public view {
assembly {
// Renamed in paris
pop(difficulty())
}
}
}
// ====
// EVMVersion: =london
// ----
// Warning 5740: (94-1733): Unreachable code.
// Warning 5740: (1746-1758): Unreachable code.
// Warning 5740: (1801-1810): Unreachable code.
// Warning 5740: (1978-2244): Unreachable code.

View File

@ -32,7 +32,7 @@ contract C {
pop(coinbase()) pop(coinbase())
pop(timestamp()) pop(timestamp())
pop(number()) pop(number())
pop(difficulty()) pop(prevrandao())
pop(gaslimit()) pop(gaslimit())
// These two are disallowed too but the error suppresses other errors. // These two are disallowed too but the error suppresses other errors.
@ -42,7 +42,7 @@ contract C {
} }
} }
// ==== // ====
// EVMVersion: >=london // EVMVersion: >=paris
// ---- // ----
// Warning 5740: (672-1083): Unreachable code. // Warning 5740: (672-1083): 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 2527: (79-87): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".

View File

@ -0,0 +1,45 @@
contract C {
function f() public pure {
assembly {
// Renamed in paris
pop(difficulty())
}
}
}
// ====
// EVMVersion: =london
// ----
// Warning 5740: (672-1083): 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".