mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #11647 from ethereum/basefee
Implement London EVMVersion and the BASEFEE opcode
This commit is contained in:
commit
0fc3e2dfb3
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 |
|
||||
+-------------------------+-----+---+-----------------------------------------------------------------+
|
||||
|
@ -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 } },
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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) {}
|
||||
|
||||
|
@ -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 (
|
||||
|
@ -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({
|
||||
|
@ -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")
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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())
|
||||
|
18
test/libsolidity/semanticTests/state/block_basefee.sol
Normal file
18
test/libsolidity/semanticTests/state/block_basefee.sol
Normal 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
|
@ -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").
|
13
test/libsolidity/syntaxTests/types/magic_block_london.sol
Normal file
13
test/libsolidity/syntaxTests/types/magic_block_london.sol
Normal 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
|
||||
// ----
|
@ -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".
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user