aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libevmasm/Assembly.cpp4
-rw-r--r--libevmasm/Assembly.h5
-rw-r--r--libevmasm/ConstantOptimiser.cpp11
-rw-r--r--libevmasm/ConstantOptimiser.h4
-rw-r--r--libevmasm/GasMeter.cpp32
-rw-r--r--libevmasm/GasMeter.h44
-rw-r--r--libevmasm/PathGasMeter.cpp6
-rw-r--r--libevmasm/PathGasMeter.h8
-rw-r--r--liblll/Compiler.cpp17
-rw-r--r--liblll/Compiler.h9
-rw-r--r--libsolidity/codegen/CompilerContext.h2
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp4
-rw-r--r--libsolidity/codegen/ContractCompiler.h2
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp2
-rw-r--r--libsolidity/interface/CompilerStack.cpp9
-rw-r--r--libsolidity/interface/GasEstimator.cpp12
-rw-r--r--libsolidity/interface/GasEstimator.h22
-rw-r--r--lllc/main.cpp4
-rw-r--r--solc/CommandLineInterface.cpp13
-rw-r--r--solc/CommandLineInterface.h5
-rw-r--r--test/contracts/LLL_ENS.cpp2
-rw-r--r--test/contracts/LLL_ERC20.cpp2
-rw-r--r--test/fuzzer.cpp1
-rw-r--r--test/libevmasm/Optimiser.cpp4
-rw-r--r--test/liblll/Compiler.cpp17
-rw-r--r--test/liblll/EndToEndTest.cpp276
-rw-r--r--test/liblll/ExecutionFramework.h2
-rw-r--r--test/libsolidity/GasMeter.cpp10
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)