Skip to content

Commit 47a927a

Browse files
committed
Better gas meter implementation for swaps and dups.
1 parent faee30b commit 47a927a

File tree

3 files changed

+34
-16
lines changed

3 files changed

+34
-16
lines changed

libevmasm/GasMeter.cpp

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,11 @@ GasMeter::GasConsumption GasMeter::memoryGas(int _stackPosOffset, int _stackPosS
263263
}));
264264
}
265265

266-
unsigned GasMeter::runGas(Instruction _instruction, langutil::EVMVersion _evmVersion)
266+
namespace
267267
{
268-
if (_instruction == Instruction::JUMPDEST)
269-
return 1;
270-
271-
switch (instructionInfo(_instruction, _evmVersion).gasPriceTier)
268+
std::optional<unsigned> gasCostForTier(Tier _tier)
269+
{
270+
switch (_tier)
272271
{
273272
case Tier::Zero: return GasCosts::tier0Gas;
274273
case Tier::Base: return GasCosts::tier1Gas;
@@ -286,10 +285,21 @@ unsigned GasMeter::runGas(Instruction _instruction, langutil::EVMVersion _evmVer
286285

287286
case Tier::Special:
288287
case Tier::Invalid:
289-
assertThrow(false, OptimizerException, "Invalid gas tier for instruction " + instructionInfo(_instruction, _evmVersion).name);
288+
return std::nullopt;
290289
}
291290
util::unreachable();
292291
}
292+
}
293+
294+
unsigned GasMeter::runGas(Instruction _instruction, langutil::EVMVersion _evmVersion)
295+
{
296+
if (_instruction == Instruction::JUMPDEST)
297+
return 1;
298+
299+
if (auto gasCost = gasCostForTier(instructionInfo(_instruction, _evmVersion).gasPriceTier))
300+
return *gasCost;
301+
assertThrow(false, OptimizerException, "Invalid gas tier for instruction " + instructionInfo(_instruction, _evmVersion).name);
302+
}
293303

294304
unsigned GasMeter::pushGas(u256 _value, langutil::EVMVersion _evmVersion)
295305
{
@@ -299,14 +309,22 @@ unsigned GasMeter::pushGas(u256 _value, langutil::EVMVersion _evmVersion)
299309
);
300310
}
301311

302-
unsigned GasMeter::swapGas(size_t)
312+
unsigned GasMeter::swapGas(size_t _depth, langutil::EVMVersion _evmVersion)
303313
{
304-
return 3;
314+
if (_depth <= 16)
315+
return runGas(evmasm::swapInstruction(static_cast<unsigned>(_depth)), _evmVersion);
316+
auto gasCost = gasCostForTier(instructionInfo(evmasm::Instruction::SWAPN, _evmVersion).gasPriceTier);
317+
assertThrow(gasCost.has_value(), OptimizerException, "Expected gas cost for SWAPN to be defined.");
318+
return *gasCost;
305319
}
306320

307-
unsigned GasMeter::dupGas(size_t)
321+
unsigned GasMeter::dupGas(size_t _depth, langutil::EVMVersion _evmVersion)
308322
{
309-
return 3;
323+
if (_depth <= 16)
324+
return runGas(evmasm::swapInstruction(static_cast<unsigned>(_depth)), _evmVersion);
325+
auto gasCost = gasCostForTier(instructionInfo(evmasm::Instruction::DUPN, _evmVersion).gasPriceTier);
326+
assertThrow(gasCost.has_value(), OptimizerException, "Expected gas cost for DUPN to be defined.");
327+
return *gasCost;
310328
}
311329

312330
u256 GasMeter::dataGas(bytes const& _data, bool _inCreation, langutil::EVMVersion _evmVersion)

libevmasm/GasMeter.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,11 @@ class GasMeter
229229
/// @returns gas costs for push instructions (may change depending on EVM version)
230230
static unsigned pushGas(u256 _value, langutil::EVMVersion _evmVersion);
231231

232-
/// @returns gas costs for swap instructions
233-
static unsigned swapGas(size_t _depth);
232+
/// @returns gas costs for swap instructions (may change depending on EVM version)
233+
static unsigned swapGas(size_t _depth, langutil::EVMVersion _evmVersion);
234234

235-
/// @returns gas costs for dup instructions
236-
static unsigned dupGas(size_t _depth);
235+
/// @returns gas costs for dup instructions (may change depending on EVM version)
236+
static unsigned dupGas(size_t _depth, langutil::EVMVersion _evmVersion);
237237

238238
/// @returns the gas cost of the supplied data, depending whether it is in creation code, or not.
239239
/// In case of @a _inCreation, the data is only sent as a transaction and is not stored, whereas

libyul/backends/evm/StackLayoutGenerator.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,7 @@ void StackLayoutGenerator::fillInJunk(CFG::BasicBlock const& _block, CFG::Functi
782782
if (_swapDepth > m_reachableStackDepth)
783783
opGas += 1000;
784784
else
785-
opGas += evmasm::GasMeter::swapGas(_swapDepth);
785+
opGas += evmasm::GasMeter::swapGas(_swapDepth, langutil::EVMVersion{});
786786
};
787787
auto dupOrPush = [&](StackSlot const& _slot)
788788
{
@@ -793,7 +793,7 @@ void StackLayoutGenerator::fillInJunk(CFG::BasicBlock const& _block, CFG::Functi
793793
if (auto depth = util::findOffset(_source | ranges::views::reverse, _slot))
794794
{
795795
if (*depth < m_reachableStackDepth)
796-
opGas += evmasm::GasMeter::dupGas(*depth + 1);
796+
opGas += evmasm::GasMeter::dupGas(*depth + 1, langutil::EVMVersion{});
797797
else
798798
opGas += 1000;
799799
}

0 commit comments

Comments
 (0)