diff --git a/.circleci/soltest_all.sh b/.circleci/soltest_all.sh index 7b4564ee7..3a2acd1ac 100755 --- a/.circleci/soltest_all.sh +++ b/.circleci/soltest_all.sh @@ -29,7 +29,7 @@ set -e REPODIR="$(realpath $(dirname $0)/..)" for OPTIMIZE in 0 1; do - for EVM in homestead byzantium constantinople petersburg; do + for EVM in homestead byzantium constantinople petersburg istanbul; do EVM=$EVM OPTIMIZE=$OPTIMIZE ${REPODIR}/.circleci/soltest.sh done done 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 f988138c0..38ab4aa6f 100644 --- a/libevmasm/GasMeter.h +++ b/libevmasm/GasMeter.h @@ -53,7 +53,12 @@ namespace GasCosts } inline unsigned balanceGas(langutil::EVMVersion _evmVersion) { - return _evmVersion >= langutil::EVMVersion::tangerineWhistle() ? 400 : 20; + if (_evmVersion >= langutil::EVMVersion::istanbul()) + return 700; + else if (_evmVersion >= langutil::EVMVersion::tangerineWhistle()) + return 400; + else + return 20; } static unsigned const expGas = 10; inline unsigned expByteGas(langutil::EVMVersion _evmVersion) @@ -64,7 +69,12 @@ namespace GasCosts static unsigned const keccak256WordGas = 6; inline unsigned sloadGas(langutil::EVMVersion _evmVersion) { - return _evmVersion >= langutil::EVMVersion::tangerineWhistle() ? 200 : 50; + if (_evmVersion >= langutil::EVMVersion::istanbul()) + return 800; + else if (_evmVersion >= langutil::EVMVersion::tangerineWhistle()) + return 200; + else + return 50; } static unsigned const sstoreSetGas = 20000; static unsigned const sstoreResetGas = 5000; @@ -92,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; } @@ -139,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/scripts/tests.sh b/scripts/tests.sh index 01577af1c..266c3184e 100755 --- a/scripts/tests.sh +++ b/scripts/tests.sh @@ -81,7 +81,7 @@ EVM_VERSIONS="homestead byzantium" if [ -z "$CI" ] then - EVM_VERSIONS+=" constantinople petersburg" + EVM_VERSIONS+=" constantinople petersburg istanbul" fi # And then run the Solidity unit-tests in the matrix combination of optimizer / no optimizer @@ -91,9 +91,9 @@ do for vm in $EVM_VERSIONS do FORCE_ABIV2_RUNS="no" - if [[ "$vm" == "constantinople" ]] + if [[ "$vm" == "istanbul" ]] then - FORCE_ABIV2_RUNS="no yes" # run both in constantinople + FORCE_ABIV2_RUNS="no yes" # run both in istanbul fi for abiv2 in $FORCE_ABIV2_RUNS do 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/externalTests/common.sh b/test/externalTests/common.sh index c018789ac..a94b62dc4 100644 --- a/test/externalTests/common.sh +++ b/test/externalTests/common.sh @@ -207,7 +207,7 @@ function run_test for optimize in "${optimizer_settings[@]}" do clean - force_solc_settings "$CONFIG" "$optimize" "petersburg" + force_solc_settings "$CONFIG" "$optimize" "istanbul" # Force ABIEncoderV2 in the last step. Has to be the last because code is modified. if [ "$FORCE_ABIv2" = true ]; then [[ "$optimize" =~ yul ]] && force_abi_v2 diff --git a/test/libsolidity/GasCosts.cpp b/test/libsolidity/GasCosts.cpp index 8aad4fab7..c56187148 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,33 +96,61 @@ 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); + { + // Costs with 0 are cases which cannot be triggered in tests. + if (evmVersion < EVMVersion::istanbul()) + CHECK_DEPLOY_GAS(0, 127653, evmVersion); + else + CHECK_DEPLOY_GAS(0, 113821, evmVersion); + } else - CHECK_DEPLOY_GAS(151455, 135371); + { + if (evmVersion < EVMVersion::istanbul()) + CHECK_DEPLOY_GAS(0, 135371, evmVersion); + else + CHECK_DEPLOY_GAS(0, 120083, evmVersion); + } } + else if (evmVersion < EVMVersion::istanbul()) + CHECK_DEPLOY_GAS(126861, 119591, evmVersion); else - CHECK_DEPLOY_GAS(126861, 119591); - if (Options::get().evmVersion() >= EVMVersion::byzantium()) + CHECK_DEPLOY_GAS(114173, 107163, 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) { if (Options::get().optimizeYul) - CHECK_GAS(21713, 21567, 20); + { + if (evmVersion < EVMVersion::istanbul()) + CHECK_GAS(0, 21567, 20); + else + CHECK_GAS(0, 21351, 20); + } else - CHECK_GAS(21713, 21635, 20); + { + if (evmVersion < EVMVersion::istanbul()) + CHECK_GAS(0, 21635, 20); + else + CHECK_GAS(0, 21431, 20); + } } - else + else if (evmVersion < EVMVersion::istanbul()) CHECK_GAS(21546, 21526, 20); + else + CHECK_GAS(21332, 21322, 20); } } 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; } diff --git a/test/libsolidity/semanticTests/inlineAssembly/chainid.sol b/test/libsolidity/semanticTests/inlineAssembly/chainid.sol new file mode 100644 index 000000000..491e03a54 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/chainid.sol @@ -0,0 +1,12 @@ +contract C { + function f() public returns (uint id) { + assembly { + id := chainid() + } + } +} +// ==== +// compileViaYul: also +// EVMVersion: >=istanbul +// ---- +// f() -> 1 diff --git a/test/libsolidity/semanticTests/inlineAssembly/selfbalance.sol b/test/libsolidity/semanticTests/inlineAssembly/selfbalance.sol new file mode 100644 index 000000000..8a0a5caae --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/selfbalance.sol @@ -0,0 +1,12 @@ +contract C { + function f() public payable returns (uint ret) { + assembly { + ret := selfbalance() + } + } +} +// ==== +// EVMVersion: >=istanbul +// compileViaYul: also +// ---- +// f(), 254 ether -> 254 diff --git a/test/tools/fuzzer_common.cpp b/test/tools/fuzzer_common.cpp index edeb1e554..5cd64a6c7 100644 --- a/test/tools/fuzzer_common.cpp +++ b/test/tools/fuzzer_common.cpp @@ -34,7 +34,8 @@ static vector s_evmVersions = { "spuriousDragon", "byzantium", "constantinople", - "petersburg" + "petersburg", + "istanbul" }; void FuzzerUtil::runCompiler(string const& _input, bool _quiet)