Merge pull request #11647 from ethereum/basefee

Implement London EVMVersion and the BASEFEE opcode
This commit is contained in:
Harikrishnan Mulackal 2021-08-11 10:31:22 +02:00 committed by GitHub
commit 0fc3e2dfb3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 103 additions and 10 deletions

View File

@ -28,7 +28,7 @@ set -e
REPODIR="$(realpath "$(dirname "$0")"/..)"
EVM_VALUES=(homestead byzantium constantinople petersburg istanbul berlin)
EVM_VALUES=(homestead byzantium constantinople petersburg istanbul berlin london)
DEFAULT_EVM=berlin
[[ " ${EVM_VALUES[*]} " =~ $DEFAULT_EVM ]]
OPTIMIZE_VALUES=(0 1)

View File

@ -1,6 +1,8 @@
### 0.8.7 (unreleased)
Language Features:
* Introduce global ``block.basefee`` for retrieving the base fee of the current block.
* Yul: Introduce builtin ``basefee()`` for retrieving the base fee of the current block.
Compiler Features:

View File

@ -84,6 +84,7 @@ Global Variables
to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature)), ...)```
- ``bytes.concat(...) returns (bytes memory)``: :ref:`Concatenates variable number of
arguments to one byte array<bytes-concat>`
- ``block.basefee`` (``uint``): current block's base fee (`EIP-3198 <https://eips.ethereum.org/EIPS/eip-3198>`_ and `EIP-1559 <https://eips.ethereum.org/EIPS/eip-1559>`_)
- ``block.chainid`` (``uint``): current chain id
- ``block.coinbase`` (``address payable``): current block miner's address
- ``block.difficulty`` (``uint``): current block difficulty

View File

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

View File

@ -72,6 +72,7 @@ Block and Transaction Properties
--------------------------------
- ``blockhash(uint blockNumber) returns (bytes32)``: hash of the given block when ``blocknumber`` is one of the 256 most recent blocks; otherwise returns zero
- ``block.basefee`` (``uint``): current block's base fee (`EIP-3198 <https://eips.ethereum.org/EIPS/eip-3198>`_ and `EIP-1559 <https://eips.ethereum.org/EIPS/eip-1559>`_)
- ``block.chainid`` (``uint``): current chain id
- ``block.coinbase`` (``address payable``): current block miner's address
- ``block.difficulty`` (``uint``): current block difficulty

View File

@ -717,8 +717,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.
Opcodes marked with ``-`` do not return a result and all others return exactly one value.
Opcodes marked with ``F``, ``H``, ``B``, ``C`` or ``I`` are present since Frontier, Homestead,
Byzantium, Constantinople or Istanbul, respectively.
Opcodes marked with ``F``, ``H``, ``B``, ``C``, ``I`` and ``L`` are present since Frontier, Homestead,
Byzantium, Constantinople, Istanbul or London respectively.
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``.
@ -879,7 +879,9 @@ the ``dup`` and ``swap`` instructions as well as ``jump`` instructions, labels a
| log4(p, s, t1, t2, t3, | `-` | F | log with topics t1, t2, t3, t4 and data mem[p...(p+s)) |
| t4) | | | |
+-------------------------+-----+---+-----------------------------------------------------------------+
| chainid() | | I | ID of the executing chain (EIP 1344) |
| chainid() | | I | ID of the executing chain (EIP-1344) |
+-------------------------+-----+---+-----------------------------------------------------------------+
| basefee() | | L | current block's base fee (EIP-3198 and EIP-1559) |
+-------------------------+-----+---+-----------------------------------------------------------------+
| origin() | | F | transaction sender |
+-------------------------+-----+---+-----------------------------------------------------------------+

View File

@ -84,6 +84,7 @@ std::map<std::string, Instruction> const solidity::evmasm::c_instructions =
{ "GASLIMIT", Instruction::GASLIMIT },
{ "CHAINID", Instruction::CHAINID },
{ "SELFBALANCE", Instruction::SELFBALANCE },
{ "BASEFEE", Instruction::BASEFEE },
{ "POP", Instruction::POP },
{ "MLOAD", Instruction::MLOAD },
{ "MSTORE", Instruction::MSTORE },
@ -230,6 +231,7 @@ static std::map<Instruction, InstructionInfo> const c_instructionInfo =
{ Instruction::GASLIMIT, { "GASLIMIT", 0, 0, 1, false, Tier::Base } },
{ Instruction::CHAINID, { "CHAINID", 0, 0, 1, false, Tier::Base } },
{ Instruction::SELFBALANCE, { "SELFBALANCE", 0, 0, 1, false, Tier::Low } },
{ Instruction::BASEFEE, { "BASEFEE", 0, 0, 1, false, Tier::Base } },
{ Instruction::POP, { "POP", 0, 1, 0, false, Tier::Base } },
{ Instruction::MLOAD, { "MLOAD", 0, 1, 1, true, Tier::VeryLow } },
{ Instruction::MSTORE, { "MSTORE", 0, 2, 0, true, Tier::VeryLow } },

View File

@ -88,6 +88,7 @@ enum class Instruction: uint8_t
GASLIMIT, ///< get the block's gas limit
CHAINID, ///< get the config's chainid param
SELFBALANCE, ///< get balance of the current account
BASEFEE, ///< get the block's basefee
POP = 0x50, ///< remove item from stack
MLOAD, ///< load word from memory

View File

@ -353,6 +353,7 @@ bool SemanticInformation::invalidInPureFunctions(Instruction _instruction)
case Instruction::CALLER:
case Instruction::CALLVALUE:
case Instruction::CHAINID:
case Instruction::BASEFEE:
case Instruction::GAS:
case Instruction::GASPRICE:
case Instruction::EXTCODESIZE:

View File

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

View File

@ -2947,6 +2947,12 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
_memberAccess.location(),
"\"chainid\" is not supported by the VM version."
);
else if (magicType->kind() == MagicType::Kind::Block && memberName == "basefee" && !m_evmVersion.hasBaseFee())
m_errorReporter.typeError(
5921_error,
_memberAccess.location(),
"\"basefee\" is not supported by the VM version."
);
}
if (

View File

@ -3892,7 +3892,8 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
{"difficulty", TypeProvider::uint256()},
{"number", TypeProvider::uint256()},
{"gaslimit", TypeProvider::uint256()},
{"chainid", TypeProvider::uint256()}
{"chainid", TypeProvider::uint256()},
{"basefee", TypeProvider::uint256()}
});
case Kind::Message:
return MemberList::MemberMap({

View File

@ -1731,6 +1731,8 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
m_context << Instruction::GASPRICE;
else if (member == "chainid")
m_context << Instruction::CHAINID;
else if (member == "basefee")
m_context << Instruction::BASEFEE;
else if (member == "data")
m_context << u256(0) << Instruction::CALLDATASIZE;
else if (member == "sig")

View File

@ -1733,6 +1733,8 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
define(_memberAccess) << "gasprice()\n";
else if (member == "chainid")
define(_memberAccess) << "chainid()\n";
else if (member == "basefee")
define(_memberAccess) << "basefee()\n";
else if (member == "data")
{
IRVariable var(_memberAccess);

View File

@ -695,6 +695,8 @@ bool AsmAnalyzer::validateInstructions(evmasm::Instruction _instr, SourceLocatio
errorForVM(1561_error, "only available for Istanbul-compatible");
else if (_instr == evmasm::Instruction::SELFBALANCE && !m_evmVersion.hasSelfBalance())
errorForVM(7721_error, "only available for Istanbul-compatible");
else if (_instr == evmasm::Instruction::BASEFEE && !m_evmVersion.hasBaseFee())
errorForVM(5430_error, "only available for London-compatible");
else if (_instr == evmasm::Instruction::PC)
m_errorReporter.error(
2450_error,

View File

@ -122,6 +122,8 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm):
m_evmRevision = EVMC_ISTANBUL;
else if (_evmVersion == langutil::EVMVersion::berlin())
m_evmRevision = EVMC_BERLIN;
else if (_evmVersion == langutil::EVMVersion::london())
m_evmRevision = EVMC_LONDON;
else
assertThrow(false, Exception, "Unsupported EVM version");
@ -132,6 +134,8 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm):
tx_context.tx_origin = 0x9292929292929292929292929292929292929292_address;
// Mainnet according to EIP-155
tx_context.chain_id = evmc::uint256be{1};
// The minimum value of basefee
tx_context.block_base_fee = evmc::bytes32{7};
// Reserve space for recording calls.
if (!recorded_calls.capacity())

View File

@ -0,0 +1,18 @@
contract C {
function f() public view returns (uint) {
return block.basefee;
}
function g() public view returns (uint ret) {
assembly {
ret := basefee()
}
}
}
// ====
// EVMVersion: >=london
// compileViaYul: also
// ----
// f() -> 7
// g() -> 7
// f() -> 7
// g() -> 7

View File

@ -0,0 +1,15 @@
contract C {
function f() public view returns (uint) {
return block.basefee;
}
function g() public view returns (uint ret) {
assembly {
ret := basefee()
}
}
}
// ====
// EVMVersion: =berlin
// ----
// TypeError 5921: (74-87): "basefee" is not supported by the VM version.
// TypeError 5430: (183-190): The "basefee" instruction is only available for London-compatible VMs (you are currently compiling for "berlin").

View File

@ -0,0 +1,13 @@
contract C {
function f() public view returns (uint) {
return block.basefee;
}
function g() public view returns (uint ret) {
assembly {
ret := basefee()
}
}
}
// ====
// EVMVersion: >=london
// ----

View File

@ -0,0 +1,13 @@
contract C {
function f() public pure {
assembly { pop(basefee()) }
}
function g() public pure returns (uint) {
return block.basefee;
}
}
// ====
// EVMVersion: >=london
// ----
// TypeError 2527: (67-76): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
// TypeError 2527: (147-160): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".

View File

@ -13,5 +13,5 @@ object "a" {
// stop
// data_acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f 48656c6c6f2c20576f726c6421
// Bytecode: 6006600055fe48656c6c6f2c20576f726c6421
// Opcodes: PUSH1 0x6 PUSH1 0x0 SSTORE INVALID 0x48 PUSH6 0x6C6C6F2C2057 PUSH16 0x726C6421000000000000000000000000
// Opcodes: PUSH1 0x6 PUSH1 0x0 SSTORE INVALID BASEFEE PUSH6 0x6C6C6F2C2057 PUSH16 0x726C6421000000000000000000000000
// SourceMappings: 32:19:0:-:0;29:1;22:30

View File

@ -220,6 +220,8 @@ u256 EVMInstructionInterpreter::eval(
return m_state.gasprice;
case Instruction::CHAINID:
return m_state.chainid;
case Instruction::BASEFEE:
return m_state.basefee;
case Instruction::EXTCODESIZE:
return u256(keccak256(h256(arg[0]))) & 0xffffff;
case Instruction::EXTCODEHASH:

View File

@ -90,6 +90,8 @@ struct InterpreterState
u256 difficulty = 0x9999999;
u256 gaslimit = 4000000;
u256 chainid = 0x01;
/// The minimum value of basefee: 7 wei.
u256 basefee = 0x07;
/// Log of changes / effects. Sholud be structured data in the future.
std::vector<std::string> trace;
/// This is actually an input parameter that more or less limits the runtime.
@ -227,4 +229,3 @@ private:
};
}