EIP-2.1 Fixes #96.

Address a few concerns from prior code review.
This commit is contained in:
Gav Wood 2015-11-21 14:33:55 +01:00
parent 5caad351f8
commit 6e98243ead
5 changed files with 45 additions and 34 deletions

View File

@ -22,7 +22,6 @@
#include "Assembly.h"
#include <fstream>
#include <libdevcore/Log.h>
#include <libevmcore/Params.h>
#include <libevmasm/CommonSubexpressionEliminator.h>
#include <libevmasm/ControlFlowGraph.h>
#include <libevmasm/BlockDeduplicator.h>

View File

@ -22,7 +22,6 @@
#include "libevmasm/ConstantOptimiser.h"
#include <libevmasm/Assembly.h>
#include <libevmasm/GasMeter.h>
#include <libevmcore/Params.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
@ -70,12 +69,13 @@ unsigned ConstantOptimisationMethod::optimiseConstants(
bigint ConstantOptimisationMethod::simpleRunGas(AssemblyItems const& _items)
{
EVMSchedule schedule; // TODO: make relevant to context.
bigint gas = 0;
for (AssemblyItem const& item: _items)
if (item.type() == Push)
gas += GasMeter::runGas(Instruction::PUSH1);
gas += GasMeter::runGas(Instruction::PUSH1, schedule);
else if (item.type() == Operation)
gas += GasMeter::runGas(item.instruction());
gas += GasMeter::runGas(item.instruction(), schedule);
return gas;
}
@ -85,11 +85,11 @@ bigint ConstantOptimisationMethod::dataGas(bytes const& _data) const
{
bigint gas;
for (auto b: _data)
gas += b ? c_txDataNonZeroGas : c_txDataZeroGas;
gas += b ? m_schedule.txDataNonZeroGas : m_schedule.txDataZeroGas;
return gas;
}
else
return c_createDataGas * dataSize();
return m_schedule.createDataGas * dataSize();
}
size_t ConstantOptimisationMethod::bytesRequired(AssemblyItems const& _items)
@ -121,7 +121,7 @@ bigint LiteralMethod::gasNeeded()
return combineGas(
simpleRunGas({Instruction::PUSH1}),
// PUSHX plus data
(m_params.isCreation ? c_txDataNonZeroGas : c_createDataGas) + dataGas(),
(m_params.isCreation ? m_schedule.txDataNonZeroGas : m_schedule.createDataGas) + dataGas(),
0
);
}
@ -148,9 +148,9 @@ bigint CodeCopyMethod::gasNeeded()
{
return combineGas(
// Run gas: we ignore memory increase costs
simpleRunGas(m_copyRoutine) + c_copyGas,
simpleRunGas(m_copyRoutine) + m_schedule.copyGas,
// Data gas for copy routines: Some bytes are zero, but we ignore them.
bytesRequired(m_copyRoutine) * (m_params.isCreation ? c_txDataNonZeroGas : c_createDataGas),
bytesRequired(m_copyRoutine) * (m_params.isCreation ? m_schedule.txDataNonZeroGas : m_schedule.createDataGas),
// Data gas for data itself
dataGas(toBigEndian(m_value))
);
@ -217,9 +217,9 @@ bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine)
{
size_t numExps = count(_routine.begin(), _routine.end(), Instruction::EXP);
return combineGas(
simpleRunGas(_routine) + numExps * (c_expGas + c_expByteGas),
simpleRunGas(_routine) + numExps * (m_schedule.expGas + m_schedule.expByteGas),
// Data gas for routine: Some bytes are zero, but we ignore them.
bytesRequired(_routine) * (m_params.isCreation ? c_txDataNonZeroGas : c_createDataGas),
bytesRequired(_routine) * (m_params.isCreation ? m_schedule.txDataNonZeroGas : m_schedule.createDataGas),
0
);
}

View File

@ -24,6 +24,7 @@
#include <vector>
#include <libdevcore/CommonData.h>
#include <libdevcore/CommonIO.h>
#include <libethcore/ChainOperationParams.h>
namespace dev
{
@ -34,6 +35,8 @@ class AssemblyItem;
using AssemblyItems = std::vector<AssemblyItem>;
class Assembly;
// TODO: FIXME: HOMESTEAD: XXX: @chfast populate m_schedule from an ExtVMFace instance via ExtVMFace::evmSchedule.
/**
* Abstract base class for one way to change how constants are represented in the code.
*/
@ -88,6 +91,7 @@ protected:
Params m_params;
u256 const& m_value;
EVMSchedule m_schedule;
};
/**
@ -101,6 +105,8 @@ public:
ConstantOptimisationMethod(_params, _value) {}
virtual bigint gasNeeded() override;
virtual void execute(Assembly&, AssemblyItems&) override {}
EVMSchedule m_schedule;
};
/**
@ -115,6 +121,7 @@ public:
protected:
AssemblyItems m_copyRoutine;
EVMSchedule m_schedule;
};
/**
@ -141,6 +148,7 @@ protected:
bigint gasNeeded(AssemblyItems const& _routine);
AssemblyItems m_routine;
EVMSchedule m_schedule;
};
}

View File

@ -21,8 +21,6 @@
#include "GasMeter.h"
#include <libevmasm/KnownState.h>
#include <libevmcore/Params.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
@ -73,13 +71,13 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item)
m_state->storageContent().count(slot) &&
classes.knownNonZero(m_state->storageContent().at(slot))
))
gas += c_sstoreResetGas; //@todo take refunds into account
gas += m_schedule.sstoreResetGas; //@todo take refunds into account
else
gas += c_sstoreSetGas;
gas += m_schedule.sstoreSetGas;
break;
}
case Instruction::SLOAD:
gas += c_sloadGas;
gas += m_schedule.sloadGas;
break;
case Instruction::RETURN:
gas += memoryGas(0, -1);
@ -98,18 +96,18 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item)
}));
break;
case Instruction::SHA3:
gas = c_sha3Gas;
gas += wordGas(c_sha3WordGas, m_state->relativeStackElement(-1));
gas = m_schedule.sha3Gas;
gas += wordGas(m_schedule.sha3WordGas, m_state->relativeStackElement(-1));
gas += memoryGas(0, -1);
break;
case Instruction::CALLDATACOPY:
case Instruction::CODECOPY:
gas += memoryGas(0, -2);
gas += wordGas(c_copyGas, m_state->relativeStackElement(-2));
gas += wordGas(m_schedule.copyGas, m_state->relativeStackElement(-2));
break;
case Instruction::EXTCODECOPY:
gas += memoryGas(-1, -3);
gas += wordGas(c_copyGas, m_state->relativeStackElement(-3));
gas += wordGas(m_schedule.copyGas, m_state->relativeStackElement(-3));
break;
case Instruction::LOG0:
case Instruction::LOG1:
@ -118,38 +116,38 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item)
case Instruction::LOG4:
{
unsigned n = unsigned(_item.instruction()) - unsigned(Instruction::LOG0);
gas = c_logGas + c_logTopicGas * n;
gas = m_schedule.logGas + m_schedule.logTopicGas * n;
gas += memoryGas(0, -1);
if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1)))
gas += c_logDataGas * (*value);
gas += m_schedule.logDataGas * (*value);
else
gas = GasConsumption::infinite();
break;
}
case Instruction::CALL:
case Instruction::CALLCODE:
gas = c_callGas;
gas = m_schedule.callGas;
if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(0)))
gas += (*value);
else
gas = GasConsumption::infinite();
if (_item.instruction() != Instruction::CALLCODE)
gas += c_callNewAccountGas; // We very rarely know whether the address exists.
gas += m_schedule.callNewAccountGas; // We very rarely know whether the address exists.
if (!classes.knownZero(m_state->relativeStackElement(-2)))
gas += c_callValueTransferGas;
gas += m_schedule.callValueTransferGas;
gas += memoryGas(-3, -4);
gas += memoryGas(-5, -6);
break;
case Instruction::CREATE:
gas = c_createGas;
gas = m_schedule.createGas;
gas += memoryGas(-1, -2);
break;
case Instruction::EXP:
gas = c_expGas;
gas = m_schedule.expGas;
if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1)))
gas += c_expByteGas * (32 - (h256(*value).firstBitSet() / 8));
gas += m_schedule.expByteGas * (32 - (h256(*value).firstBitSet() / 8));
else
gas += c_expByteGas * 32;
gas += m_schedule.expByteGas * 32;
break;
default:
break;
@ -182,10 +180,10 @@ GasMeter::GasConsumption GasMeter::memoryGas(ExpressionClasses::Id _position)
return GasConsumption(u256(0));
u256 previous = m_largestMemoryAccess;
m_largestMemoryAccess = *value;
auto memGas = [](u256 const& pos) -> u256
auto memGas = [=](u256 const& pos) -> u256
{
u256 size = (pos + 31) / 32;
return c_memoryGas * size + size * size / c_quadCoeffDiv;
return m_schedule.memoryGas * size + size * size / m_schedule.quadCoeffDiv;
};
return memGas(*value) - memGas(previous);
}
@ -202,14 +200,14 @@ GasMeter::GasConsumption GasMeter::memoryGas(int _stackPosOffset, int _stackPosS
}));
}
u256 GasMeter::runGas(Instruction _instruction)
u256 GasMeter::runGas(Instruction _instruction, EVMSchedule const& _es)
{
if (_instruction == Instruction::JUMPDEST)
return 1;
int tier = instructionInfo(_instruction).gasPriceTier;
assertThrow(tier != InvalidTier, OptimizerException, "Invalid gas tier.");
return c_tierStepGas[tier];
return _es.tierStepGas[tier];
}

View File

@ -25,6 +25,7 @@
#include <tuple>
#include <libevmasm/ExpressionClasses.h>
#include <libevmasm/AssemblyItem.h>
#include <libethcore/ChainOperationParams.h>
namespace dev
{
@ -33,6 +34,8 @@ namespace eth
class KnownState;
// TODO: FIXME: HOMESTEAD: XXX: @chfast populate m_schedule from an ExtVMFace instance via ExtVMFace::evmSchedule.
/**
* Class that helps computing the maximum gas consumption for instructions.
* Has to be initialized with a certain known state that will be automatically updated for
@ -66,7 +69,8 @@ public:
u256 const& largestMemoryAccess() const { return m_largestMemoryAccess; }
static u256 runGas(Instruction _instruction);
u256 runGas(Instruction _instruction) const { return runGas(_instruction, m_schedule); }
static u256 runGas(Instruction _instruction, EVMSchedule const& _es);
private:
/// @returns _multiplier * (_value + 31) / 32, if _value is a known constant and infinite otherwise.
@ -81,6 +85,8 @@ private:
std::shared_ptr<KnownState> m_state;
/// Largest point where memory was accessed since the creation of this object.
u256 m_largestMemoryAccess;
EVMSchedule m_schedule;
};
inline std::ostream& operator<<(std::ostream& _str, GasMeter::GasConsumption const& _consumption)