From d92b211a2f4e85fbf856736e318edb27c53286b7 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 12 Jul 2021 16:48:18 +0200 Subject: [PATCH 1/6] Added the instruction basefee. --- libevmasm/Instruction.cpp | 2 ++ libevmasm/Instruction.h | 1 + libevmasm/SemanticInformation.cpp | 1 + 3 files changed, 4 insertions(+) diff --git a/libevmasm/Instruction.cpp b/libevmasm/Instruction.cpp index e9f528d89dcb..7ce36c254337 100644 --- a/libevmasm/Instruction.cpp +++ b/libevmasm/Instruction.cpp @@ -84,6 +84,7 @@ std::map 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 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 } }, diff --git a/libevmasm/Instruction.h b/libevmasm/Instruction.h index 5159bee5dac1..10035b8543bb 100644 --- a/libevmasm/Instruction.h +++ b/libevmasm/Instruction.h @@ -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 diff --git a/libevmasm/SemanticInformation.cpp b/libevmasm/SemanticInformation.cpp index a6ab8c49c009..d3359c4f7386 100644 --- a/libevmasm/SemanticInformation.cpp +++ b/libevmasm/SemanticInformation.cpp @@ -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: From 95091f6b5892b556b3a2a151af147f60da0a74bf Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 12 Jul 2021 16:49:05 +0200 Subject: [PATCH 2/6] Implemented `block.basefee` in Solidilty and `basefee()` in Yul. Also added basefee to Yul grammar. --- docs/grammar/SolidityLexer.g4 | 3 ++- libsolidity/analysis/TypeChecker.cpp | 6 ++++++ libsolidity/ast/Types.cpp | 3 ++- libsolidity/codegen/ExpressionCompiler.cpp | 2 ++ libsolidity/codegen/ir/IRGeneratorForStatements.cpp | 2 ++ libyul/AsmAnalysis.cpp | 2 ++ 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/grammar/SolidityLexer.g4 b/docs/grammar/SolidityLexer.g4 index f216402641b3..5a73be85fdb4 100644 --- a/docs/grammar/SolidityLexer.g4 +++ b/docs/grammar/SolidityLexer.g4 @@ -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; diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 0c90d005cb8d..f15fe730e253 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -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 ( diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 06d6a0fd9756..2d8b5dd52e83 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -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({ diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 338430723844..4c86aa980569 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -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") diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 86fcddc927c4..96b8c991d340 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -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); diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index 95d2f41fa4b8..43b78d6b2e5a 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -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, From 543ccf52871dfafd2d7880354c14968ad755d45f Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 12 Jul 2021 16:49:53 +0200 Subject: [PATCH 3/6] Added the basefee instruction in YulInterpreter --- test/tools/yulInterpreter/EVMInstructionInterpreter.cpp | 2 ++ test/tools/yulInterpreter/Interpreter.h | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp b/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp index 1bb5d1147024..476c95357356 100644 --- a/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp +++ b/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp @@ -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: diff --git a/test/tools/yulInterpreter/Interpreter.h b/test/tools/yulInterpreter/Interpreter.h index 2bc586acfaf4..621305422c39 100644 --- a/test/tools/yulInterpreter/Interpreter.h +++ b/test/tools/yulInterpreter/Interpreter.h @@ -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 trace; /// This is actually an input parameter that more or less limits the runtime. @@ -227,4 +229,3 @@ class ExpressionEvaluator: public ASTWalker }; } - From af1dabb5554a22f9fae545451a9867f37d2520f6 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 12 Jul 2021 16:50:16 +0200 Subject: [PATCH 4/6] Added EVMVersion london. Also set the value of `block_base_fee` for testing to 7 wei. --- .circleci/soltest_all.sh | 2 +- liblangutil/EVMVersion.h | 7 +++++-- test/EVMHost.cpp | 4 ++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.circleci/soltest_all.sh b/.circleci/soltest_all.sh index a7922863712b..e069c0f6b688 100755 --- a/.circleci/soltest_all.sh +++ b/.circleci/soltest_all.sh @@ -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) diff --git a/liblangutil/EVMVersion.h b/liblangutil/EVMVersion.h index a3aeff3d0b7b..bbb4200b19ae 100644 --- a/liblangutil/EVMVersion.h +++ b/liblangutil/EVMVersion.h @@ -51,10 +51,11 @@ class EVMVersion: 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 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 @@ class EVMVersion: 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 @@ class EVMVersion: 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 @@ class EVMVersion: 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) {} diff --git a/test/EVMHost.cpp b/test/EVMHost.cpp index c2db412b6203..6d925f4d2e32 100644 --- a/test/EVMHost.cpp +++ b/test/EVMHost.cpp @@ -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()) From cb9b52c242dcccbab811eb37dd7c283367e0fa8d Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 12 Jul 2021 16:50:37 +0200 Subject: [PATCH 5/6] Docs for block.basefee and basefee() in Yul. --- docs/cheatsheet.rst | 1 + docs/units-and-global-variables.rst | 1 + docs/yul.rst | 8 +++++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/cheatsheet.rst b/docs/cheatsheet.rst index c39209e37bc1..4ff9118bc9ab 100644 --- a/docs/cheatsheet.rst +++ b/docs/cheatsheet.rst @@ -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` +- ``block.basefee`` (``uint``): current block's base fee (`EIP-3198 `_ and `EIP-1559 `_) - ``block.chainid`` (``uint``): current chain id - ``block.coinbase`` (``address payable``): current block miner's address - ``block.difficulty`` (``uint``): current block difficulty diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index 0e2ce34a2ee5..95438b85acd2 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -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 `_ and `EIP-1559 `_) - ``block.chainid`` (``uint``): current chain id - ``block.coinbase`` (``address payable``): current block miner's address - ``block.difficulty`` (``uint``): current block difficulty diff --git a/docs/yul.rst b/docs/yul.rst index 0f7d3cef38ca..d0126e65bf6e 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -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 | +-------------------------+-----+---+-----------------------------------------------------------------+ From 43605d92992dfbd070c27851550cc78a82ae00e2 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 12 Jul 2021 16:51:56 +0200 Subject: [PATCH 6/6] Tests and Changelog for basefee. --- Changelog.md | 2 ++ .../semanticTests/state/block_basefee.sol | 18 ++++++++++++++++++ .../types/magic_block_basefee_error.sol | 15 +++++++++++++++ .../syntaxTests/types/magic_block_london.sol | 13 +++++++++++++ .../viewPureChecker/basefee_not_pure.sol | 13 +++++++++++++ test/libyul/objectCompiler/dataoffset_data.yul | 2 +- 6 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 test/libsolidity/semanticTests/state/block_basefee.sol create mode 100644 test/libsolidity/syntaxTests/types/magic_block_basefee_error.sol create mode 100644 test/libsolidity/syntaxTests/types/magic_block_london.sol create mode 100644 test/libsolidity/syntaxTests/viewPureChecker/basefee_not_pure.sol diff --git a/Changelog.md b/Changelog.md index 916dbfde5cd0..3939681b0ade 100644 --- a/Changelog.md +++ b/Changelog.md @@ -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: diff --git a/test/libsolidity/semanticTests/state/block_basefee.sol b/test/libsolidity/semanticTests/state/block_basefee.sol new file mode 100644 index 000000000000..0b54008b0932 --- /dev/null +++ b/test/libsolidity/semanticTests/state/block_basefee.sol @@ -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 diff --git a/test/libsolidity/syntaxTests/types/magic_block_basefee_error.sol b/test/libsolidity/syntaxTests/types/magic_block_basefee_error.sol new file mode 100644 index 000000000000..706fa3183a32 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/magic_block_basefee_error.sol @@ -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"). diff --git a/test/libsolidity/syntaxTests/types/magic_block_london.sol b/test/libsolidity/syntaxTests/types/magic_block_london.sol new file mode 100644 index 000000000000..0d65672ca984 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/magic_block_london.sol @@ -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 +// ---- diff --git a/test/libsolidity/syntaxTests/viewPureChecker/basefee_not_pure.sol b/test/libsolidity/syntaxTests/viewPureChecker/basefee_not_pure.sol new file mode 100644 index 000000000000..0d7c19086710 --- /dev/null +++ b/test/libsolidity/syntaxTests/viewPureChecker/basefee_not_pure.sol @@ -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". diff --git a/test/libyul/objectCompiler/dataoffset_data.yul b/test/libyul/objectCompiler/dataoffset_data.yul index 2a029785b09d..bc066c802c75 100644 --- a/test/libyul/objectCompiler/dataoffset_data.yul +++ b/test/libyul/objectCompiler/dataoffset_data.yul @@ -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