mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Use EVM version in gas meter and optimizer.
This commit is contained in:
parent
5a54cd5c70
commit
6ec4517929
@ -353,7 +353,7 @@ void Assembly::injectStart(AssemblyItem const& _i)
|
|||||||
m_items.insert(m_items.begin(), _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;
|
OptimiserSettings settings;
|
||||||
settings.isCreation = _isCreation;
|
settings.isCreation = _isCreation;
|
||||||
@ -365,6 +365,7 @@ Assembly& Assembly::optimise(bool _enable, bool _isCreation, size_t _runs)
|
|||||||
settings.runCSE = true;
|
settings.runCSE = true;
|
||||||
settings.runConstantOptimiser = true;
|
settings.runConstantOptimiser = true;
|
||||||
}
|
}
|
||||||
|
settings.evmVersion = _evmVersion;
|
||||||
settings.expectedExecutionsPerDeployment = _runs;
|
settings.expectedExecutionsPerDeployment = _runs;
|
||||||
optimise(settings);
|
optimise(settings);
|
||||||
return *this;
|
return *this;
|
||||||
@ -482,6 +483,7 @@ map<u256, u256> Assembly::optimiseInternal(
|
|||||||
ConstantOptimisationMethod::optimiseConstants(
|
ConstantOptimisationMethod::optimiseConstants(
|
||||||
_settings.isCreation,
|
_settings.isCreation,
|
||||||
_settings.isCreation ? 1 : _settings.expectedExecutionsPerDeployment,
|
_settings.isCreation ? 1 : _settings.expectedExecutionsPerDeployment,
|
||||||
|
_settings.evmVersion,
|
||||||
*this,
|
*this,
|
||||||
m_items
|
m_items
|
||||||
);
|
);
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#include <libevmasm/LinkerObject.h>
|
#include <libevmasm/LinkerObject.h>
|
||||||
#include <libevmasm/Exceptions.h>
|
#include <libevmasm/Exceptions.h>
|
||||||
|
|
||||||
|
#include <libsolidity/interface/EVMVersion.h>
|
||||||
|
|
||||||
#include <libdevcore/Common.h>
|
#include <libdevcore/Common.h>
|
||||||
#include <libdevcore/Assertions.h>
|
#include <libdevcore/Assertions.h>
|
||||||
#include <libdevcore/SHA3.h>
|
#include <libdevcore/SHA3.h>
|
||||||
@ -107,6 +109,7 @@ public:
|
|||||||
bool runDeduplicate = false;
|
bool runDeduplicate = false;
|
||||||
bool runCSE = false;
|
bool runCSE = false;
|
||||||
bool runConstantOptimiser = false;
|
bool runConstantOptimiser = false;
|
||||||
|
solidity::EVMVersion evmVersion;
|
||||||
/// This specifies an estimate on how often each opcode in this assembly will be executed,
|
/// 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.
|
/// i.e. use a small value to optimise for size and a large value to optimise for runtime gas usage.
|
||||||
size_t expectedExecutionsPerDeployment = 200;
|
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,
|
/// @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.
|
/// 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.
|
/// 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.
|
/// Create a text representation of the assembly.
|
||||||
std::string assemblyString(
|
std::string assemblyString(
|
||||||
|
@ -29,6 +29,7 @@ using namespace dev::eth;
|
|||||||
unsigned ConstantOptimisationMethod::optimiseConstants(
|
unsigned ConstantOptimisationMethod::optimiseConstants(
|
||||||
bool _isCreation,
|
bool _isCreation,
|
||||||
size_t _runs,
|
size_t _runs,
|
||||||
|
solidity::EVMVersion _evmVersion,
|
||||||
Assembly& _assembly,
|
Assembly& _assembly,
|
||||||
AssemblyItems& _items
|
AssemblyItems& _items
|
||||||
)
|
)
|
||||||
@ -48,6 +49,7 @@ unsigned ConstantOptimisationMethod::optimiseConstants(
|
|||||||
params.multiplicity = it.second;
|
params.multiplicity = it.second;
|
||||||
params.isCreation = _isCreation;
|
params.isCreation = _isCreation;
|
||||||
params.runs = _runs;
|
params.runs = _runs;
|
||||||
|
params.evmVersion = _evmVersion;
|
||||||
LiteralMethod lit(params, item.data());
|
LiteralMethod lit(params, item.data());
|
||||||
bigint literalGas = lit.gasNeeded();
|
bigint literalGas = lit.gasNeeded();
|
||||||
CodeCopyMethod copy(params, item.data());
|
CodeCopyMethod copy(params, item.data());
|
||||||
@ -80,7 +82,12 @@ bigint ConstantOptimisationMethod::simpleRunGas(AssemblyItems const& _items)
|
|||||||
if (item.type() == Push)
|
if (item.type() == Push)
|
||||||
gas += GasMeter::runGas(Instruction::PUSH1);
|
gas += GasMeter::runGas(Instruction::PUSH1);
|
||||||
else if (item.type() == Operation)
|
else if (item.type() == Operation)
|
||||||
|
{
|
||||||
|
if (item.instruction() == Instruction::EXP)
|
||||||
|
gas += GasCosts::expGas;
|
||||||
|
else
|
||||||
gas += GasMeter::runGas(item.instruction());
|
gas += GasMeter::runGas(item.instruction());
|
||||||
|
}
|
||||||
return gas;
|
return gas;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,7 +293,7 @@ bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine) const
|
|||||||
{
|
{
|
||||||
size_t numExps = count(_routine.begin(), _routine.end(), Instruction::EXP);
|
size_t numExps = count(_routine.begin(), _routine.end(), Instruction::EXP);
|
||||||
return combineGas(
|
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.
|
// Data gas for routine: Some bytes are zero, but we ignore them.
|
||||||
bytesRequired(_routine) * (m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas),
|
bytesRequired(_routine) * (m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas),
|
||||||
0
|
0
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
|
|
||||||
#include <libevmasm/Exceptions.h>
|
#include <libevmasm/Exceptions.h>
|
||||||
|
|
||||||
|
#include <libsolidity/interface/EVMVersion.h>
|
||||||
|
|
||||||
#include <libdevcore/Assertions.h>
|
#include <libdevcore/Assertions.h>
|
||||||
#include <libdevcore/CommonData.h>
|
#include <libdevcore/CommonData.h>
|
||||||
#include <libdevcore/CommonIO.h>
|
#include <libdevcore/CommonIO.h>
|
||||||
@ -50,6 +52,7 @@ public:
|
|||||||
static unsigned optimiseConstants(
|
static unsigned optimiseConstants(
|
||||||
bool _isCreation,
|
bool _isCreation,
|
||||||
size_t _runs,
|
size_t _runs,
|
||||||
|
solidity::EVMVersion _evmVersion,
|
||||||
Assembly& _assembly,
|
Assembly& _assembly,
|
||||||
AssemblyItems& _items
|
AssemblyItems& _items
|
||||||
);
|
);
|
||||||
@ -59,6 +62,7 @@ public:
|
|||||||
bool isCreation; ///< Whether this is called during contract creation or runtime.
|
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 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.
|
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):
|
explicit ConstantOptimisationMethod(Params const& _params, u256 const& _value):
|
||||||
|
@ -61,7 +61,6 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
|||||||
case Operation:
|
case Operation:
|
||||||
{
|
{
|
||||||
ExpressionClasses& classes = m_state->expressionClasses();
|
ExpressionClasses& classes = m_state->expressionClasses();
|
||||||
gas = runGas(_item.instruction());
|
|
||||||
switch (_item.instruction())
|
switch (_item.instruction())
|
||||||
{
|
{
|
||||||
case Instruction::SSTORE:
|
case Instruction::SSTORE:
|
||||||
@ -72,26 +71,29 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
|||||||
m_state->storageContent().count(slot) &&
|
m_state->storageContent().count(slot) &&
|
||||||
classes.knownNonZero(m_state->storageContent().at(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
|
else
|
||||||
gas += GasCosts::sstoreSetGas;
|
gas = GasCosts::sstoreSetGas;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Instruction::SLOAD:
|
case Instruction::SLOAD:
|
||||||
gas += GasCosts::sloadGas;
|
gas = GasCosts::sloadGas(m_evmVersion);
|
||||||
break;
|
break;
|
||||||
case Instruction::RETURN:
|
case Instruction::RETURN:
|
||||||
case Instruction::REVERT:
|
case Instruction::REVERT:
|
||||||
|
gas = runGas(_item.instruction());
|
||||||
gas += memoryGas(0, -1);
|
gas += memoryGas(0, -1);
|
||||||
break;
|
break;
|
||||||
case Instruction::MLOAD:
|
case Instruction::MLOAD:
|
||||||
case Instruction::MSTORE:
|
case Instruction::MSTORE:
|
||||||
|
gas = runGas(_item.instruction());
|
||||||
gas += memoryGas(classes.find(Instruction::ADD, {
|
gas += memoryGas(classes.find(Instruction::ADD, {
|
||||||
m_state->relativeStackElement(0),
|
m_state->relativeStackElement(0),
|
||||||
classes.find(AssemblyItem(32))
|
classes.find(AssemblyItem(32))
|
||||||
}));
|
}));
|
||||||
break;
|
break;
|
||||||
case Instruction::MSTORE8:
|
case Instruction::MSTORE8:
|
||||||
|
gas = runGas(_item.instruction());
|
||||||
gas += memoryGas(classes.find(Instruction::ADD, {
|
gas += memoryGas(classes.find(Instruction::ADD, {
|
||||||
m_state->relativeStackElement(0),
|
m_state->relativeStackElement(0),
|
||||||
classes.find(AssemblyItem(1))
|
classes.find(AssemblyItem(1))
|
||||||
@ -105,10 +107,15 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
|||||||
case Instruction::CALLDATACOPY:
|
case Instruction::CALLDATACOPY:
|
||||||
case Instruction::CODECOPY:
|
case Instruction::CODECOPY:
|
||||||
case Instruction::RETURNDATACOPY:
|
case Instruction::RETURNDATACOPY:
|
||||||
|
gas = runGas(_item.instruction());
|
||||||
gas += memoryGas(0, -2);
|
gas += memoryGas(0, -2);
|
||||||
gas += wordGas(GasCosts::copyGas, m_state->relativeStackElement(-2));
|
gas += wordGas(GasCosts::copyGas, m_state->relativeStackElement(-2));
|
||||||
break;
|
break;
|
||||||
|
case Instruction::EXTCODESIZE:
|
||||||
|
gas = GasCosts::extCodeGas(m_evmVersion);
|
||||||
|
break;
|
||||||
case Instruction::EXTCODECOPY:
|
case Instruction::EXTCODECOPY:
|
||||||
|
gas = GasCosts::extCodeGas(m_evmVersion);
|
||||||
gas += memoryGas(-1, -3);
|
gas += memoryGas(-1, -3);
|
||||||
gas += wordGas(GasCosts::copyGas, m_state->relativeStackElement(-3));
|
gas += wordGas(GasCosts::copyGas, m_state->relativeStackElement(-3));
|
||||||
break;
|
break;
|
||||||
@ -137,7 +144,7 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
|||||||
gas = GasConsumption::infinite();
|
gas = GasConsumption::infinite();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gas = GasCosts::callGas;
|
gas = GasCosts::callGas(m_evmVersion);
|
||||||
if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(0)))
|
if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(0)))
|
||||||
gas += (*value);
|
gas += (*value);
|
||||||
else
|
else
|
||||||
@ -155,7 +162,7 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Instruction::SELFDESTRUCT:
|
case Instruction::SELFDESTRUCT:
|
||||||
gas = GasCosts::selfdestructGas;
|
gas = GasCosts::selfdestructGas(m_evmVersion);
|
||||||
gas += GasCosts::callNewAccountGas; // We very rarely know whether the address exists.
|
gas += GasCosts::callNewAccountGas; // We very rarely know whether the address exists.
|
||||||
break;
|
break;
|
||||||
case Instruction::CREATE:
|
case Instruction::CREATE:
|
||||||
@ -172,11 +179,15 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
|||||||
case Instruction::EXP:
|
case Instruction::EXP:
|
||||||
gas = GasCosts::expGas;
|
gas = GasCosts::expGas;
|
||||||
if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1)))
|
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
|
else
|
||||||
gas += GasCosts::expByteGas * 32;
|
gas += GasCosts::expByteGas(m_evmVersion) * 32;
|
||||||
|
break;
|
||||||
|
case Instruction::BALANCE:
|
||||||
|
gas = GasCosts::balanceGas(m_evmVersion);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
gas = runGas(_item.instruction());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -241,12 +252,9 @@ unsigned GasMeter::runGas(Instruction _instruction)
|
|||||||
case Tier::Mid: return GasCosts::tier4Gas;
|
case Tier::Mid: return GasCosts::tier4Gas;
|
||||||
case Tier::High: return GasCosts::tier5Gas;
|
case Tier::High: return GasCosts::tier5Gas;
|
||||||
case Tier::Ext: return GasCosts::tier6Gas;
|
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;
|
default: break;
|
||||||
}
|
}
|
||||||
assertThrow(false, OptimizerException, "Invalid gas tier.");
|
assertThrow(false, OptimizerException, "Invalid gas tier for instruction " + instructionInfo(_instruction).name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,11 +21,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ostream>
|
|
||||||
#include <tuple>
|
|
||||||
#include <libevmasm/ExpressionClasses.h>
|
#include <libevmasm/ExpressionClasses.h>
|
||||||
#include <libevmasm/AssemblyItem.h>
|
#include <libevmasm/AssemblyItem.h>
|
||||||
|
|
||||||
|
#include <libsolidity/interface/EVMVersion.h>
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
namespace dev
|
namespace dev
|
||||||
{
|
{
|
||||||
namespace eth
|
namespace eth
|
||||||
@ -44,13 +47,25 @@ namespace GasCosts
|
|||||||
static unsigned const tier5Gas = 10;
|
static unsigned const tier5Gas = 10;
|
||||||
static unsigned const tier6Gas = 20;
|
static unsigned const tier6Gas = 20;
|
||||||
static unsigned const tier7Gas = 0;
|
static unsigned const tier7Gas = 0;
|
||||||
static unsigned const extCodeGas = 700;
|
inline unsigned extCodeGas(EVMVersion _evmVersion)
|
||||||
static unsigned const balanceGas = 400;
|
{
|
||||||
|
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 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 keccak256Gas = 30;
|
||||||
static unsigned const keccak256WordGas = 6;
|
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 sstoreSetGas = 20000;
|
||||||
static unsigned const sstoreResetGas = 5000;
|
static unsigned const sstoreResetGas = 5000;
|
||||||
static unsigned const sstoreRefundGas = 15000;
|
static unsigned const sstoreRefundGas = 15000;
|
||||||
@ -59,11 +74,17 @@ namespace GasCosts
|
|||||||
static unsigned const logDataGas = 8;
|
static unsigned const logDataGas = 8;
|
||||||
static unsigned const logTopicGas = 375;
|
static unsigned const logTopicGas = 375;
|
||||||
static unsigned const createGas = 32000;
|
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 callStipend = 2300;
|
||||||
static unsigned const callValueTransferGas = 9000;
|
static unsigned const callValueTransferGas = 9000;
|
||||||
static unsigned const callNewAccountGas = 25000;
|
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 selfdestructRefundGas = 24000;
|
||||||
static unsigned const memoryGas = 3;
|
static unsigned const memoryGas = 3;
|
||||||
static unsigned const quadCoeffDiv = 512;
|
static unsigned const quadCoeffDiv = 512;
|
||||||
@ -100,8 +121,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Constructs a new gas meter given the current state.
|
/// Constructs a new gas meter given the current state.
|
||||||
explicit GasMeter(std::shared_ptr<KnownState> const& _state, u256 const& _largestMemoryAccess = 0):
|
GasMeter(std::shared_ptr<KnownState> const& _state, solidity::EVMVersion _evmVersion, u256 const& _largestMemoryAccess = 0):
|
||||||
m_state(_state), m_largestMemoryAccess(_largestMemoryAccess) {}
|
m_state(_state), m_evmVersion(_evmVersion), m_largestMemoryAccess(_largestMemoryAccess) {}
|
||||||
|
|
||||||
/// @returns an upper bound on the gas consumed by the given instruction and updates
|
/// @returns an upper bound on the gas consumed by the given instruction and updates
|
||||||
/// the state.
|
/// the state.
|
||||||
@ -110,6 +131,8 @@ public:
|
|||||||
|
|
||||||
u256 const& largestMemoryAccess() const { return m_largestMemoryAccess; }
|
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);
|
static unsigned runGas(Instruction _instruction);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -123,6 +146,7 @@ private:
|
|||||||
GasConsumption memoryGas(int _stackPosOffset, int _stackPosSize);
|
GasConsumption memoryGas(int _stackPosOffset, int _stackPosSize);
|
||||||
|
|
||||||
std::shared_ptr<KnownState> m_state;
|
std::shared_ptr<KnownState> m_state;
|
||||||
|
EVMVersion m_evmVersion;
|
||||||
/// Largest point where memory was accessed since the creation of this object.
|
/// Largest point where memory was accessed since the creation of this object.
|
||||||
u256 m_largestMemoryAccess;
|
u256 m_largestMemoryAccess;
|
||||||
};
|
};
|
||||||
|
@ -27,8 +27,8 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace dev::eth;
|
using namespace dev::eth;
|
||||||
|
|
||||||
PathGasMeter::PathGasMeter(AssemblyItems const& _items):
|
PathGasMeter::PathGasMeter(AssemblyItems const& _items, solidity::EVMVersion _evmVersion):
|
||||||
m_items(_items)
|
m_items(_items), m_evmVersion(_evmVersion)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < m_items.size(); ++i)
|
for (size_t i = 0; i < m_items.size(); ++i)
|
||||||
if (m_items[i].type() == Tag)
|
if (m_items[i].type() == Tag)
|
||||||
@ -59,7 +59,7 @@ GasMeter::GasConsumption PathGasMeter::handleQueueItem()
|
|||||||
m_queue.pop_back();
|
m_queue.pop_back();
|
||||||
|
|
||||||
shared_ptr<KnownState> state = path->state;
|
shared_ptr<KnownState> state = path->state;
|
||||||
GasMeter meter(state, path->largestMemoryAccess);
|
GasMeter meter(state, m_evmVersion, path->largestMemoryAccess);
|
||||||
ExpressionClasses& classes = state->expressionClasses();
|
ExpressionClasses& classes = state->expressionClasses();
|
||||||
GasMeter::GasConsumption gas = path->gas;
|
GasMeter::GasConsumption gas = path->gas;
|
||||||
size_t index = path->index;
|
size_t index = path->index;
|
||||||
|
@ -21,10 +21,13 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <libevmasm/GasMeter.h>
|
||||||
|
|
||||||
|
#include <libsolidity/interface/EVMVersion.h>
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <libevmasm/GasMeter.h>
|
|
||||||
|
|
||||||
namespace dev
|
namespace dev
|
||||||
{
|
{
|
||||||
@ -50,7 +53,7 @@ struct GasPath
|
|||||||
class PathGasMeter
|
class PathGasMeter
|
||||||
{
|
{
|
||||||
public:
|
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);
|
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::vector<std::unique_ptr<GasPath>> m_queue;
|
||||||
std::map<u256, size_t> m_tagPositions;
|
std::map<u256, size_t> m_tagPositions;
|
||||||
AssemblyItems const& m_items;
|
AssemblyItems const& m_items;
|
||||||
|
solidity::EVMVersion m_evmVersion;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,17 +19,16 @@
|
|||||||
* @date 2014
|
* @date 2014
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Compiler.h"
|
#include <liblll/Compiler.h>
|
||||||
#include "Parser.h"
|
#include <liblll/Parser.h>
|
||||||
#include "CompilerState.h"
|
#include <liblll/CompilerState.h>
|
||||||
#include "CodeFragment.h"
|
#include <liblll/CodeFragment.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace dev::eth;
|
using namespace dev::eth;
|
||||||
|
|
||||||
|
bytes dev::eth::compileLLL(string const& _src, dev::solidity::EVMVersion _evmVersion, bool _opt, std::vector<std::string>* _errors, dev::eth::ReadCallback const& _readFile)
|
||||||
bytes dev::eth::compileLLL(string const& _src, bool _opt, vector<string>* _errors, ReadCallback const& _readFile)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -37,7 +36,7 @@ bytes dev::eth::compileLLL(string const& _src, bool _opt, vector<string>* _error
|
|||||||
cs.populateStandard();
|
cs.populateStandard();
|
||||||
auto assembly = CodeFragment::compile(_src, cs, _readFile).assembly(cs);
|
auto assembly = CodeFragment::compile(_src, cs, _readFile).assembly(cs);
|
||||||
if (_opt)
|
if (_opt)
|
||||||
assembly = assembly.optimise(true);
|
assembly = assembly.optimise(true, _evmVersion);
|
||||||
bytes ret = assembly.assemble().bytecode;
|
bytes ret = assembly.assemble().bytecode;
|
||||||
for (auto i: cs.treesToKill)
|
for (auto i: cs.treesToKill)
|
||||||
killBigints(i);
|
killBigints(i);
|
||||||
@ -67,7 +66,7 @@ bytes dev::eth::compileLLL(string const& _src, bool _opt, vector<string>* _error
|
|||||||
return bytes();
|
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
|
try
|
||||||
{
|
{
|
||||||
@ -75,7 +74,7 @@ std::string dev::eth::compileLLLToAsm(std::string const& _src, bool _opt, std::v
|
|||||||
cs.populateStandard();
|
cs.populateStandard();
|
||||||
auto assembly = CodeFragment::compile(_src, cs, _readFile).assembly(cs);
|
auto assembly = CodeFragment::compile(_src, cs, _readFile).assembly(cs);
|
||||||
if (_opt)
|
if (_opt)
|
||||||
assembly = assembly.optimise(true);
|
assembly = assembly.optimise(true, _evmVersion);
|
||||||
string ret = assembly.assemblyString();
|
string ret = assembly.assemblyString();
|
||||||
for (auto i: cs.treesToKill)
|
for (auto i: cs.treesToKill)
|
||||||
killBigints(i);
|
killBigints(i);
|
||||||
|
@ -21,9 +21,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <libdevcore/Common.h>
|
||||||
|
|
||||||
|
#include <libsolidity/interface/EVMVersion.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <libdevcore/Common.h>
|
|
||||||
|
|
||||||
namespace dev
|
namespace dev
|
||||||
{
|
{
|
||||||
@ -33,8 +36,8 @@ namespace eth
|
|||||||
using ReadCallback = std::function<std::string(std::string const&)>;
|
using ReadCallback = std::function<std::string(std::string const&)>;
|
||||||
|
|
||||||
std::string parseLLL(std::string const& _src);
|
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());
|
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, 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());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,7 +209,7 @@ public:
|
|||||||
void appendAuxiliaryData(bytes const& _data) { m_asm->appendAuxiliaryDataToEnd(_data); }
|
void appendAuxiliaryData(bytes const& _data) { m_asm->appendAuxiliaryDataToEnd(_data); }
|
||||||
|
|
||||||
/// Run optimisation step.
|
/// 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.
|
/// @returns the runtime context if in creation mode and runtime context is set, nullptr otherwise.
|
||||||
CompilerContext* runtimeContext() { return m_runtimeContext; }
|
CompilerContext* runtimeContext() { return m_runtimeContext; }
|
||||||
|
@ -1059,7 +1059,7 @@ void ContractCompiler::compileExpression(Expression const& _expression, TypePoin
|
|||||||
CompilerUtils(m_context).convertType(*_expression.annotation().type, *_targetType);
|
CompilerUtils(m_context).convertType(*_expression.annotation().type, *_targetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
eth::AssemblyPointer ContractCompiler::cloneRuntime()
|
eth::AssemblyPointer ContractCompiler::cloneRuntime() const
|
||||||
{
|
{
|
||||||
eth::Assembly a;
|
eth::Assembly a;
|
||||||
a << Instruction::CALLDATASIZE;
|
a << Instruction::CALLDATASIZE;
|
||||||
@ -1070,7 +1070,7 @@ eth::AssemblyPointer ContractCompiler::cloneRuntime()
|
|||||||
// this is the address which has to be substituted by the linker.
|
// this is the address which has to be substituted by the linker.
|
||||||
//@todo implement as special "marker" AssemblyItem.
|
//@todo implement as special "marker" AssemblyItem.
|
||||||
a << u256("0xcafecafecafecafecafecafecafecafecafecafe");
|
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;
|
a << Instruction::DELEGATECALL;
|
||||||
//Propagate error condition (if DELEGATECALL pushes 0 on stack).
|
//Propagate error condition (if DELEGATECALL pushes 0 on stack).
|
||||||
a << Instruction::ISZERO;
|
a << Instruction::ISZERO;
|
||||||
|
@ -125,7 +125,7 @@ private:
|
|||||||
void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer());
|
void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer());
|
||||||
|
|
||||||
/// @returns the runtime assembly for clone contracts.
|
/// @returns the runtime assembly for clone contracts.
|
||||||
static eth::AssemblyPointer cloneRuntime();
|
eth::AssemblyPointer cloneRuntime() const;
|
||||||
|
|
||||||
bool const m_optimise;
|
bool const m_optimise;
|
||||||
/// Pointer to the runtime compiler in case this is a creation compiler.
|
/// Pointer to the runtime compiler in case this is a creation compiler.
|
||||||
|
@ -1756,7 +1756,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
{
|
{
|
||||||
// send all gas except the amount needed to execute "SUB" and "CALL"
|
// 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.
|
// @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())
|
if (_functionType.valueSet())
|
||||||
gasNeededByCaller += eth::GasCosts::callValueTransferGas;
|
gasNeededByCaller += eth::GasCosts::callValueTransferGas;
|
||||||
if (!existenceChecked)
|
if (!existenceChecked)
|
||||||
|
@ -959,11 +959,12 @@ Json::Value CompilerStack::gasEstimates(string const& _contractName) const
|
|||||||
return Json::Value();
|
return Json::Value();
|
||||||
|
|
||||||
using Gas = GasEstimator::GasConsumption;
|
using Gas = GasEstimator::GasConsumption;
|
||||||
|
GasEstimator gasEstimator(m_evmVersion);
|
||||||
Json::Value output(Json::objectValue);
|
Json::Value output(Json::objectValue);
|
||||||
|
|
||||||
if (eth::AssemblyItems const* items = assemblyItems(_contractName))
|
if (eth::AssemblyItems const* items = assemblyItems(_contractName))
|
||||||
{
|
{
|
||||||
Gas executionGas = GasEstimator::functionalEstimation(*items);
|
Gas executionGas = gasEstimator.functionalEstimation(*items);
|
||||||
u256 bytecodeSize(runtimeObject(_contractName).bytecode.size());
|
u256 bytecodeSize(runtimeObject(_contractName).bytecode.size());
|
||||||
Gas codeDepositGas = bytecodeSize * eth::GasCosts::createDataGas;
|
Gas codeDepositGas = bytecodeSize * eth::GasCosts::createDataGas;
|
||||||
|
|
||||||
@ -984,14 +985,14 @@ Json::Value CompilerStack::gasEstimates(string const& _contractName) const
|
|||||||
for (auto it: contract.interfaceFunctions())
|
for (auto it: contract.interfaceFunctions())
|
||||||
{
|
{
|
||||||
string sig = it.second->externalSignature();
|
string sig = it.second->externalSignature();
|
||||||
externalFunctions[sig] = gasToJson(GasEstimator::functionalEstimation(*items, sig));
|
externalFunctions[sig] = gasToJson(gasEstimator.functionalEstimation(*items, sig));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contract.fallbackFunction())
|
if (contract.fallbackFunction())
|
||||||
/// This needs to be set to an invalid signature in order to trigger the fallback,
|
/// 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.
|
/// without the shortcut (of CALLDATSIZE == 0), and therefore to receive the upper bound.
|
||||||
/// An empty string ("") would work to trigger the shortcut only.
|
/// 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())
|
if (!externalFunctions.empty())
|
||||||
output["external"] = externalFunctions;
|
output["external"] = externalFunctions;
|
||||||
@ -1007,7 +1008,7 @@ Json::Value CompilerStack::gasEstimates(string const& _contractName) const
|
|||||||
size_t entry = functionEntryPoint(_contractName, *it);
|
size_t entry = functionEntryPoint(_contractName, *it);
|
||||||
GasEstimator::GasConsumption gas = GasEstimator::GasConsumption::infinite();
|
GasEstimator::GasConsumption gas = GasEstimator::GasConsumption::infinite();
|
||||||
if (entry > 0)
|
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()
|
/// TODO: This could move into a method shared with externalSignature()
|
||||||
FunctionType type(*it);
|
FunctionType type(*it);
|
||||||
|
@ -40,7 +40,7 @@ using namespace dev::solidity;
|
|||||||
GasEstimator::ASTGasConsumptionSelfAccumulated GasEstimator::structuralEstimation(
|
GasEstimator::ASTGasConsumptionSelfAccumulated GasEstimator::structuralEstimation(
|
||||||
AssemblyItems const& _items,
|
AssemblyItems const& _items,
|
||||||
vector<ASTNode const*> const& _ast
|
vector<ASTNode const*> const& _ast
|
||||||
)
|
) const
|
||||||
{
|
{
|
||||||
solAssert(std::count(_ast.begin(), _ast.end(), nullptr) == 0, "");
|
solAssert(std::count(_ast.begin(), _ast.end(), nullptr) == 0, "");
|
||||||
map<SourceLocation, GasConsumption> particularCosts;
|
map<SourceLocation, GasConsumption> particularCosts;
|
||||||
@ -49,7 +49,7 @@ GasEstimator::ASTGasConsumptionSelfAccumulated GasEstimator::structuralEstimatio
|
|||||||
for (BasicBlock const& block: cfg.optimisedBlocks())
|
for (BasicBlock const& block: cfg.optimisedBlocks())
|
||||||
{
|
{
|
||||||
solAssert(!!block.startState, "");
|
solAssert(!!block.startState, "");
|
||||||
GasMeter meter(block.startState->copy());
|
GasMeter meter(block.startState->copy(), m_evmVersion);
|
||||||
auto const end = _items.begin() + block.end;
|
auto const end = _items.begin() + block.end;
|
||||||
for (auto iter = _items.begin() + block.begin; iter != end; ++iter)
|
for (auto iter = _items.begin() + block.begin; iter != end; ++iter)
|
||||||
particularCosts[iter->location()] += meter.estimateMax(*iter);
|
particularCosts[iter->location()] += meter.estimateMax(*iter);
|
||||||
@ -127,7 +127,7 @@ map<ASTNode const*, GasMeter::GasConsumption> GasEstimator::breakToStatementLeve
|
|||||||
GasEstimator::GasConsumption GasEstimator::functionalEstimation(
|
GasEstimator::GasConsumption GasEstimator::functionalEstimation(
|
||||||
AssemblyItems const& _items,
|
AssemblyItems const& _items,
|
||||||
string const& _signature
|
string const& _signature
|
||||||
)
|
) const
|
||||||
{
|
{
|
||||||
auto state = make_shared<KnownState>();
|
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);
|
return meter.estimateMax(0, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +152,7 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation(
|
|||||||
AssemblyItems const& _items,
|
AssemblyItems const& _items,
|
||||||
size_t const& _offset,
|
size_t const& _offset,
|
||||||
FunctionDefinition const& _function
|
FunctionDefinition const& _function
|
||||||
)
|
) const
|
||||||
{
|
{
|
||||||
auto state = make_shared<KnownState>();
|
auto state = make_shared<KnownState>();
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation(
|
|||||||
if (parametersSize > 0)
|
if (parametersSize > 0)
|
||||||
state->feedItem(swapInstruction(parametersSize));
|
state->feedItem(swapInstruction(parametersSize));
|
||||||
|
|
||||||
return PathGasMeter(_items).estimateMax(_offset, state);
|
return PathGasMeter(_items, m_evmVersion).estimateMax(_offset, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
set<ASTNode const*> GasEstimator::finestNodesAtLocation(
|
set<ASTNode const*> GasEstimator::finestNodesAtLocation(
|
||||||
|
@ -22,11 +22,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <libsolidity/interface/EVMVersion.h>
|
||||||
|
|
||||||
|
#include <libevmasm/GasMeter.h>
|
||||||
|
#include <libevmasm/Assembly.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <libevmasm/GasMeter.h>
|
|
||||||
#include <libevmasm/Assembly.h>
|
|
||||||
|
|
||||||
namespace dev
|
namespace dev
|
||||||
{
|
{
|
||||||
@ -44,13 +47,15 @@ public:
|
|||||||
using ASTGasConsumptionSelfAccumulated =
|
using ASTGasConsumptionSelfAccumulated =
|
||||||
std::map<ASTNode const*, std::array<GasConsumption, 2>>;
|
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
|
/// Estimates the gas consumption for every assembly item in the given assembly and stores
|
||||||
/// it by source location.
|
/// it by source location.
|
||||||
/// @returns a mapping from each AST node to a pair of its particular and syntactically accumulated gas costs.
|
/// @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,
|
eth::AssemblyItems const& _items,
|
||||||
std::vector<ASTNode const*> const& _ast
|
std::vector<ASTNode const*> const& _ast
|
||||||
);
|
) const;
|
||||||
/// @returns a mapping from nodes with non-overlapping source locations to gas consumptions such that
|
/// @returns a mapping from nodes with non-overlapping source locations to gas consumptions such that
|
||||||
/// the following source locations are part of the mapping:
|
/// the following source locations are part of the mapping:
|
||||||
/// 1. source locations of statements that do not contain other statements
|
/// 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
|
/// @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.
|
/// given signature. If no signature is given, estimates the maximum gas usage.
|
||||||
static GasConsumption functionalEstimation(
|
GasConsumption functionalEstimation(
|
||||||
eth::AssemblyItems const& _items,
|
eth::AssemblyItems const& _items,
|
||||||
std::string const& _signature = ""
|
std::string const& _signature = ""
|
||||||
);
|
) const;
|
||||||
|
|
||||||
/// @returns the estimated gas consumption by the given function which starts at the given
|
/// @returns the estimated gas consumption by the given function which starts at the given
|
||||||
/// offset into the list of assembly items.
|
/// offset into the list of assembly items.
|
||||||
/// @note this does not work correctly for recursive functions.
|
/// @note this does not work correctly for recursive functions.
|
||||||
static GasConsumption functionalEstimation(
|
GasConsumption functionalEstimation(
|
||||||
eth::AssemblyItems const& _items,
|
eth::AssemblyItems const& _items,
|
||||||
size_t const& _offset,
|
size_t const& _offset,
|
||||||
FunctionDefinition const& _function
|
FunctionDefinition const& _function
|
||||||
);
|
) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// @returns the set of AST nodes which are the finest nodes at their location.
|
/// @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);
|
static std::set<ASTNode const*> finestNodesAtLocation(std::vector<ASTNode const*> const& _roots);
|
||||||
|
EVMVersion m_evmVersion;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
else if (mode == Binary || mode == Hex)
|
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)
|
if (mode == Hex)
|
||||||
cout << toHex(bs) << endl;
|
cout << toHex(bs) << endl;
|
||||||
else if (mode == Binary)
|
else if (mode == Binary)
|
||||||
@ -145,7 +145,7 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
else if (mode == Assembly)
|
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)
|
for (auto const& i: errors)
|
||||||
|
@ -748,7 +748,6 @@ bool CommandLineInterface::processInput()
|
|||||||
if (!parseLibraryOption(library))
|
if (!parseLibraryOption(library))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
EVMVersion evmVersion;
|
|
||||||
if (m_args.count(g_strEVMVersion))
|
if (m_args.count(g_strEVMVersion))
|
||||||
{
|
{
|
||||||
string versionOptionStr = m_args[g_strEVMVersion].as<string>();
|
string versionOptionStr = m_args[g_strEVMVersion].as<string>();
|
||||||
@ -758,7 +757,7 @@ bool CommandLineInterface::processInput()
|
|||||||
cerr << "Invalid option for --evm-version: " << versionOptionStr << endl;
|
cerr << "Invalid option for --evm-version: " << versionOptionStr << endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
evmVersion = *versionOption;
|
m_evmVersion = *versionOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_args.count(g_argAssemble) || m_args.count(g_argStrictAssembly) || m_args.count(g_argJulia))
|
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 false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return assemble(evmVersion, inputLanguage, targetMachine);
|
return assemble(inputLanguage, targetMachine);
|
||||||
}
|
}
|
||||||
if (m_args.count(g_argLink))
|
if (m_args.count(g_argLink))
|
||||||
{
|
{
|
||||||
@ -808,8 +807,7 @@ bool CommandLineInterface::processInput()
|
|||||||
m_compiler->addSource(sourceCode.first, sourceCode.second);
|
m_compiler->addSource(sourceCode.first, sourceCode.second);
|
||||||
if (m_args.count(g_argLibraries))
|
if (m_args.count(g_argLibraries))
|
||||||
m_compiler->setLibraries(m_libraries);
|
m_compiler->setLibraries(m_libraries);
|
||||||
if (m_args.count(g_strEVMVersion))
|
m_compiler->setEVMVersion(m_evmVersion);
|
||||||
m_compiler->setEVMVersion(evmVersion);
|
|
||||||
// TODO: Perhaps we should not compile unless requested
|
// TODO: Perhaps we should not compile unless requested
|
||||||
bool optimize = m_args.count(g_argOptimize) > 0;
|
bool optimize = m_args.count(g_argOptimize) > 0;
|
||||||
unsigned runs = m_args[g_argOptimizeRuns].as<unsigned>();
|
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?
|
// FIXME: shouldn't this be done for every contract?
|
||||||
if (m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()))
|
if (m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()))
|
||||||
gasCosts = GasEstimator::breakToStatementLevel(
|
gasCosts = GasEstimator::breakToStatementLevel(
|
||||||
GasEstimator::structuralEstimation(*m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()), asts),
|
GasEstimator(m_evmVersion).structuralEstimation(*m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()), asts),
|
||||||
asts
|
asts
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1081,7 +1079,6 @@ void CommandLineInterface::writeLinkedFiles()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CommandLineInterface::assemble(
|
bool CommandLineInterface::assemble(
|
||||||
EVMVersion _evmVersion,
|
|
||||||
AssemblyStack::Language _language,
|
AssemblyStack::Language _language,
|
||||||
AssemblyStack::Machine _targetMachine
|
AssemblyStack::Machine _targetMachine
|
||||||
)
|
)
|
||||||
@ -1090,7 +1087,7 @@ bool CommandLineInterface::assemble(
|
|||||||
map<string, AssemblyStack> assemblyStacks;
|
map<string, AssemblyStack> assemblyStacks;
|
||||||
for (auto const& src: m_sourceCodes)
|
for (auto const& src: m_sourceCodes)
|
||||||
{
|
{
|
||||||
auto& stack = assemblyStacks[src.first] = AssemblyStack(_evmVersion, _language);
|
auto& stack = assemblyStacks[src.first] = AssemblyStack(m_evmVersion, _language);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!stack.parseAndAnalyze(src.first, src.second))
|
if (!stack.parseAndAnalyze(src.first, src.second))
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <libsolidity/interface/CompilerStack.h>
|
#include <libsolidity/interface/CompilerStack.h>
|
||||||
#include <libsolidity/interface/AssemblyStack.h>
|
#include <libsolidity/interface/AssemblyStack.h>
|
||||||
|
#include <libsolidity/interface/EVMVersion.h>
|
||||||
|
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
@ -54,7 +55,7 @@ private:
|
|||||||
bool link();
|
bool link();
|
||||||
void writeLinkedFiles();
|
void writeLinkedFiles();
|
||||||
|
|
||||||
bool assemble(EVMVersion _evmVersion, AssemblyStack::Language _language, AssemblyStack::Machine _targetMachine);
|
bool assemble(AssemblyStack::Language _language, AssemblyStack::Machine _targetMachine);
|
||||||
|
|
||||||
void outputCompilationResults();
|
void outputCompilationResults();
|
||||||
|
|
||||||
@ -102,6 +103,8 @@ private:
|
|||||||
std::map<std::string, h160> m_libraries;
|
std::map<std::string, h160> m_libraries;
|
||||||
/// Solidity compiler stack
|
/// Solidity compiler stack
|
||||||
std::unique_ptr<dev::solidity::CompilerStack> m_compiler;
|
std::unique_ptr<dev::solidity::CompilerStack> m_compiler;
|
||||||
|
/// EVM version to use
|
||||||
|
EVMVersion m_evmVersion;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -345,7 +345,7 @@ protected:
|
|||||||
if (!s_compiledEns)
|
if (!s_compiledEns)
|
||||||
{
|
{
|
||||||
vector<string> errors;
|
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());
|
BOOST_REQUIRE(errors.empty());
|
||||||
}
|
}
|
||||||
sendMessage(*s_compiledEns, true);
|
sendMessage(*s_compiledEns, true);
|
||||||
|
@ -396,7 +396,7 @@ protected:
|
|||||||
if (!s_compiledErc20)
|
if (!s_compiledErc20)
|
||||||
{
|
{
|
||||||
vector<string> errors;
|
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());
|
BOOST_REQUIRE(errors.empty());
|
||||||
}
|
}
|
||||||
sendMessage(*s_compiledErc20, true);
|
sendMessage(*s_compiledErc20, true);
|
||||||
|
@ -76,6 +76,7 @@ void testConstantOptimizer()
|
|||||||
ConstantOptimisationMethod::optimiseConstants(
|
ConstantOptimisationMethod::optimiseConstants(
|
||||||
isCreation,
|
isCreation,
|
||||||
runs,
|
runs,
|
||||||
|
EVMVersion{},
|
||||||
assembly,
|
assembly,
|
||||||
const_cast<AssemblyItems&>(assembly.items())
|
const_cast<AssemblyItems&>(assembly.items())
|
||||||
);
|
);
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
* Tests for the Solidity optimizer.
|
* Tests for the Solidity optimizer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <test/TestHelper.h>
|
||||||
|
|
||||||
#include <libevmasm/CommonSubexpressionEliminator.h>
|
#include <libevmasm/CommonSubexpressionEliminator.h>
|
||||||
#include <libevmasm/PeepholeOptimiser.h>
|
#include <libevmasm/PeepholeOptimiser.h>
|
||||||
#include <libevmasm/JumpdestRemover.h>
|
#include <libevmasm/JumpdestRemover.h>
|
||||||
@ -916,7 +918,7 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies)
|
|||||||
main.append(t1.toSubAssemblyTag(subId));
|
main.append(t1.toSubAssemblyTag(subId));
|
||||||
main.append(u256(8));
|
main.append(u256(8));
|
||||||
|
|
||||||
main.optimise(true);
|
main.optimise(true, dev::test::Options::get().evmVersion());
|
||||||
|
|
||||||
AssemblyItems expectationMain{
|
AssemblyItems expectationMain{
|
||||||
AssemblyItem(PushSubSize, 0),
|
AssemblyItem(PushSubSize, 0),
|
||||||
|
@ -20,11 +20,16 @@
|
|||||||
* Unit tests for the LLL compiler.
|
* 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 <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <boost/test/unit_test.hpp>
|
|
||||||
#include <liblll/Compiler.h>
|
|
||||||
#include <libdevcore/FixedHash.h>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -41,7 +46,7 @@ namespace
|
|||||||
bool successCompile(string const& _sourceCode)
|
bool successCompile(string const& _sourceCode)
|
||||||
{
|
{
|
||||||
vector<string> errors;
|
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())
|
if (!errors.empty())
|
||||||
return false;
|
return false;
|
||||||
if (bytecode.empty())
|
if (bytecode.empty())
|
||||||
@ -353,7 +358,7 @@ BOOST_AUTO_TEST_CASE(valid_opcodes_functional)
|
|||||||
|
|
||||||
for (size_t i = 0; i < opcodes_bytecode.size(); i++) {
|
for (size_t i = 0; i < opcodes_bytecode.size(); i++) {
|
||||||
vector<string> errors;
|
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]);
|
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++) {
|
for (size_t i = 0; i < opcodes_bytecode.size(); i++) {
|
||||||
vector<string> errors;
|
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]);
|
BOOST_REQUIRE_MESSAGE(errors.empty(), opcodes_lll[i]);
|
||||||
|
|
||||||
|
@ -20,10 +20,13 @@
|
|||||||
* End to end tests for LLL.
|
* End to end tests for LLL.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <test/liblll/ExecutionFramework.h>
|
||||||
|
#include <test/TestHelper.h>
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <boost/test/unit_test.hpp>
|
|
||||||
#include <test/liblll/ExecutionFramework.h>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -583,6 +586,10 @@ BOOST_AUTO_TEST_CASE(allgas)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(send_two_args)
|
BOOST_AUTO_TEST_CASE(send_two_args)
|
||||||
{
|
{
|
||||||
|
// "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"(
|
char const* sourceCode = R"(
|
||||||
(returnlll
|
(returnlll
|
||||||
(send 0xdead 42))
|
(send 0xdead 42))
|
||||||
@ -590,10 +597,15 @@ BOOST_AUTO_TEST_CASE(send_two_args)
|
|||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
callFallbackWithValue(42);
|
callFallbackWithValue(42);
|
||||||
BOOST_CHECK(balanceAt(Address(0xdead)) == 42);
|
BOOST_CHECK(balanceAt(Address(0xdead)) == 42);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(send_three_args)
|
BOOST_AUTO_TEST_CASE(send_three_args)
|
||||||
{
|
{
|
||||||
|
// "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"(
|
char const* sourceCode = R"(
|
||||||
(returnlll
|
(returnlll
|
||||||
(send allgas 0xdead 42))
|
(send allgas 0xdead 42))
|
||||||
@ -601,6 +613,7 @@ BOOST_AUTO_TEST_CASE(send_three_args)
|
|||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
callFallbackWithValue(42);
|
callFallbackWithValue(42);
|
||||||
BOOST_CHECK(balanceAt(Address(0xdead)) == 42);
|
BOOST_CHECK(balanceAt(Address(0xdead)) == 42);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regression test for edge case that previously failed
|
// Regression test for edge case that previously failed
|
||||||
@ -708,6 +721,10 @@ BOOST_AUTO_TEST_CASE(msg_four_args)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(msg_three_args)
|
BOOST_AUTO_TEST_CASE(msg_three_args)
|
||||||
{
|
{
|
||||||
|
// "msg" does not retain enough gas.
|
||||||
|
// Disabling for non-tangerineWhistle VMs.
|
||||||
|
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||||
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
(returnlll
|
(returnlll
|
||||||
(seq
|
(seq
|
||||||
@ -717,10 +734,15 @@ BOOST_AUTO_TEST_CASE(msg_three_args)
|
|||||||
)";
|
)";
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42)));
|
BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(msg_two_args)
|
BOOST_AUTO_TEST_CASE(msg_two_args)
|
||||||
{
|
{
|
||||||
|
// "msg" does not retain enough gas.
|
||||||
|
// Disabling for non-tangerineWhistle VMs.
|
||||||
|
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||||
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
(returnlll
|
(returnlll
|
||||||
(seq
|
(seq
|
||||||
@ -730,10 +752,15 @@ BOOST_AUTO_TEST_CASE(msg_two_args)
|
|||||||
)";
|
)";
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
BOOST_CHECK(callFallback() == encodeArgs(u256(42)));
|
BOOST_CHECK(callFallback() == encodeArgs(u256(42)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(create_one_arg)
|
BOOST_AUTO_TEST_CASE(create_one_arg)
|
||||||
{
|
{
|
||||||
|
// "call" does not retain enough gas.
|
||||||
|
// Disabling for non-tangerineWhistle VMs.
|
||||||
|
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||||
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
(returnlll
|
(returnlll
|
||||||
(seq
|
(seq
|
||||||
@ -744,10 +771,15 @@ BOOST_AUTO_TEST_CASE(create_one_arg)
|
|||||||
)";
|
)";
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
BOOST_CHECK(callFallback() == encodeArgs(u256(42)));
|
BOOST_CHECK(callFallback() == encodeArgs(u256(42)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(create_two_args)
|
BOOST_AUTO_TEST_CASE(create_two_args)
|
||||||
{
|
{
|
||||||
|
// "call" does not retain enough gas.
|
||||||
|
// Disabling for non-tangerineWhistle VMs.
|
||||||
|
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||||
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
(returnlll
|
(returnlll
|
||||||
(seq
|
(seq
|
||||||
@ -758,6 +790,7 @@ BOOST_AUTO_TEST_CASE(create_two_args)
|
|||||||
)";
|
)";
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42)));
|
BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(sha3_two_args)
|
BOOST_AUTO_TEST_CASE(sha3_two_args)
|
||||||
@ -822,6 +855,10 @@ BOOST_AUTO_TEST_CASE(makeperm) // Covers makeperm (implicit), permcount and perm
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(ecrecover)
|
BOOST_AUTO_TEST_CASE(ecrecover)
|
||||||
{
|
{
|
||||||
|
// "ecrecover" does not retain enough gas.
|
||||||
|
// Disabling for non-tangerineWhistle VMs.
|
||||||
|
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||||
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
(returnlll
|
(returnlll
|
||||||
(return
|
(return
|
||||||
@ -837,10 +874,15 @@ BOOST_AUTO_TEST_CASE(ecrecover)
|
|||||||
)";
|
)";
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
BOOST_CHECK(callFallback() == encodeArgs(fromHex("0x8743523d96a1b2cbe0c6909653a56da18ed484af")));
|
BOOST_CHECK(callFallback() == encodeArgs(fromHex("0x8743523d96a1b2cbe0c6909653a56da18ed484af")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(sha256_two_args)
|
BOOST_AUTO_TEST_CASE(sha256_two_args)
|
||||||
{
|
{
|
||||||
|
// "sha256" does not retain enough gas.
|
||||||
|
// Disabling for non-tangerineWhistle VMs.
|
||||||
|
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||||
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
(returnlll
|
(returnlll
|
||||||
(seq
|
(seq
|
||||||
@ -852,10 +894,15 @@ BOOST_AUTO_TEST_CASE(sha256_two_args)
|
|||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
BOOST_CHECK(callFallback() == encodeArgs(
|
BOOST_CHECK(callFallback() == encodeArgs(
|
||||||
fromHex("0xcf25a9fe3d86ae228c226c81d2d8c64c687cd6dc4586d10d8e7e4e5b6706d429")));
|
fromHex("0xcf25a9fe3d86ae228c226c81d2d8c64c687cd6dc4586d10d8e7e4e5b6706d429")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(ripemd160_two_args)
|
BOOST_AUTO_TEST_CASE(ripemd160_two_args)
|
||||||
{
|
{
|
||||||
|
// "ripemd160" does not retain enough gas.
|
||||||
|
// Disabling for non-tangerineWhistle VMs.
|
||||||
|
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||||
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
(returnlll
|
(returnlll
|
||||||
(seq
|
(seq
|
||||||
@ -867,10 +914,15 @@ BOOST_AUTO_TEST_CASE(ripemd160_two_args)
|
|||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
BOOST_CHECK(callFallback() == encodeArgs(
|
BOOST_CHECK(callFallback() == encodeArgs(
|
||||||
fromHex("0x36c6b90a49e17d4c1e1b0e634ec74124d9b207da")));
|
fromHex("0x36c6b90a49e17d4c1e1b0e634ec74124d9b207da")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(sha256_one_arg)
|
BOOST_AUTO_TEST_CASE(sha256_one_arg)
|
||||||
{
|
{
|
||||||
|
// "sha256" does not retain enough gas.
|
||||||
|
// Disabling for non-tangerineWhistle VMs.
|
||||||
|
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||||
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
(returnlll
|
(returnlll
|
||||||
(seq
|
(seq
|
||||||
@ -880,10 +932,15 @@ BOOST_AUTO_TEST_CASE(sha256_one_arg)
|
|||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
BOOST_CHECK(callFallback() == encodeArgs(
|
BOOST_CHECK(callFallback() == encodeArgs(
|
||||||
fromHex("0xcfd2f1fad75a1978da0a444883db7251414b139f31f5a04704c291fdb0e175e6")));
|
fromHex("0xcfd2f1fad75a1978da0a444883db7251414b139f31f5a04704c291fdb0e175e6")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(ripemd160_one_arg)
|
BOOST_AUTO_TEST_CASE(ripemd160_one_arg)
|
||||||
{
|
{
|
||||||
|
// "ripemd160" does not retain enough gas.
|
||||||
|
// Disabling for non-tangerineWhistle VMs.
|
||||||
|
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||||
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
(returnlll
|
(returnlll
|
||||||
(seq
|
(seq
|
||||||
@ -893,6 +950,7 @@ BOOST_AUTO_TEST_CASE(ripemd160_one_arg)
|
|||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
BOOST_CHECK(callFallback() == encodeArgs(
|
BOOST_CHECK(callFallback() == encodeArgs(
|
||||||
fromHex("0xac5ab22e07b0fb80c69b6207902f725e2507e546")));
|
fromHex("0xac5ab22e07b0fb80c69b6207902f725e2507e546")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(wei_szabo_finney_ether)
|
BOOST_AUTO_TEST_CASE(wei_szabo_finney_ether)
|
||||||
|
@ -56,7 +56,7 @@ public:
|
|||||||
BOOST_REQUIRE(_libraryAddresses.empty());
|
BOOST_REQUIRE(_libraryAddresses.empty());
|
||||||
|
|
||||||
std::vector<std::string> errors;
|
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())
|
if (!errors.empty())
|
||||||
{
|
{
|
||||||
for (auto const& error: errors)
|
for (auto const& error: errors)
|
||||||
|
@ -56,7 +56,7 @@ public:
|
|||||||
ASTNode const& sourceUnit = m_compiler.ast("");
|
ASTNode const& sourceUnit = m_compiler.ast("");
|
||||||
BOOST_REQUIRE(items != nullptr);
|
BOOST_REQUIRE(items != nullptr);
|
||||||
m_gasCosts = GasEstimator::breakToStatementLevel(
|
m_gasCosts = GasEstimator::breakToStatementLevel(
|
||||||
GasEstimator::structuralEstimation(*items, vector<ASTNode const*>({&sourceUnit})),
|
GasEstimator(dev::test::Options::get().evmVersion()).structuralEstimation(*items, vector<ASTNode const*>({&sourceUnit})),
|
||||||
{&sourceUnit}
|
{&sourceUnit}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ public:
|
|||||||
{
|
{
|
||||||
compileAndRun(_sourceCode);
|
compileAndRun(_sourceCode);
|
||||||
auto state = make_shared<KnownState>();
|
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);
|
GasMeter::GasConsumption gas = meter.estimateMax(0, state);
|
||||||
u256 bytecodeSize(m_compiler.runtimeObject(m_compiler.lastContractName()).bytecode.size());
|
u256 bytecodeSize(m_compiler.runtimeObject(m_compiler.lastContractName()).bytecode.size());
|
||||||
// costs for deployment
|
// costs for deployment
|
||||||
@ -74,7 +74,7 @@ public:
|
|||||||
gas += gasForTransaction(m_compiler.object(m_compiler.lastContractName()).bytecode, true);
|
gas += gasForTransaction(m_compiler.object(m_compiler.lastContractName()).bytecode, true);
|
||||||
|
|
||||||
BOOST_REQUIRE(!gas.isInfinite);
|
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)
|
/// 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 = max(gas, gasForTransaction(hash.asBytes() + arguments, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
gas += GasEstimator::functionalEstimation(
|
gas += GasEstimator(dev::test::Options::get().evmVersion()).functionalEstimation(
|
||||||
*m_compiler.runtimeAssemblyItems(m_compiler.lastContractName()),
|
*m_compiler.runtimeAssemblyItems(m_compiler.lastContractName()),
|
||||||
_sig
|
_sig
|
||||||
);
|
);
|
||||||
BOOST_REQUIRE(!gas.isInfinite);
|
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)
|
static GasMeter::GasConsumption gasForTransaction(bytes const& _data, bool _isCreation)
|
||||||
|
Loading…
Reference in New Issue
Block a user