diff --git a/libevmasm/ConstantOptimiser.cpp b/libevmasm/ConstantOptimiser.cpp index 4825bc5cf..36cb2d656 100644 --- a/libevmasm/ConstantOptimiser.cpp +++ b/libevmasm/ConstantOptimiser.cpp @@ -96,7 +96,7 @@ bigint ConstantOptimisationMethod::simpleRunGas(AssemblyItems const& _items) bigint ConstantOptimisationMethod::dataGas(bytes const& _data) const { assertThrow(_data.size() > 0, OptimizerException, "Empty bytecode generated."); - return bigint(GasMeter::dataGas(_data, m_params.isCreation)); + return bigint(GasMeter::dataGas(_data, m_params.isCreation, m_params.evmVersion)); } size_t ConstantOptimisationMethod::bytesRequired(AssemblyItems const& _items) @@ -131,7 +131,7 @@ bigint LiteralMethod::gasNeeded() const return combineGas( simpleRunGas({Instruction::PUSH1}), // PUSHX plus data - (m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas) + dataGas(toCompactBigEndian(m_value, 1)), + (m_params.isCreation ? GasCosts::txDataNonZeroGas(m_params.evmVersion) : GasCosts::createDataGas) + dataGas(toCompactBigEndian(m_value, 1)), 0 ); } @@ -142,7 +142,7 @@ bigint CodeCopyMethod::gasNeeded() const // Run gas: we ignore memory increase costs simpleRunGas(copyRoutine()) + GasCosts::copyGas, // Data gas for copy routines: Some bytes are zero, but we ignore them. - bytesRequired(copyRoutine()) * (m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas), + bytesRequired(copyRoutine()) * (m_params.isCreation ? GasCosts::txDataNonZeroGas(m_params.evmVersion) : GasCosts::createDataGas), // Data gas for data itself dataGas(toBigEndian(m_value)) ); @@ -322,7 +322,7 @@ bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine) const return combineGas( simpleRunGas(_routine) + numExps * (GasCosts::expGas + GasCosts::expByteGas(m_params.evmVersion)), // Data gas for routine: Some bytes are zero, but we ignore them. - bytesRequired(_routine) * (m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas), + bytesRequired(_routine) * (m_params.isCreation ? GasCosts::txDataNonZeroGas(m_params.evmVersion) : GasCosts::createDataGas), 0 ); } diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp index 5ff3a905e..ca8d7fbd4 100644 --- a/libevmasm/GasMeter.cpp +++ b/libevmasm/GasMeter.cpp @@ -266,13 +266,13 @@ unsigned GasMeter::runGas(Instruction _instruction) return 0; } -u256 GasMeter::dataGas(bytes const& _data, bool _inCreation) +u256 GasMeter::dataGas(bytes const& _data, bool _inCreation, langutil::EVMVersion _evmVersion) { bigint gas = 0; if (_inCreation) { for (auto b: _data) - gas += (b != 0) ? GasCosts::txDataNonZeroGas : GasCosts::txDataZeroGas; + gas += (b != 0) ? GasCosts::txDataNonZeroGas(_evmVersion) : GasCosts::txDataZeroGas; } else gas = bigint(GasCosts::createDataGas) * _data.size(); diff --git a/libevmasm/GasMeter.h b/libevmasm/GasMeter.h index 8086ed196..38ab4aa6f 100644 --- a/libevmasm/GasMeter.h +++ b/libevmasm/GasMeter.h @@ -102,7 +102,10 @@ namespace GasCosts static unsigned const txGas = 21000; static unsigned const txCreateGas = 53000; static unsigned const txDataZeroGas = 4; - static unsigned const txDataNonZeroGas = 68; + inline unsigned txDataNonZeroGas(langutil::EVMVersion _evmVersion) + { + return _evmVersion >= langutil::EVMVersion::istanbul() ? 16 : 68; + } static unsigned const copyGas = 3; } @@ -149,7 +152,7 @@ public: /// @returns the gas cost of the supplied data, depending whether it is in creation code, or not. /// In case of @a _inCreation, the data is only sent as a transaction and is not stored, whereas /// otherwise code will be stored and have to pay "createDataGas" cost. - static u256 dataGas(bytes const& _data, bool _inCreation); + static u256 dataGas(bytes const& _data, bool _inCreation, langutil::EVMVersion _evmVersion); private: /// @returns _multiplier * (_value + 31) / 32, if _value is a known constant and infinite otherwise. diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 57cae9374..423cdcceb 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -1410,7 +1410,7 @@ Json::Value CompilerStack::gasEstimates(string const& _contractName) const if (eth::AssemblyItems const* items = assemblyItems(_contractName)) { Gas executionGas = gasEstimator.functionalEstimation(*items); - Gas codeDepositGas{eth::GasMeter::dataGas(runtimeObject(_contractName).bytecode, false)}; + Gas codeDepositGas{eth::GasMeter::dataGas(runtimeObject(_contractName).bytecode, false, m_evmVersion)}; Json::Value creation(Json::objectValue); creation["codeDepositCost"] = gasToJson(codeDepositGas); diff --git a/libyul/backends/evm/EVMMetrics.cpp b/libyul/backends/evm/EVMMetrics.cpp index 5211e5132..204014589 100644 --- a/libyul/backends/evm/EVMMetrics.cpp +++ b/libyul/backends/evm/EVMMetrics.cpp @@ -96,7 +96,7 @@ void GasMeterVisitor::operator()(Literal const& _lit) m_runGas += dev::eth::GasMeter::runGas(dev::eth::Instruction::PUSH1); m_dataGas += singleByteDataGas() + - size_t(dev::eth::GasMeter::dataGas(dev::toCompactBigEndian(valueOfLiteral(_lit), 1), m_isCreation)); + size_t(dev::eth::GasMeter::dataGas(dev::toCompactBigEndian(valueOfLiteral(_lit), 1), m_isCreation, m_dialect.evmVersion())); } void GasMeterVisitor::operator()(Identifier const&) @@ -108,7 +108,7 @@ void GasMeterVisitor::operator()(Identifier const&) size_t GasMeterVisitor::singleByteDataGas() const { if (m_isCreation) - return dev::eth::GasCosts::txDataNonZeroGas; + return dev::eth::GasCosts::txDataNonZeroGas(m_dialect.evmVersion()); else return dev::eth::GasCosts::createDataGas; } diff --git a/test/EVMHost.cpp b/test/EVMHost.cpp index d2852614e..64ef1c5e5 100644 --- a/test/EVMHost.cpp +++ b/test/EVMHost.cpp @@ -64,7 +64,8 @@ evmc::VM* EVMHost::getVM(string const& _path) } EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM* _vm): - m_vm(_vm) + m_vm(_vm), + m_evmVersion(_evmVersion) { if (!m_vm) { @@ -73,21 +74,21 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM* _vm): } if (_evmVersion == langutil::EVMVersion::homestead()) - m_evmVersion = EVMC_HOMESTEAD; + m_evmRevision = EVMC_HOMESTEAD; else if (_evmVersion == langutil::EVMVersion::tangerineWhistle()) - m_evmVersion = EVMC_TANGERINE_WHISTLE; + m_evmRevision = EVMC_TANGERINE_WHISTLE; else if (_evmVersion == langutil::EVMVersion::spuriousDragon()) - m_evmVersion = EVMC_SPURIOUS_DRAGON; + m_evmRevision = EVMC_SPURIOUS_DRAGON; else if (_evmVersion == langutil::EVMVersion::byzantium()) - m_evmVersion = EVMC_BYZANTIUM; + m_evmRevision = EVMC_BYZANTIUM; else if (_evmVersion == langutil::EVMVersion::constantinople()) - m_evmVersion = EVMC_CONSTANTINOPLE; + m_evmRevision = EVMC_CONSTANTINOPLE; else if (_evmVersion == langutil::EVMVersion::istanbul()) - m_evmVersion = EVMC_ISTANBUL; + m_evmRevision = EVMC_ISTANBUL; else if (_evmVersion == langutil::EVMVersion::berlin()) assertThrow(false, Exception, "Berlin is not supported yet."); else //if (_evmVersion == langutil::EVMVersion::petersburg()) - m_evmVersion = EVMC_PETERSBURG; + m_evmRevision = EVMC_PETERSBURG; } evmc_storage_status EVMHost::set_storage(const evmc::address& _addr, const evmc::bytes32& _key, const evmc::bytes32& _value) noexcept @@ -146,7 +147,7 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept { message.gas -= message.kind == EVMC_CREATE ? eth::GasCosts::txCreateGas : eth::GasCosts::txGas; for (size_t i = 0; i < message.input_size; ++i) - message.gas -= message.input_data[i] == 0 ? eth::GasCosts::txDataZeroGas : eth::GasCosts::txDataNonZeroGas; + message.gas -= message.input_data[i] == 0 ? eth::GasCosts::txDataZeroGas : eth::GasCosts::txDataNonZeroGas(m_evmVersion); if (message.gas < 0) { evmc::result result({}); @@ -191,7 +192,7 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept evmc::address currentAddress = m_currentAddress; m_currentAddress = message.destination; - evmc::result result = m_vm->execute(*this, m_evmVersion, message, code.data(), code.size()); + evmc::result result = m_vm->execute(*this, m_evmRevision, message, code.data(), code.size()); m_currentAddress = currentAddress; if (message.kind == EVMC_CREATE) diff --git a/test/EVMHost.h b/test/EVMHost.h index 2ffcabcfa..a0adb67bc 100644 --- a/test/EVMHost.h +++ b/test/EVMHost.h @@ -180,7 +180,10 @@ private: static evmc::result resultWithGas(evmc_message const& _message, bytes const& _data) noexcept; evmc::VM* m_vm = nullptr; - evmc_revision m_evmVersion; + // EVM version requested by the testing tool + langutil::EVMVersion m_evmVersion; + // EVM version requested from EVMC (matches the above) + evmc_revision m_evmRevision; }; diff --git a/test/libsolidity/GasCosts.cpp b/test/libsolidity/GasCosts.cpp index 8aad4fab7..395c44575 100644 --- a/test/libsolidity/GasCosts.cpp +++ b/test/libsolidity/GasCosts.cpp @@ -19,6 +19,7 @@ */ #include +#include #include #include @@ -37,10 +38,10 @@ namespace solidity namespace test { -#define CHECK_DEPLOY_GAS(_gasNoOpt, _gasOpt) \ +#define CHECK_DEPLOY_GAS(_gasNoOpt, _gasOpt, _evmVersion) \ do \ { \ - u256 bzzr1Cost = GasMeter::dataGas(dev::bzzr1Hash(m_compiler.metadata(m_compiler.lastContractName())).asBytes(), true); \ + u256 bzzr1Cost = GasMeter::dataGas(dev::bzzr1Hash(m_compiler.metadata(m_compiler.lastContractName())).asBytes(), true, _evmVersion); \ u256 gasOpt{_gasOpt}; \ u256 gasNoOpt{_gasNoOpt}; \ u256 gas = m_optimiserSettings == OptimiserSettings::minimal() ? gasNoOpt : gasOpt; \ @@ -95,22 +96,25 @@ BOOST_AUTO_TEST_CASE(string_storage) m_compiler.overwriteReleaseFlag(true); compileAndRun(sourceCode); - if (Options::get().evmVersion() <= EVMVersion::byzantium()) - CHECK_DEPLOY_GAS(134071, 130763); + auto evmVersion = dev::test::Options::get().evmVersion(); + + if (evmVersion <= EVMVersion::byzantium()) + CHECK_DEPLOY_GAS(134071, 130763, evmVersion); // This is only correct on >=Constantinople. else if (Options::get().useABIEncoderV2) { if (Options::get().optimizeYul) - CHECK_DEPLOY_GAS(151455, 127653); + CHECK_DEPLOY_GAS(151455, 127653, evmVersion); else - CHECK_DEPLOY_GAS(151455, 135371); + CHECK_DEPLOY_GAS(151455, 135371, evmVersion); } else - CHECK_DEPLOY_GAS(126861, 119591); - if (Options::get().evmVersion() >= EVMVersion::byzantium()) + CHECK_DEPLOY_GAS(126861, 119591, evmVersion); + + if (evmVersion >= EVMVersion::byzantium()) { callContractFunction("f()"); - if (Options::get().evmVersion() == EVMVersion::byzantium()) + if (evmVersion == EVMVersion::byzantium()) CHECK_GAS(21551, 21526, 20); // This is only correct on >=Constantinople. else if (Options::get().useABIEncoderV2) diff --git a/test/libsolidity/GasMeter.cpp b/test/libsolidity/GasMeter.cpp index 4b13172b1..bccf27458 100644 --- a/test/libsolidity/GasMeter.cpp +++ b/test/libsolidity/GasMeter.cpp @@ -114,9 +114,10 @@ public: static GasMeter::GasConsumption gasForTransaction(bytes const& _data, bool _isCreation) { + auto evmVersion = dev::test::Options::get().evmVersion(); GasMeter::GasConsumption gas = _isCreation ? GasCosts::txCreateGas : GasCosts::txGas; for (auto i: _data) - gas += i != 0 ? GasCosts::txDataNonZeroGas : GasCosts::txDataZeroGas; + gas += i != 0 ? GasCosts::txDataNonZeroGas(evmVersion) : GasCosts::txDataZeroGas; return gas; }