diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index ab6ac2c63f24..3f067ff6bcac 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp index 5982b8a08092..b3d160585e37 100644 --- a/libevmasm/GasMeter.cpp +++ b/libevmasm/GasMeter.cpp @@ -274,18 +274,20 @@ unsigned GasMeter::runGas(Instruction _instruction, langutil::EVMVersion _evmVer switch (instructionInfo(_instruction, _evmVersion).gasPriceTier) { - case Tier::Zero: return GasCosts::tier0Gas; - case Tier::Base: return GasCosts::tier1Gas; - case Tier::VeryLow: return GasCosts::tier2Gas; - case Tier::Low: return GasCosts::tier3Gas; - case Tier::Mid: return GasCosts::tier4Gas; - case Tier::High: return GasCosts::tier5Gas; - case Tier::Ext: return GasCosts::tier6Gas; - case Tier::WarmAccess: return GasCosts::warmStorageReadCost; - default: break; + case Tier::Zero: return GasCosts::tier0Gas; + case Tier::Base: return GasCosts::tier1Gas; + case Tier::VeryLow: return GasCosts::tier2Gas; + case Tier::Low: return GasCosts::tier3Gas; + case Tier::Mid: return GasCosts::tier4Gas; + case Tier::High: return GasCosts::tier5Gas; + case Tier::BlockHash: return GasCosts::tier6Gas; + case Tier::WarmAccess: return GasCosts::warmStorageReadCost; + + case Tier::Special: + case Tier::Invalid: + assertThrow(false, OptimizerException, "Invalid gas tier for instruction " + instructionInfo(_instruction, _evmVersion).name); } - assertThrow(false, OptimizerException, "Invalid gas tier for instruction " + instructionInfo(_instruction, _evmVersion).name); - return 0; + util::unreachable(); } u256 GasMeter::dataGas(bytes const& _data, bool _inCreation, langutil::EVMVersion _evmVersion) diff --git a/libevmasm/GasMeter.h b/libevmasm/GasMeter.h index ec1946644787..e4bb19925796 100644 --- a/libevmasm/GasMeter.h +++ b/libevmasm/GasMeter.h @@ -43,32 +43,34 @@ class KnownState; namespace GasCosts { + /// NOTE: The GAS_... constants referenced by comments are defined for each EVM version in the Execution Specs: + /// https://ethereum.github.io/execution-specs/autoapi/ethereum//vm/gas/index.html + static unsigned const stackLimit = 1024; - static unsigned const tier0Gas = 0; - static unsigned const tier1Gas = 2; - static unsigned const tier2Gas = 3; - static unsigned const tier3Gas = 5; - static unsigned const tier4Gas = 8; - static unsigned const tier5Gas = 10; - static unsigned const tier6Gas = 20; - static unsigned const tier7Gas = 0; - static unsigned const expGas = 10; + static unsigned const tier0Gas = 0; // GAS_ZERO (in Execution Specs) + static unsigned const tier1Gas = 2; // GAS_BASE + static unsigned const tier2Gas = 3; // GAS_VERY_LOW + static unsigned const tier3Gas = 5; // GAS_LOW / GAS_FAST_STEP + static unsigned const tier4Gas = 8; // GAS_MID + static unsigned const tier5Gas = 10; // GAS_HIGH + static unsigned const tier6Gas = 20; // GAS_BLOCK_HASH + static unsigned const expGas = 10; // GAS_EXPONENTIATION inline unsigned expByteGas(langutil::EVMVersion _evmVersion) { - return _evmVersion >= langutil::EVMVersion::spuriousDragon() ? 50 : 10; + return _evmVersion >= langutil::EVMVersion::spuriousDragon() ? 50 : 10; // GAS_EXPONENTIATION_PER_BYTE } - static unsigned const keccak256Gas = 30; - static unsigned const keccak256WordGas = 6; + static unsigned const keccak256Gas = 30; // GAS_KECCAK256 + static unsigned const keccak256WordGas = 6; // GAS_KECCAK256_WORD /// Corresponds to ACCESS_LIST_ADDRESS_COST from EIP-2930 static unsigned const accessListAddressCost = 2400; /// Corresponds to ACCESS_LIST_STORAGE_COST from EIP-2930 static unsigned const accessListStorageKeyCost = 1900; /// Corresponds to COLD_SLOAD_COST from EIP-2929 - static unsigned const coldSloadCost = 2100; + static unsigned const coldSloadCost = 2100; // GAS_COLD_SLOAD /// Corresponds to COLD_ACCOUNT_ACCESS_COST from EIP-2929 - static unsigned const coldAccountAccessCost = 2600; + static unsigned const coldAccountAccessCost = 2600; // GAS_COLD_ACCOUNT_ACCESS /// Corresponds to WARM_STORAGE_READ_COST from EIP-2929 - static unsigned const warmStorageReadCost = 100; + static unsigned const warmStorageReadCost = 100; // GAS_WARM_ACCESS inline unsigned sloadGas(langutil::EVMVersion _evmVersion) { if (_evmVersion >= langutil::EVMVersion::berlin()) @@ -81,7 +83,7 @@ namespace GasCosts return 50; } /// Corresponds to SSTORE_SET_GAS - static unsigned const sstoreSetGas = 20000; + static unsigned const sstoreSetGas = 20000; // GAS_STORAGE_SET /// Corresponds to SSTORE_RESET_GAS from EIP-2929 static unsigned const sstoreResetGas = 5000 - coldSloadCost; /// Corresponds to SSTORE_CLEARS_SCHEDULE from EIP-2200 @@ -130,11 +132,11 @@ namespace GasCosts else return 20; } - static unsigned const jumpdestGas = 1; - static unsigned const logGas = 375; - static unsigned const logDataGas = 8; - static unsigned const logTopicGas = 375; - static unsigned const createGas = 32000; + static unsigned const jumpdestGas = 1; // GAS_JUMPDEST + static unsigned const logGas = 375; // GAS_LOG + static unsigned const logDataGas = 8; // GAS_LOG_DATA + static unsigned const logTopicGas = 375; // GAS_LOG_TOPIC + static unsigned const createGas = 32000; // GAS_CREATE inline unsigned callGas(langutil::EVMVersion _evmVersion) { if (_evmVersion >= langutil::EVMVersion::berlin()) @@ -144,10 +146,10 @@ namespace GasCosts else return 40; } - static unsigned const callStipend = 2300; - static unsigned const callValueTransferGas = 9000; - static unsigned const callNewAccountGas = 25000; - inline unsigned selfdestructGas(langutil::EVMVersion _evmVersion) + static unsigned const callStipend = 2300; // GAS_CALL_STIPEND + static unsigned const callValueTransferGas = 9000; // GAS_CALL_VALUE + static unsigned const callNewAccountGas = 25000; // GAS_NEW_ACCOUNT / GAS_SELF_DESTRUCT_NEW_ACCOUNT + inline unsigned selfdestructGas(langutil::EVMVersion _evmVersion) // GAS_SELF_DESTRUCT { if (_evmVersion >= langutil::EVMVersion::berlin()) return coldAccountAccessCost; @@ -164,9 +166,9 @@ namespace GasCosts else return 24000; } - static unsigned const memoryGas = 3; + static unsigned const memoryGas = 3; // GAS_MEMORY / GAS_COPY / GAS_RETURN_DATA_COPY static unsigned const quadCoeffDiv = 512; - static unsigned const createDataGas = 200; + static unsigned const createDataGas = 200; // GAS_CODE_DEPOSIT static unsigned const txGas = 21000; static unsigned const txCreateGas = 53000; static unsigned const txDataZeroGas = 4; diff --git a/libevmasm/Instruction.cpp b/libevmasm/Instruction.cpp index a21f33e1838f..ca0dff185ad4 100644 --- a/libevmasm/Instruction.cpp +++ b/libevmasm/Instruction.cpp @@ -211,7 +211,7 @@ static std::map const c_instructionInfo = { Instruction::SIGNEXTEND, { "SIGNEXTEND", 0, 2, 1, false, Tier::Low } }, { Instruction::KECCAK256, { "KECCAK256", 0, 2, 1, true, Tier::Special } }, { Instruction::ADDRESS, { "ADDRESS", 0, 0, 1, false, Tier::Base } }, - { Instruction::BALANCE, { "BALANCE", 0, 1, 1, false, Tier::Balance } }, + { Instruction::BALANCE, { "BALANCE", 0, 1, 1, false, Tier::Special } }, { Instruction::ORIGIN, { "ORIGIN", 0, 0, 1, false, Tier::Base } }, { Instruction::CALLER, { "CALLER", 0, 0, 1, false, Tier::Base } }, { Instruction::CALLVALUE, { "CALLVALUE", 0, 0, 1, false, Tier::Base } }, @@ -221,13 +221,13 @@ static std::map const c_instructionInfo = { Instruction::CODESIZE, { "CODESIZE", 0, 0, 1, false, Tier::Base } }, { Instruction::CODECOPY, { "CODECOPY", 0, 3, 0, true, Tier::VeryLow } }, { Instruction::GASPRICE, { "GASPRICE", 0, 0, 1, false, Tier::Base } }, - { Instruction::EXTCODESIZE, { "EXTCODESIZE", 0, 1, 1, false, Tier::ExtCode } }, - { Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0, true, Tier::ExtCode } }, - { Instruction::RETURNDATASIZE, {"RETURNDATASIZE", 0, 0, 1, false, Tier::Base } }, - { Instruction::RETURNDATACOPY, {"RETURNDATACOPY", 0, 3, 0, true, Tier::VeryLow } }, + { Instruction::EXTCODESIZE, { "EXTCODESIZE", 0, 1, 1, false, Tier::Special } }, + { Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0, true, Tier::Special } }, + { Instruction::RETURNDATASIZE, {"RETURNDATASIZE", 0, 0, 1, false, Tier::Base } }, + { Instruction::RETURNDATACOPY, {"RETURNDATACOPY", 0, 3, 0, true, Tier::VeryLow } }, { Instruction::MCOPY, { "MCOPY", 0, 3, 0, true, Tier::VeryLow } }, - { Instruction::EXTCODEHASH, { "EXTCODEHASH", 0, 1, 1, false, Tier::Balance } }, - { Instruction::BLOCKHASH, { "BLOCKHASH", 0, 1, 1, false, Tier::Ext } }, + { Instruction::EXTCODEHASH, { "EXTCODEHASH", 0, 1, 1, false, Tier::Special } }, + { Instruction::BLOCKHASH, { "BLOCKHASH", 0, 1, 1, false, Tier::BlockHash } }, { Instruction::BLOBHASH, { "BLOBHASH", 0, 1, 1, false, Tier::VeryLow } }, { Instruction::COINBASE, { "COINBASE", 0, 0, 1, false, Tier::Base } }, { Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1, false, Tier::Base } }, diff --git a/libevmasm/Instruction.h b/libevmasm/Instruction.h index 1733863aa5a2..289469b5ef7b 100644 --- a/libevmasm/Instruction.h +++ b/libevmasm/Instruction.h @@ -287,20 +287,23 @@ inline Instruction logInstruction(unsigned _number) return Instruction(unsigned(Instruction::LOG0) + _number); } +/// Gas price tiers representing static cost of an instruction. +/// Opcodes whose cost is dynamic or depends on EVM version should use the `Special` tier and need +/// dedicated logic in GasMeter (especially in estimateMax()). +/// The tiers loosely follow opcode groups originally defined in the Yellow Paper. enum class Tier { - Zero = 0, // 0, Zero - Base, // 2, Quick - VeryLow, // 3, Fastest - Low, // 5, Fast - Mid, // 8, Mid - High, // 10, Slow - Ext, // 20, Ext - WarmAccess, // 100, Warm Access - ExtCode, // 700, Extcode - Balance, // 400, Balance - Special, // multiparam or otherwise special - Invalid // Invalid. + // NOTE: Tiers should be ordered by cost, since we sometimes perform comparisons between them. + Zero = 0, // 0, Zero + Base, // 2, Quick + VeryLow, // 3, Fastest + Low, // 5, Fast + Mid, // 8, Mid + High, // 10, Slow + BlockHash, // 20 + WarmAccess, // 100, Warm Access + Special, // multiparam or otherwise special + Invalid, // Invalid. }; /// Information structure for a particular instruction. diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 9b5c87818bf2..69394417586e 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -1480,15 +1480,8 @@ void CompilerStack::compileContract( solAssert(!m_viaIR, ""); bytes cborEncodedMetadata = createCBORMetadata(compiledContract, /* _forIR */ false); - try - { - // Run optimiser and compile the contract. - compiler->compileContract(_contract, _otherCompilers, cborEncodedMetadata); - } - catch(evmasm::OptimizerException const&) - { - solAssert(false, "Optimizer exception during compilation"); - } + // Run optimiser and compile the contract. + compiler->compileContract(_contract, _otherCompilers, cborEncodedMetadata); _otherCompilers[compiledContract.contract] = compiler; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 7181bfd4cc7e..4c08efb51a00 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -43,9 +43,7 @@ #include -#include #include -#include #include #include