diff options
28 files changed, 328 insertions, 201 deletions
diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index b9fedf26..bd4ebf59 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -353,7 +353,7 @@ void Assembly::injectStart(AssemblyItem const& _i) m_items.insert(m_items.begin(), _i); } -Assembly& Assembly::optimise(bool _enable, bool _isCreation, size_t _runs) +Assembly& Assembly::optimise(bool _enable, EVMVersion _evmVersion, bool _isCreation, size_t _runs) { OptimiserSettings settings; settings.isCreation = _isCreation; @@ -365,6 +365,7 @@ Assembly& Assembly::optimise(bool _enable, bool _isCreation, size_t _runs) settings.runCSE = true; settings.runConstantOptimiser = true; } + settings.evmVersion = _evmVersion; settings.expectedExecutionsPerDeployment = _runs; optimise(settings); return *this; @@ -482,6 +483,7 @@ map<u256, u256> Assembly::optimiseInternal( ConstantOptimisationMethod::optimiseConstants( _settings.isCreation, _settings.isCreation ? 1 : _settings.expectedExecutionsPerDeployment, + _settings.evmVersion, *this, m_items ); diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index 885192e4..367c6daa 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -23,6 +23,8 @@ #include <libevmasm/LinkerObject.h> #include <libevmasm/Exceptions.h> +#include <libsolidity/interface/EVMVersion.h> + #include <libdevcore/Common.h> #include <libdevcore/Assertions.h> #include <libdevcore/SHA3.h> @@ -107,6 +109,7 @@ public: bool runDeduplicate = false; bool runCSE = false; bool runConstantOptimiser = false; + solidity::EVMVersion evmVersion; /// This specifies an estimate on how often each opcode in this assembly will be executed, /// i.e. use a small value to optimise for size and a large value to optimise for runtime gas usage. size_t expectedExecutionsPerDeployment = 200; @@ -120,7 +123,7 @@ public: /// @a _runs specifes an estimate on how often each opcode in this assembly will be executed, /// i.e. use a small value to optimise for size and a large value to optimise for runtime. /// If @a _enable is not set, will perform some simple peephole optimizations. - Assembly& optimise(bool _enable, bool _isCreation = true, size_t _runs = 200); + Assembly& optimise(bool _enable, EVMVersion _evmVersion, bool _isCreation = true, size_t _runs = 200); /// Create a text representation of the assembly. std::string assemblyString( diff --git a/libevmasm/ConstantOptimiser.cpp b/libevmasm/ConstantOptimiser.cpp index 2efd2dc9..d0b6843c 100644 --- a/libevmasm/ConstantOptimiser.cpp +++ b/libevmasm/ConstantOptimiser.cpp @@ -29,6 +29,7 @@ using namespace dev::eth; unsigned ConstantOptimisationMethod::optimiseConstants( bool _isCreation, size_t _runs, + solidity::EVMVersion _evmVersion, Assembly& _assembly, AssemblyItems& _items ) @@ -48,6 +49,7 @@ unsigned ConstantOptimisationMethod::optimiseConstants( params.multiplicity = it.second; params.isCreation = _isCreation; params.runs = _runs; + params.evmVersion = _evmVersion; LiteralMethod lit(params, item.data()); bigint literalGas = lit.gasNeeded(); CodeCopyMethod copy(params, item.data()); @@ -80,7 +82,12 @@ bigint ConstantOptimisationMethod::simpleRunGas(AssemblyItems const& _items) if (item.type() == Push) gas += GasMeter::runGas(Instruction::PUSH1); else if (item.type() == Operation) - gas += GasMeter::runGas(item.instruction()); + { + if (item.instruction() == Instruction::EXP) + gas += GasCosts::expGas; + else + gas += GasMeter::runGas(item.instruction()); + } return gas; } @@ -286,7 +293,7 @@ bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine) const { size_t numExps = count(_routine.begin(), _routine.end(), Instruction::EXP); return combineGas( - simpleRunGas(_routine) + numExps * (GasCosts::expGas + GasCosts::expByteGas), + 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), 0 diff --git a/libevmasm/ConstantOptimiser.h b/libevmasm/ConstantOptimiser.h index c450b0b4..9b60b26b 100644 --- a/libevmasm/ConstantOptimiser.h +++ b/libevmasm/ConstantOptimiser.h @@ -23,6 +23,8 @@ #include <libevmasm/Exceptions.h> +#include <libsolidity/interface/EVMVersion.h> + #include <libdevcore/Assertions.h> #include <libdevcore/CommonData.h> #include <libdevcore/CommonIO.h> @@ -50,6 +52,7 @@ public: static unsigned optimiseConstants( bool _isCreation, size_t _runs, + solidity::EVMVersion _evmVersion, Assembly& _assembly, AssemblyItems& _items ); @@ -59,6 +62,7 @@ public: bool isCreation; ///< Whether this is called during contract creation or runtime. size_t runs; ///< Estimated number of calls per opcode oven the lifetime of the contract. size_t multiplicity; ///< Number of times the constant appears in the code. + solidity::EVMVersion evmVersion; ///< Version of the EVM }; explicit ConstantOptimisationMethod(Params const& _params, u256 const& _value): diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp index 543f1cbc..caa06fc0 100644 --- a/libevmasm/GasMeter.cpp +++ b/libevmasm/GasMeter.cpp @@ -61,7 +61,6 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _ case Operation: { ExpressionClasses& classes = m_state->expressionClasses(); - gas = runGas(_item.instruction()); switch (_item.instruction()) { case Instruction::SSTORE: @@ -72,26 +71,29 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _ m_state->storageContent().count(slot) && classes.knownNonZero(m_state->storageContent().at(slot)) )) - gas += GasCosts::sstoreResetGas; //@todo take refunds into account + gas = GasCosts::sstoreResetGas; //@todo take refunds into account else - gas += GasCosts::sstoreSetGas; + gas = GasCosts::sstoreSetGas; break; } case Instruction::SLOAD: - gas += GasCosts::sloadGas; + gas = GasCosts::sloadGas(m_evmVersion); break; case Instruction::RETURN: case Instruction::REVERT: + gas = runGas(_item.instruction()); gas += memoryGas(0, -1); break; case Instruction::MLOAD: case Instruction::MSTORE: + gas = runGas(_item.instruction()); gas += memoryGas(classes.find(Instruction::ADD, { m_state->relativeStackElement(0), classes.find(AssemblyItem(32)) })); break; case Instruction::MSTORE8: + gas = runGas(_item.instruction()); gas += memoryGas(classes.find(Instruction::ADD, { m_state->relativeStackElement(0), classes.find(AssemblyItem(1)) @@ -105,10 +107,15 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _ case Instruction::CALLDATACOPY: case Instruction::CODECOPY: case Instruction::RETURNDATACOPY: + gas = runGas(_item.instruction()); gas += memoryGas(0, -2); gas += wordGas(GasCosts::copyGas, m_state->relativeStackElement(-2)); break; + case Instruction::EXTCODESIZE: + gas = GasCosts::extCodeGas(m_evmVersion); + break; case Instruction::EXTCODECOPY: + gas = GasCosts::extCodeGas(m_evmVersion); gas += memoryGas(-1, -3); gas += wordGas(GasCosts::copyGas, m_state->relativeStackElement(-3)); break; @@ -137,7 +144,7 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _ gas = GasConsumption::infinite(); else { - gas = GasCosts::callGas; + gas = GasCosts::callGas(m_evmVersion); if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(0))) gas += (*value); else @@ -155,7 +162,7 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _ break; } case Instruction::SELFDESTRUCT: - gas = GasCosts::selfdestructGas; + gas = GasCosts::selfdestructGas(m_evmVersion); gas += GasCosts::callNewAccountGas; // We very rarely know whether the address exists. break; case Instruction::CREATE: @@ -172,11 +179,15 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _ case Instruction::EXP: gas = GasCosts::expGas; if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1))) - gas += GasCosts::expByteGas * (32 - (h256(*value).firstBitSet() / 8)); + gas += GasCosts::expByteGas(m_evmVersion) * (32 - (h256(*value).firstBitSet() / 8)); else - gas += GasCosts::expByteGas * 32; + gas += GasCosts::expByteGas(m_evmVersion) * 32; + break; + case Instruction::BALANCE: + gas = GasCosts::balanceGas(m_evmVersion); break; default: + gas = runGas(_item.instruction()); break; } break; @@ -241,12 +252,9 @@ unsigned GasMeter::runGas(Instruction _instruction) case Tier::Mid: return GasCosts::tier4Gas; case Tier::High: return GasCosts::tier5Gas; case Tier::Ext: return GasCosts::tier6Gas; - case Tier::Special: return GasCosts::tier7Gas; - case Tier::ExtCode: return GasCosts::extCodeGas; - case Tier::Balance: return GasCosts::balanceGas; default: break; } - assertThrow(false, OptimizerException, "Invalid gas tier."); + assertThrow(false, OptimizerException, "Invalid gas tier for instruction " + instructionInfo(_instruction).name); return 0; } diff --git a/libevmasm/GasMeter.h b/libevmasm/GasMeter.h index 2c3ecf5a..b131802f 100644 --- a/libevmasm/GasMeter.h +++ b/libevmasm/GasMeter.h @@ -21,11 +21,14 @@ #pragma once -#include <ostream> -#include <tuple> #include <libevmasm/ExpressionClasses.h> #include <libevmasm/AssemblyItem.h> +#include <libsolidity/interface/EVMVersion.h> + +#include <ostream> +#include <tuple> + namespace dev { namespace eth @@ -44,13 +47,25 @@ namespace GasCosts static unsigned const tier5Gas = 10; static unsigned const tier6Gas = 20; static unsigned const tier7Gas = 0; - static unsigned const extCodeGas = 700; - static unsigned const balanceGas = 400; + inline unsigned extCodeGas(EVMVersion _evmVersion) + { + return _evmVersion >= EVMVersion::tangerineWhistle() ? 700 : 20; + } + inline unsigned balanceGas(EVMVersion _evmVersion) + { + return _evmVersion >= EVMVersion::tangerineWhistle() ? 400 : 20; + } static unsigned const expGas = 10; - static unsigned const expByteGas = 50; + inline unsigned expByteGas(EVMVersion _evmVersion) + { + return _evmVersion >= EVMVersion::spuriousDragon() ? 50 : 10; + } static unsigned const keccak256Gas = 30; static unsigned const keccak256WordGas = 6; - static unsigned const sloadGas = 200; + inline unsigned sloadGas(EVMVersion _evmVersion) + { + return _evmVersion >= EVMVersion::tangerineWhistle() ? 200 : 50; + } static unsigned const sstoreSetGas = 20000; static unsigned const sstoreResetGas = 5000; static unsigned const sstoreRefundGas = 15000; @@ -59,11 +74,17 @@ namespace GasCosts static unsigned const logDataGas = 8; static unsigned const logTopicGas = 375; static unsigned const createGas = 32000; - static unsigned const callGas = 700; + inline unsigned callGas(EVMVersion _evmVersion) + { + return _evmVersion >= EVMVersion::tangerineWhistle() ? 700 : 40; + } static unsigned const callStipend = 2300; static unsigned const callValueTransferGas = 9000; static unsigned const callNewAccountGas = 25000; - static unsigned const selfdestructGas = 5000; + inline unsigned selfdestructGas(EVMVersion _evmVersion) + { + return _evmVersion >= EVMVersion::tangerineWhistle() ? 5000 : 0; + } static unsigned const selfdestructRefundGas = 24000; static unsigned const memoryGas = 3; static unsigned const quadCoeffDiv = 512; @@ -100,8 +121,8 @@ public: }; /// Constructs a new gas meter given the current state. - explicit GasMeter(std::shared_ptr<KnownState> const& _state, u256 const& _largestMemoryAccess = 0): - m_state(_state), m_largestMemoryAccess(_largestMemoryAccess) {} + GasMeter(std::shared_ptr<KnownState> const& _state, solidity::EVMVersion _evmVersion, u256 const& _largestMemoryAccess = 0): + m_state(_state), m_evmVersion(_evmVersion), m_largestMemoryAccess(_largestMemoryAccess) {} /// @returns an upper bound on the gas consumed by the given instruction and updates /// the state. @@ -110,6 +131,8 @@ public: u256 const& largestMemoryAccess() const { return m_largestMemoryAccess; } + /// @returns gas costs for simple instructions with constant gas costs (that do not + /// change with EVM versions) static unsigned runGas(Instruction _instruction); private: @@ -123,6 +146,7 @@ private: GasConsumption memoryGas(int _stackPosOffset, int _stackPosSize); std::shared_ptr<KnownState> m_state; + EVMVersion m_evmVersion; /// Largest point where memory was accessed since the creation of this object. u256 m_largestMemoryAccess; }; diff --git a/libevmasm/PathGasMeter.cpp b/libevmasm/PathGasMeter.cpp index c56e2f8b..3fe682b7 100644 --- a/libevmasm/PathGasMeter.cpp +++ b/libevmasm/PathGasMeter.cpp @@ -27,8 +27,8 @@ using namespace std; using namespace dev; using namespace dev::eth; -PathGasMeter::PathGasMeter(AssemblyItems const& _items): - m_items(_items) +PathGasMeter::PathGasMeter(AssemblyItems const& _items, solidity::EVMVersion _evmVersion): + m_items(_items), m_evmVersion(_evmVersion) { for (size_t i = 0; i < m_items.size(); ++i) if (m_items[i].type() == Tag) @@ -59,7 +59,7 @@ GasMeter::GasConsumption PathGasMeter::handleQueueItem() m_queue.pop_back(); shared_ptr<KnownState> state = path->state; - GasMeter meter(state, path->largestMemoryAccess); + GasMeter meter(state, m_evmVersion, path->largestMemoryAccess); ExpressionClasses& classes = state->expressionClasses(); GasMeter::GasConsumption gas = path->gas; size_t index = path->index; diff --git a/libevmasm/PathGasMeter.h b/libevmasm/PathGasMeter.h index 4826eac2..2527d7fb 100644 --- a/libevmasm/PathGasMeter.h +++ b/libevmasm/PathGasMeter.h @@ -21,10 +21,13 @@ #pragma once +#include <libevmasm/GasMeter.h> + +#include <libsolidity/interface/EVMVersion.h> + #include <set> #include <vector> #include <memory> -#include <libevmasm/GasMeter.h> namespace dev { @@ -50,7 +53,7 @@ struct GasPath class PathGasMeter { public: - explicit PathGasMeter(AssemblyItems const& _items); + explicit PathGasMeter(AssemblyItems const& _items, solidity::EVMVersion _evmVersion); GasMeter::GasConsumption estimateMax(size_t _startIndex, std::shared_ptr<KnownState> const& _state); @@ -60,6 +63,7 @@ private: std::vector<std::unique_ptr<GasPath>> m_queue; std::map<u256, size_t> m_tagPositions; AssemblyItems const& m_items; + solidity::EVMVersion m_evmVersion; }; } diff --git a/liblll/Compiler.cpp b/liblll/Compiler.cpp index 1638f69e..f2c1b0be 100644 --- a/liblll/Compiler.cpp +++ b/liblll/Compiler.cpp @@ -19,17 +19,16 @@ * @date 2014 */ -#include "Compiler.h" -#include "Parser.h" -#include "CompilerState.h" -#include "CodeFragment.h" +#include <liblll/Compiler.h> +#include <liblll/Parser.h> +#include <liblll/CompilerState.h> +#include <liblll/CodeFragment.h> using namespace std; using namespace dev; using namespace dev::eth; - -bytes dev::eth::compileLLL(string const& _src, bool _opt, vector<string>* _errors, ReadCallback const& _readFile) +bytes dev::eth::compileLLL(string const& _src, dev::solidity::EVMVersion _evmVersion, bool _opt, std::vector<std::string>* _errors, dev::eth::ReadCallback const& _readFile) { try { @@ -37,7 +36,7 @@ bytes dev::eth::compileLLL(string const& _src, bool _opt, vector<string>* _error cs.populateStandard(); auto assembly = CodeFragment::compile(_src, cs, _readFile).assembly(cs); if (_opt) - assembly = assembly.optimise(true); + assembly = assembly.optimise(true, _evmVersion); bytes ret = assembly.assemble().bytecode; for (auto i: cs.treesToKill) killBigints(i); @@ -67,7 +66,7 @@ bytes dev::eth::compileLLL(string const& _src, bool _opt, vector<string>* _error return bytes(); } -std::string dev::eth::compileLLLToAsm(std::string const& _src, bool _opt, std::vector<std::string>* _errors, ReadCallback const& _readFile) +std::string dev::eth::compileLLLToAsm(std::string const& _src, EVMVersion _evmVersion, bool _opt, std::vector<std::string>* _errors, ReadCallback const& _readFile) { try { @@ -75,7 +74,7 @@ std::string dev::eth::compileLLLToAsm(std::string const& _src, bool _opt, std::v cs.populateStandard(); auto assembly = CodeFragment::compile(_src, cs, _readFile).assembly(cs); if (_opt) - assembly = assembly.optimise(true); + assembly = assembly.optimise(true, _evmVersion); string ret = assembly.assemblyString(); for (auto i: cs.treesToKill) killBigints(i); diff --git a/liblll/Compiler.h b/liblll/Compiler.h index c3395b66..06440c17 100644 --- a/liblll/Compiler.h +++ b/liblll/Compiler.h @@ -21,9 +21,12 @@ #pragma once +#include <libdevcore/Common.h> + +#include <libsolidity/interface/EVMVersion.h> + #include <string> #include <vector> -#include <libdevcore/Common.h> namespace dev { @@ -33,8 +36,8 @@ namespace eth using ReadCallback = std::function<std::string(std::string const&)>; std::string parseLLL(std::string const& _src); -std::string compileLLLToAsm(std::string const& _src, bool _opt = true, std::vector<std::string>* _errors = nullptr, ReadCallback const& _readFile = ReadCallback()); -bytes compileLLL(std::string const& _src, bool _opt = true, std::vector<std::string>* _errors = nullptr, ReadCallback const& _readFile = ReadCallback()); +std::string compileLLLToAsm(std::string const& _src, solidity::EVMVersion _evmVersion, bool _opt = true, std::vector<std::string>* _errors = nullptr, ReadCallback const& _readFile = ReadCallback()); +bytes compileLLL(std::string const& _src, solidity::EVMVersion _evmVersion, bool _opt = true, std::vector<std::string>* _errors = nullptr, ReadCallback const& _readFile = ReadCallback()); } } diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index e6b2484a..cf626683 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -209,7 +209,7 @@ public: void appendAuxiliaryData(bytes const& _data) { m_asm->appendAuxiliaryDataToEnd(_data); } /// Run optimisation step. - void optimise(bool _fullOptimsation, unsigned _runs = 200) { m_asm->optimise(_fullOptimsation, true, _runs); } + void optimise(bool _fullOptimsation, unsigned _runs = 200) { m_asm->optimise(_fullOptimsation, m_evmVersion, true, _runs); } /// @returns the runtime context if in creation mode and runtime context is set, nullptr otherwise. CompilerContext* runtimeContext() { return m_runtimeContext; } diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index ebb718a5..5a9498f0 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -1059,7 +1059,7 @@ void ContractCompiler::compileExpression(Expression const& _expression, TypePoin CompilerUtils(m_context).convertType(*_expression.annotation().type, *_targetType); } -eth::AssemblyPointer ContractCompiler::cloneRuntime() +eth::AssemblyPointer ContractCompiler::cloneRuntime() const { eth::Assembly a; a << Instruction::CALLDATASIZE; @@ -1070,7 +1070,7 @@ eth::AssemblyPointer ContractCompiler::cloneRuntime() // this is the address which has to be substituted by the linker. //@todo implement as special "marker" AssemblyItem. a << u256("0xcafecafecafecafecafecafecafecafecafecafe"); - a << u256(eth::GasCosts::callGas + 10) << Instruction::GAS << Instruction::SUB; + a << u256(eth::GasCosts::callGas(m_context.evmVersion()) + 10) << Instruction::GAS << Instruction::SUB; a << Instruction::DELEGATECALL; //Propagate error condition (if DELEGATECALL pushes 0 on stack). a << Instruction::ISZERO; diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h index 18f31967..8559ea58 100644 --- a/libsolidity/codegen/ContractCompiler.h +++ b/libsolidity/codegen/ContractCompiler.h @@ -125,7 +125,7 @@ private: void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer()); /// @returns the runtime assembly for clone contracts. - static eth::AssemblyPointer cloneRuntime(); + eth::AssemblyPointer cloneRuntime() const; bool const m_optimise; /// Pointer to the runtime compiler in case this is a creation compiler. diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 61920592..12881d63 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1756,7 +1756,7 @@ void ExpressionCompiler::appendExternalFunctionCall( { // send all gas except the amount needed to execute "SUB" and "CALL" // @todo this retains too much gas for now, needs to be fine-tuned. - u256 gasNeededByCaller = eth::GasCosts::callGas + 10; + u256 gasNeededByCaller = eth::GasCosts::callGas(m_context.evmVersion()) + 10; if (_functionType.valueSet()) gasNeededByCaller += eth::GasCosts::callValueTransferGas; if (!existenceChecked) diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index cb1ca3aa..eacfca9c 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -959,11 +959,12 @@ Json::Value CompilerStack::gasEstimates(string const& _contractName) const return Json::Value(); using Gas = GasEstimator::GasConsumption; + GasEstimator gasEstimator(m_evmVersion); Json::Value output(Json::objectValue); if (eth::AssemblyItems const* items = assemblyItems(_contractName)) { - Gas executionGas = GasEstimator::functionalEstimation(*items); + Gas executionGas = gasEstimator.functionalEstimation(*items); u256 bytecodeSize(runtimeObject(_contractName).bytecode.size()); Gas codeDepositGas = bytecodeSize * eth::GasCosts::createDataGas; @@ -984,14 +985,14 @@ Json::Value CompilerStack::gasEstimates(string const& _contractName) const for (auto it: contract.interfaceFunctions()) { string sig = it.second->externalSignature(); - externalFunctions[sig] = gasToJson(GasEstimator::functionalEstimation(*items, sig)); + externalFunctions[sig] = gasToJson(gasEstimator.functionalEstimation(*items, sig)); } if (contract.fallbackFunction()) /// This needs to be set to an invalid signature in order to trigger the fallback, /// without the shortcut (of CALLDATSIZE == 0), and therefore to receive the upper bound. /// An empty string ("") would work to trigger the shortcut only. - externalFunctions[""] = gasToJson(GasEstimator::functionalEstimation(*items, "INVALID")); + externalFunctions[""] = gasToJson(gasEstimator.functionalEstimation(*items, "INVALID")); if (!externalFunctions.empty()) output["external"] = externalFunctions; @@ -1007,7 +1008,7 @@ Json::Value CompilerStack::gasEstimates(string const& _contractName) const size_t entry = functionEntryPoint(_contractName, *it); GasEstimator::GasConsumption gas = GasEstimator::GasConsumption::infinite(); if (entry > 0) - gas = GasEstimator::functionalEstimation(*items, entry, *it); + gas = gasEstimator.functionalEstimation(*items, entry, *it); /// TODO: This could move into a method shared with externalSignature() FunctionType type(*it); diff --git a/libsolidity/interface/GasEstimator.cpp b/libsolidity/interface/GasEstimator.cpp index 22cc0266..2139395f 100644 --- a/libsolidity/interface/GasEstimator.cpp +++ b/libsolidity/interface/GasEstimator.cpp @@ -40,7 +40,7 @@ using namespace dev::solidity; GasEstimator::ASTGasConsumptionSelfAccumulated GasEstimator::structuralEstimation( AssemblyItems const& _items, vector<ASTNode const*> const& _ast -) +) const { solAssert(std::count(_ast.begin(), _ast.end(), nullptr) == 0, ""); map<SourceLocation, GasConsumption> particularCosts; @@ -49,7 +49,7 @@ GasEstimator::ASTGasConsumptionSelfAccumulated GasEstimator::structuralEstimatio for (BasicBlock const& block: cfg.optimisedBlocks()) { solAssert(!!block.startState, ""); - GasMeter meter(block.startState->copy()); + GasMeter meter(block.startState->copy(), m_evmVersion); auto const end = _items.begin() + block.end; for (auto iter = _items.begin() + block.begin; iter != end; ++iter) particularCosts[iter->location()] += meter.estimateMax(*iter); @@ -127,7 +127,7 @@ map<ASTNode const*, GasMeter::GasConsumption> GasEstimator::breakToStatementLeve GasEstimator::GasConsumption GasEstimator::functionalEstimation( AssemblyItems const& _items, string const& _signature -) +) const { auto state = make_shared<KnownState>(); @@ -144,7 +144,7 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation( }); } - PathGasMeter meter(_items); + PathGasMeter meter(_items, m_evmVersion); return meter.estimateMax(0, state); } @@ -152,7 +152,7 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation( AssemblyItems const& _items, size_t const& _offset, FunctionDefinition const& _function -) +) const { auto state = make_shared<KnownState>(); @@ -167,7 +167,7 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation( if (parametersSize > 0) state->feedItem(swapInstruction(parametersSize)); - return PathGasMeter(_items).estimateMax(_offset, state); + return PathGasMeter(_items, m_evmVersion).estimateMax(_offset, state); } set<ASTNode const*> GasEstimator::finestNodesAtLocation( diff --git a/libsolidity/interface/GasEstimator.h b/libsolidity/interface/GasEstimator.h index bf63df96..ea94d988 100644 --- a/libsolidity/interface/GasEstimator.h +++ b/libsolidity/interface/GasEstimator.h @@ -22,11 +22,14 @@ #pragma once +#include <libsolidity/interface/EVMVersion.h> + +#include <libevmasm/GasMeter.h> +#include <libevmasm/Assembly.h> + #include <vector> #include <map> #include <array> -#include <libevmasm/GasMeter.h> -#include <libevmasm/Assembly.h> namespace dev { @@ -44,13 +47,15 @@ public: using ASTGasConsumptionSelfAccumulated = std::map<ASTNode const*, std::array<GasConsumption, 2>>; + explicit GasEstimator(EVMVersion _evmVersion): m_evmVersion(_evmVersion) {} + /// Estimates the gas consumption for every assembly item in the given assembly and stores /// it by source location. /// @returns a mapping from each AST node to a pair of its particular and syntactically accumulated gas costs. - static ASTGasConsumptionSelfAccumulated structuralEstimation( + ASTGasConsumptionSelfAccumulated structuralEstimation( eth::AssemblyItems const& _items, std::vector<ASTNode const*> const& _ast - ); + ) const; /// @returns a mapping from nodes with non-overlapping source locations to gas consumptions such that /// the following source locations are part of the mapping: /// 1. source locations of statements that do not contain other statements @@ -62,23 +67,24 @@ public: /// @returns the estimated gas consumption by the (public or external) function with the /// given signature. If no signature is given, estimates the maximum gas usage. - static GasConsumption functionalEstimation( + GasConsumption functionalEstimation( eth::AssemblyItems const& _items, std::string const& _signature = "" - ); + ) const; /// @returns the estimated gas consumption by the given function which starts at the given /// offset into the list of assembly items. /// @note this does not work correctly for recursive functions. - static GasConsumption functionalEstimation( + GasConsumption functionalEstimation( eth::AssemblyItems const& _items, size_t const& _offset, FunctionDefinition const& _function - ); + ) const; private: /// @returns the set of AST nodes which are the finest nodes at their location. static std::set<ASTNode const*> finestNodesAtLocation(std::vector<ASTNode const*> const& _roots); + EVMVersion m_evmVersion; }; } diff --git a/lllc/main.cpp b/lllc/main.cpp index 5679bc2b..0ca3ff13 100644 --- a/lllc/main.cpp +++ b/lllc/main.cpp @@ -133,7 +133,7 @@ int main(int argc, char** argv) } else if (mode == Binary || mode == Hex) { - auto bs = compileLLL(src, optimise ? true : false, &errors, readFileAsString); + auto bs = compileLLL(src, EVMVersion{}, optimise ? true : false, &errors, readFileAsString); if (mode == Hex) cout << toHex(bs) << endl; else if (mode == Binary) @@ -145,7 +145,7 @@ int main(int argc, char** argv) } else if (mode == Assembly) { - cout << compileLLLToAsm(src, optimise ? true : false, &errors, readFileAsString) << endl; + cout << compileLLLToAsm(src, EVMVersion{}, optimise ? true : false, &errors, readFileAsString) << endl; } for (auto const& i: errors) diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index fd079656..d3d234c3 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -748,7 +748,6 @@ bool CommandLineInterface::processInput() if (!parseLibraryOption(library)) return false; - EVMVersion evmVersion; if (m_args.count(g_strEVMVersion)) { string versionOptionStr = m_args[g_strEVMVersion].as<string>(); @@ -758,7 +757,7 @@ bool CommandLineInterface::processInput() cerr << "Invalid option for --evm-version: " << versionOptionStr << endl; return false; } - evmVersion = *versionOption; + m_evmVersion = *versionOption; } if (m_args.count(g_argAssemble) || m_args.count(g_argStrictAssembly) || m_args.count(g_argJulia)) @@ -784,7 +783,7 @@ bool CommandLineInterface::processInput() return false; } } - return assemble(evmVersion, inputLanguage, targetMachine); + return assemble(inputLanguage, targetMachine); } if (m_args.count(g_argLink)) { @@ -808,8 +807,7 @@ bool CommandLineInterface::processInput() m_compiler->addSource(sourceCode.first, sourceCode.second); if (m_args.count(g_argLibraries)) m_compiler->setLibraries(m_libraries); - if (m_args.count(g_strEVMVersion)) - m_compiler->setEVMVersion(evmVersion); + m_compiler->setEVMVersion(m_evmVersion); // TODO: Perhaps we should not compile unless requested bool optimize = m_args.count(g_argOptimize) > 0; unsigned runs = m_args[g_argOptimizeRuns].as<unsigned>(); @@ -968,7 +966,7 @@ void CommandLineInterface::handleAst(string const& _argStr) // FIXME: shouldn't this be done for every contract? if (m_compiler->runtimeAssemblyItems(m_compiler->lastContractName())) gasCosts = GasEstimator::breakToStatementLevel( - GasEstimator::structuralEstimation(*m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()), asts), + GasEstimator(m_evmVersion).structuralEstimation(*m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()), asts), asts ); @@ -1081,7 +1079,6 @@ void CommandLineInterface::writeLinkedFiles() } bool CommandLineInterface::assemble( - EVMVersion _evmVersion, AssemblyStack::Language _language, AssemblyStack::Machine _targetMachine ) @@ -1090,7 +1087,7 @@ bool CommandLineInterface::assemble( map<string, AssemblyStack> assemblyStacks; for (auto const& src: m_sourceCodes) { - auto& stack = assemblyStacks[src.first] = AssemblyStack(_evmVersion, _language); + auto& stack = assemblyStacks[src.first] = AssemblyStack(m_evmVersion, _language); try { if (!stack.parseAndAnalyze(src.first, src.second)) diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 81117fdc..303023fc 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -23,6 +23,7 @@ #include <libsolidity/interface/CompilerStack.h> #include <libsolidity/interface/AssemblyStack.h> +#include <libsolidity/interface/EVMVersion.h> #include <boost/program_options.hpp> #include <boost/filesystem/path.hpp> @@ -54,7 +55,7 @@ private: bool link(); void writeLinkedFiles(); - bool assemble(EVMVersion _evmVersion, AssemblyStack::Language _language, AssemblyStack::Machine _targetMachine); + bool assemble(AssemblyStack::Language _language, AssemblyStack::Machine _targetMachine); void outputCompilationResults(); @@ -102,6 +103,8 @@ private: std::map<std::string, h160> m_libraries; /// Solidity compiler stack std::unique_ptr<dev::solidity::CompilerStack> m_compiler; + /// EVM version to use + EVMVersion m_evmVersion; }; } diff --git a/test/contracts/LLL_ENS.cpp b/test/contracts/LLL_ENS.cpp index c5fe8a82..028d58c8 100644 --- a/test/contracts/LLL_ENS.cpp +++ b/test/contracts/LLL_ENS.cpp @@ -345,7 +345,7 @@ protected: if (!s_compiledEns) { vector<string> errors; - s_compiledEns.reset(new bytes(compileLLL(ensCode, dev::test::Options::get().optimize, &errors))); + s_compiledEns.reset(new bytes(compileLLL(ensCode, dev::test::Options::get().evmVersion(), dev::test::Options::get().optimize, &errors))); BOOST_REQUIRE(errors.empty()); } sendMessage(*s_compiledEns, true); diff --git a/test/contracts/LLL_ERC20.cpp b/test/contracts/LLL_ERC20.cpp index 25665d64..60b43e4f 100644 --- a/test/contracts/LLL_ERC20.cpp +++ b/test/contracts/LLL_ERC20.cpp @@ -396,7 +396,7 @@ protected: if (!s_compiledErc20) { vector<string> errors; - s_compiledErc20.reset(new bytes(compileLLL(erc20Code, dev::test::Options::get().optimize, &errors))); + s_compiledErc20.reset(new bytes(compileLLL(erc20Code, dev::test::Options::get().evmVersion(), dev::test::Options::get().optimize, &errors))); BOOST_REQUIRE(errors.empty()); } sendMessage(*s_compiledErc20, true); diff --git a/test/fuzzer.cpp b/test/fuzzer.cpp index 45738baa..71f38b67 100644 --- a/test/fuzzer.cpp +++ b/test/fuzzer.cpp @@ -76,6 +76,7 @@ void testConstantOptimizer() ConstantOptimisationMethod::optimiseConstants( isCreation, runs, + EVMVersion{}, assembly, const_cast<AssemblyItems&>(assembly.items()) ); diff --git a/test/libevmasm/Optimiser.cpp b/test/libevmasm/Optimiser.cpp index 0ab95b08..e6abcb53 100644 --- a/test/libevmasm/Optimiser.cpp +++ b/test/libevmasm/Optimiser.cpp @@ -20,6 +20,8 @@ * Tests for the Solidity optimizer. */ +#include <test/TestHelper.h> + #include <libevmasm/CommonSubexpressionEliminator.h> #include <libevmasm/PeepholeOptimiser.h> #include <libevmasm/JumpdestRemover.h> @@ -916,7 +918,7 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies) main.append(t1.toSubAssemblyTag(subId)); main.append(u256(8)); - main.optimise(true); + main.optimise(true, dev::test::Options::get().evmVersion()); AssemblyItems expectationMain{ AssemblyItem(PushSubSize, 0), diff --git a/test/liblll/Compiler.cpp b/test/liblll/Compiler.cpp index ace97e15..6c6eae3f 100644 --- a/test/liblll/Compiler.cpp +++ b/test/liblll/Compiler.cpp @@ -20,11 +20,16 @@ * Unit tests for the LLL compiler. */ +#include <test/TestHelper.h> + +#include <libdevcore/FixedHash.h> + +#include <liblll/Compiler.h> + +#include <boost/test/unit_test.hpp> + #include <string> #include <memory> -#include <boost/test/unit_test.hpp> -#include <liblll/Compiler.h> -#include <libdevcore/FixedHash.h> using namespace std; @@ -41,7 +46,7 @@ namespace bool successCompile(string const& _sourceCode) { vector<string> errors; - bytes bytecode = eth::compileLLL(_sourceCode, false, &errors); + bytes bytecode = eth::compileLLL(_sourceCode, dev::test::Options::get().evmVersion(), false, &errors); if (!errors.empty()) return false; if (bytecode.empty()) @@ -353,7 +358,7 @@ BOOST_AUTO_TEST_CASE(valid_opcodes_functional) for (size_t i = 0; i < opcodes_bytecode.size(); i++) { vector<string> errors; - bytes code = eth::compileLLL(opcodes_lll[i], false, &errors); + bytes code = eth::compileLLL(opcodes_lll[i], dev::test::Options::get().evmVersion(), false, &errors); BOOST_REQUIRE_MESSAGE(errors.empty(), opcodes_lll[i]); @@ -641,7 +646,7 @@ BOOST_AUTO_TEST_CASE(valid_opcodes_asm) for (size_t i = 0; i < opcodes_bytecode.size(); i++) { vector<string> errors; - bytes code = eth::compileLLL(opcodes_lll[i], false, &errors); + bytes code = eth::compileLLL(opcodes_lll[i], dev::test::Options::get().evmVersion(), false, &errors); BOOST_REQUIRE_MESSAGE(errors.empty(), opcodes_lll[i]); diff --git a/test/liblll/EndToEndTest.cpp b/test/liblll/EndToEndTest.cpp index 1a5bb490..e5e70cf8 100644 --- a/test/liblll/EndToEndTest.cpp +++ b/test/liblll/EndToEndTest.cpp @@ -20,10 +20,13 @@ * End to end tests for LLL. */ +#include <test/liblll/ExecutionFramework.h> +#include <test/TestHelper.h> + +#include <boost/test/unit_test.hpp> + #include <string> #include <memory> -#include <boost/test/unit_test.hpp> -#include <test/liblll/ExecutionFramework.h> using namespace std; @@ -583,24 +586,34 @@ BOOST_AUTO_TEST_CASE(allgas) BOOST_AUTO_TEST_CASE(send_two_args) { - char const* sourceCode = R"( - (returnlll - (send 0xdead 42)) - )"; - compileAndRun(sourceCode); - callFallbackWithValue(42); - BOOST_CHECK(balanceAt(Address(0xdead)) == 42); + // "send" does not retain enough gas to be able to pay for account creation. + // Disabling for non-tangerineWhistle VMs. + if (dev::test::Options::get().evmVersion().canOverchargeGasForCall()) + { + char const* sourceCode = R"( + (returnlll + (send 0xdead 42)) + )"; + compileAndRun(sourceCode); + callFallbackWithValue(42); + BOOST_CHECK(balanceAt(Address(0xdead)) == 42); + } } BOOST_AUTO_TEST_CASE(send_three_args) { - char const* sourceCode = R"( - (returnlll - (send allgas 0xdead 42)) - )"; - compileAndRun(sourceCode); - callFallbackWithValue(42); - BOOST_CHECK(balanceAt(Address(0xdead)) == 42); + // "send" does not retain enough gas to be able to pay for account creation. + // Disabling for non-tangerineWhistle VMs. + if (dev::test::Options::get().evmVersion().canOverchargeGasForCall()) + { + char const* sourceCode = R"( + (returnlll + (send allgas 0xdead 42)) + )"; + compileAndRun(sourceCode); + callFallbackWithValue(42); + BOOST_CHECK(balanceAt(Address(0xdead)) == 42); + } } // Regression test for edge case that previously failed @@ -708,56 +721,76 @@ BOOST_AUTO_TEST_CASE(msg_four_args) BOOST_AUTO_TEST_CASE(msg_three_args) { - char const* sourceCode = R"( - (returnlll - (seq - (when (= 0 (calldatasize)) - (return (msg (address) 42 0xff))) - (return (callvalue)))) - )"; - compileAndRun(sourceCode); - BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42))); + // "msg" does not retain enough gas. + // Disabling for non-tangerineWhistle VMs. + if (dev::test::Options::get().evmVersion().canOverchargeGasForCall()) + { + char const* sourceCode = R"( + (returnlll + (seq + (when (= 0 (calldatasize)) + (return (msg (address) 42 0xff))) + (return (callvalue)))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42))); + } } BOOST_AUTO_TEST_CASE(msg_two_args) { - char const* sourceCode = R"( - (returnlll - (seq - (when (= 0 (calldatasize)) - (return (msg (address) 0xff))) - (return 42))) - )"; - compileAndRun(sourceCode); - BOOST_CHECK(callFallback() == encodeArgs(u256(42))); + // "msg" does not retain enough gas. + // Disabling for non-tangerineWhistle VMs. + if (dev::test::Options::get().evmVersion().canOverchargeGasForCall()) + { + char const* sourceCode = R"( + (returnlll + (seq + (when (= 0 (calldatasize)) + (return (msg (address) 0xff))) + (return 42))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callFallback() == encodeArgs(u256(42))); + } } BOOST_AUTO_TEST_CASE(create_one_arg) { - char const* sourceCode = R"( - (returnlll - (seq - (call allgas - (create (returnlll (return 42))) - 0 0 0 0x00 0x20) - (return 0x00 0x20))) - )"; - compileAndRun(sourceCode); - BOOST_CHECK(callFallback() == encodeArgs(u256(42))); + // "call" does not retain enough gas. + // Disabling for non-tangerineWhistle VMs. + if (dev::test::Options::get().evmVersion().canOverchargeGasForCall()) + { + char const* sourceCode = R"( + (returnlll + (seq + (call allgas + (create (returnlll (return 42))) + 0 0 0 0x00 0x20) + (return 0x00 0x20))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callFallback() == encodeArgs(u256(42))); + } } BOOST_AUTO_TEST_CASE(create_two_args) { - char const* sourceCode = R"( - (returnlll - (seq - (call allgas - (create 42 (returnlll (return (balance (address))))) - 0 0 0 0x00 0x20) - (return 0x00 0x20))) - )"; - compileAndRun(sourceCode); - BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42))); + // "call" does not retain enough gas. + // Disabling for non-tangerineWhistle VMs. + if (dev::test::Options::get().evmVersion().canOverchargeGasForCall()) + { + char const* sourceCode = R"( + (returnlll + (seq + (call allgas + (create 42 (returnlll (return (balance (address))))) + 0 0 0 0x00 0x20) + (return 0x00 0x20))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42))); + } } BOOST_AUTO_TEST_CASE(sha3_two_args) @@ -822,77 +855,102 @@ BOOST_AUTO_TEST_CASE(makeperm) // Covers makeperm (implicit), permcount and perm BOOST_AUTO_TEST_CASE(ecrecover) { - char const* sourceCode = R"( - (returnlll - (return - (ecrecover - ; Hash of 'hello world' - 0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad - ; v = 1 + 27 - 0x1c - ; r - 0xdebaaa0cddb321b2dcaaf846d39605de7b97e77ba6106587855b9106cb104215 - ; s - 0x61a22d94fa8b8a687ff9c911c844d1c016d1a685a9166858f9c7c1bc85128aca))) - )"; - compileAndRun(sourceCode); - BOOST_CHECK(callFallback() == encodeArgs(fromHex("0x8743523d96a1b2cbe0c6909653a56da18ed484af"))); + // "ecrecover" does not retain enough gas. + // Disabling for non-tangerineWhistle VMs. + if (dev::test::Options::get().evmVersion().canOverchargeGasForCall()) + { + char const* sourceCode = R"( + (returnlll + (return + (ecrecover + ; Hash of 'hello world' + 0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad + ; v = 1 + 27 + 0x1c + ; r + 0xdebaaa0cddb321b2dcaaf846d39605de7b97e77ba6106587855b9106cb104215 + ; s + 0x61a22d94fa8b8a687ff9c911c844d1c016d1a685a9166858f9c7c1bc85128aca))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callFallback() == encodeArgs(fromHex("0x8743523d96a1b2cbe0c6909653a56da18ed484af"))); + } } BOOST_AUTO_TEST_CASE(sha256_two_args) { - char const* sourceCode = R"( - (returnlll - (seq - (lit 0x20 "abcdefghijklmnopqrstuvwxyzABCDEF") - (lit 0x40 "GHIJKLMNOPQRSTUVWXYZ0123456789?!") - (sha256 0x20 0x40) - (return 0x00 0x20))) - )"; - compileAndRun(sourceCode); - BOOST_CHECK(callFallback() == encodeArgs( - fromHex("0xcf25a9fe3d86ae228c226c81d2d8c64c687cd6dc4586d10d8e7e4e5b6706d429"))); + // "sha256" does not retain enough gas. + // Disabling for non-tangerineWhistle VMs. + if (dev::test::Options::get().evmVersion().canOverchargeGasForCall()) + { + char const* sourceCode = R"( + (returnlll + (seq + (lit 0x20 "abcdefghijklmnopqrstuvwxyzABCDEF") + (lit 0x40 "GHIJKLMNOPQRSTUVWXYZ0123456789?!") + (sha256 0x20 0x40) + (return 0x00 0x20))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callFallback() == encodeArgs( + fromHex("0xcf25a9fe3d86ae228c226c81d2d8c64c687cd6dc4586d10d8e7e4e5b6706d429"))); + } } BOOST_AUTO_TEST_CASE(ripemd160_two_args) { - char const* sourceCode = R"( - (returnlll - (seq - (lit 0x20 "abcdefghijklmnopqrstuvwxyzABCDEF") - (lit 0x40 "GHIJKLMNOPQRSTUVWXYZ0123456789?!") - (ripemd160 0x20 0x40) - (return 0x00 0x20))) - )"; - compileAndRun(sourceCode); - BOOST_CHECK(callFallback() == encodeArgs( - fromHex("0x36c6b90a49e17d4c1e1b0e634ec74124d9b207da"))); + // "ripemd160" does not retain enough gas. + // Disabling for non-tangerineWhistle VMs. + if (dev::test::Options::get().evmVersion().canOverchargeGasForCall()) + { + char const* sourceCode = R"( + (returnlll + (seq + (lit 0x20 "abcdefghijklmnopqrstuvwxyzABCDEF") + (lit 0x40 "GHIJKLMNOPQRSTUVWXYZ0123456789?!") + (ripemd160 0x20 0x40) + (return 0x00 0x20))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callFallback() == encodeArgs( + fromHex("0x36c6b90a49e17d4c1e1b0e634ec74124d9b207da"))); + } } BOOST_AUTO_TEST_CASE(sha256_one_arg) { - char const* sourceCode = R"( - (returnlll - (seq - (sha256 0x6162636465666768696a6b6c6d6e6f707172737475767778797a414243444546) - (return 0x00 0x20))) - )"; - compileAndRun(sourceCode); - BOOST_CHECK(callFallback() == encodeArgs( - fromHex("0xcfd2f1fad75a1978da0a444883db7251414b139f31f5a04704c291fdb0e175e6"))); + // "sha256" does not retain enough gas. + // Disabling for non-tangerineWhistle VMs. + if (dev::test::Options::get().evmVersion().canOverchargeGasForCall()) + { + char const* sourceCode = R"( + (returnlll + (seq + (sha256 0x6162636465666768696a6b6c6d6e6f707172737475767778797a414243444546) + (return 0x00 0x20))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callFallback() == encodeArgs( + fromHex("0xcfd2f1fad75a1978da0a444883db7251414b139f31f5a04704c291fdb0e175e6"))); + } } BOOST_AUTO_TEST_CASE(ripemd160_one_arg) { - char const* sourceCode = R"( - (returnlll - (seq - (ripemd160 0x6162636465666768696a6b6c6d6e6f707172737475767778797a414243444546) - (return 0x00 0x20))) - )"; - compileAndRun(sourceCode); - BOOST_CHECK(callFallback() == encodeArgs( - fromHex("0xac5ab22e07b0fb80c69b6207902f725e2507e546"))); + // "ripemd160" does not retain enough gas. + // Disabling for non-tangerineWhistle VMs. + if (dev::test::Options::get().evmVersion().canOverchargeGasForCall()) + { + char const* sourceCode = R"( + (returnlll + (seq + (ripemd160 0x6162636465666768696a6b6c6d6e6f707172737475767778797a414243444546) + (return 0x00 0x20))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callFallback() == encodeArgs( + fromHex("0xac5ab22e07b0fb80c69b6207902f725e2507e546"))); + } } BOOST_AUTO_TEST_CASE(wei_szabo_finney_ether) diff --git a/test/liblll/ExecutionFramework.h b/test/liblll/ExecutionFramework.h index 58e1f0ad..ae5cd988 100644 --- a/test/liblll/ExecutionFramework.h +++ b/test/liblll/ExecutionFramework.h @@ -56,7 +56,7 @@ public: BOOST_REQUIRE(_libraryAddresses.empty()); std::vector<std::string> errors; - bytes bytecode = eth::compileLLL(_sourceCode, m_optimize, &errors); + bytes bytecode = eth::compileLLL(_sourceCode, dev::test::Options::get().evmVersion(), m_optimize, &errors); if (!errors.empty()) { for (auto const& error: errors) diff --git a/test/libsolidity/GasMeter.cpp b/test/libsolidity/GasMeter.cpp index 105a0398..fd2017f9 100644 --- a/test/libsolidity/GasMeter.cpp +++ b/test/libsolidity/GasMeter.cpp @@ -56,7 +56,7 @@ public: ASTNode const& sourceUnit = m_compiler.ast(""); BOOST_REQUIRE(items != nullptr); m_gasCosts = GasEstimator::breakToStatementLevel( - GasEstimator::structuralEstimation(*items, vector<ASTNode const*>({&sourceUnit})), + GasEstimator(dev::test::Options::get().evmVersion()).structuralEstimation(*items, vector<ASTNode const*>({&sourceUnit})), {&sourceUnit} ); } @@ -65,7 +65,7 @@ public: { compileAndRun(_sourceCode); auto state = make_shared<KnownState>(); - PathGasMeter meter(*m_compiler.assemblyItems(m_compiler.lastContractName())); + PathGasMeter meter(*m_compiler.assemblyItems(m_compiler.lastContractName()), dev::test::Options::get().evmVersion()); GasMeter::GasConsumption gas = meter.estimateMax(0, state); u256 bytecodeSize(m_compiler.runtimeObject(m_compiler.lastContractName()).bytecode.size()); // costs for deployment @@ -74,7 +74,7 @@ public: gas += gasForTransaction(m_compiler.object(m_compiler.lastContractName()).bytecode, true); BOOST_REQUIRE(!gas.isInfinite); - BOOST_CHECK(gas.value == m_gasUsed); + BOOST_CHECK_EQUAL(gas.value, m_gasUsed); } /// Compares the gas computed by PathGasMeter for the given signature (but unknown arguments) @@ -91,12 +91,12 @@ public: gas = max(gas, gasForTransaction(hash.asBytes() + arguments, false)); } - gas += GasEstimator::functionalEstimation( + gas += GasEstimator(dev::test::Options::get().evmVersion()).functionalEstimation( *m_compiler.runtimeAssemblyItems(m_compiler.lastContractName()), _sig ); BOOST_REQUIRE(!gas.isInfinite); - BOOST_CHECK(gas.value == m_gasUsed); + BOOST_CHECK_EQUAL(gas.value, m_gasUsed); } static GasMeter::GasConsumption gasForTransaction(bytes const& _data, bool _isCreation) |