aboutsummaryrefslogtreecommitdiffstats
path: root/libevmasm
diff options
context:
space:
mode:
Diffstat (limited to 'libevmasm')
-rw-r--r--libevmasm/Assembly.cpp3
-rw-r--r--libevmasm/AssemblyItem.cpp17
-rw-r--r--libevmasm/ConstantOptimiser.cpp57
-rw-r--r--libevmasm/ConstantOptimiser.h13
-rw-r--r--libevmasm/EVMSchedule.h2
-rw-r--r--libevmasm/GasMeter.cpp6
-rw-r--r--libevmasm/GasMeter.h9
-rw-r--r--libevmasm/Instruction.cpp8
-rw-r--r--libevmasm/Instruction.h2
9 files changed, 100 insertions, 17 deletions
diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp
index f12e8aa8..ea061a30 100644
--- a/libevmasm/Assembly.cpp
+++ b/libevmasm/Assembly.cpp
@@ -205,7 +205,8 @@ ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap con
{
_out << _prefix << "stop" << endl;
for (auto const& i: m_data)
- assertThrow(u256(i.first) < m_subs.size(), AssemblyException, "Data not yet implemented.");
+ if (u256(i.first) >= m_subs.size())
+ _out << _prefix << "data_" << toHex(u256(i.first)) << " " << toHex(i.second) << endl;
for (size_t i = 0; i < m_subs.size(); ++i)
{
diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp
index 26d9fded..e69b5932 100644
--- a/libevmasm/AssemblyItem.cpp
+++ b/libevmasm/AssemblyItem.cpp
@@ -159,18 +159,25 @@ string AssemblyItem::toAssemblyText() const
text = toHex(toCompactBigEndian(data(), 1), 1, HexPrefix::Add);
break;
case PushString:
- assertThrow(false, AssemblyException, "Push string assembly output not implemented.");
+ text = string("data_") + toHex(data());
break;
case PushTag:
- assertThrow(data() < 0x10000, AssemblyException, "Sub-assembly tags not yet implemented.");
- text = string("tag_") + to_string(size_t(data()));
+ {
+ size_t sub{0};
+ size_t tag{0};
+ tie(sub, tag) = splitForeignPushTag();
+ if (sub == size_t(-1))
+ text = string("tag_") + to_string(tag);
+ else
+ text = string("tag_") + to_string(sub) + "_" + to_string(tag);
break;
+ }
case Tag:
- assertThrow(data() < 0x10000, AssemblyException, "Sub-assembly tags not yet implemented.");
+ assertThrow(data() < 0x10000, AssemblyException, "Declaration of sub-assembly tag.");
text = string("tag_") + to_string(size_t(data())) + ":";
break;
case PushData:
- assertThrow(false, AssemblyException, "Push data not implemented.");
+ text = string("data_") + toHex(data());
break;
case PushSub:
text = string("dataOffset(sub_") + to_string(size_t(data())) + ")";
diff --git a/libevmasm/ConstantOptimiser.cpp b/libevmasm/ConstantOptimiser.cpp
index a1dfd21c..0c093ebf 100644
--- a/libevmasm/ConstantOptimiser.cpp
+++ b/libevmasm/ConstantOptimiser.cpp
@@ -203,8 +203,13 @@ AssemblyItems ComputeMethod::findRepresentation(u256 const& _value)
u256 powerOfTwo = u256(1) << bits;
u256 upperPart = _value >> bits;
bigint lowerPart = _value & (powerOfTwo - 1);
- if (abs(powerOfTwo - lowerPart) < lowerPart)
+ if ((powerOfTwo - lowerPart) < lowerPart)
+ {
lowerPart = lowerPart - powerOfTwo; // make it negative
+ upperPart++;
+ }
+ if (upperPart == 0)
+ continue;
if (abs(lowerPart) >= (powerOfTwo >> 8))
continue;
@@ -212,7 +217,7 @@ AssemblyItems ComputeMethod::findRepresentation(u256 const& _value)
if (lowerPart != 0)
newRoutine += findRepresentation(u256(abs(lowerPart)));
newRoutine += AssemblyItems{u256(bits), u256(2), Instruction::EXP};
- if (upperPart != 1 && upperPart != 0)
+ if (upperPart != 1)
newRoutine += findRepresentation(upperPart) + AssemblyItems{Instruction::MUL};
if (lowerPart > 0)
newRoutine += AssemblyItems{Instruction::ADD};
@@ -232,6 +237,54 @@ AssemblyItems ComputeMethod::findRepresentation(u256 const& _value)
}
}
+bool ComputeMethod::checkRepresentation(u256 const& _value, AssemblyItems const& _routine)
+{
+ // This is a tiny EVM that can only evaluate some instructions.
+ vector<u256> stack;
+ for (AssemblyItem const& item: _routine)
+ {
+ switch (item.type())
+ {
+ case Operation:
+ {
+ if (stack.size() < size_t(item.arguments()))
+ return false;
+ u256* sp = &stack.back();
+ switch (item.instruction())
+ {
+ case Instruction::MUL:
+ sp[-1] = sp[0] * sp[-1];
+ break;
+ case Instruction::EXP:
+ if (sp[-1] > 0xff)
+ return false;
+ sp[-1] = boost::multiprecision::pow(sp[0], unsigned(sp[-1]));
+ break;
+ case Instruction::ADD:
+ sp[-1] = sp[0] + sp[-1];
+ break;
+ case Instruction::SUB:
+ sp[-1] = sp[0] - sp[-1];
+ break;
+ case Instruction::NOT:
+ sp[0] = ~sp[0];
+ break;
+ default:
+ return false;
+ }
+ stack.resize(stack.size() + item.deposit());
+ break;
+ }
+ case Push:
+ stack.push_back(item.data());
+ break;
+ default:
+ return false;
+ }
+ }
+ return stack.size() == 1 && stack.front() == _value;
+}
+
bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine)
{
size_t numExps = count(_routine.begin(), _routine.end(), Instruction::EXP);
diff --git a/libevmasm/ConstantOptimiser.h b/libevmasm/ConstantOptimiser.h
index 4f12c49f..85bdabac 100644
--- a/libevmasm/ConstantOptimiser.h
+++ b/libevmasm/ConstantOptimiser.h
@@ -21,10 +21,14 @@
#pragma once
-#include <vector>
+#include <libevmasm/Exceptions.h>
+
+#include <libdevcore/Assertions.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/CommonIO.h>
+#include <vector>
+
namespace dev
{
namespace eth
@@ -130,6 +134,11 @@ public:
ConstantOptimisationMethod(_params, _value)
{
m_routine = findRepresentation(m_value);
+ assertThrow(
+ checkRepresentation(m_value, m_routine),
+ OptimizerException,
+ "Invalid constant expression created."
+ );
}
virtual bigint gasNeeded() override { return gasNeeded(m_routine); }
@@ -141,6 +150,8 @@ public:
protected:
/// Tries to recursively find a way to compute @a _value.
AssemblyItems findRepresentation(u256 const& _value);
+ /// Recomputes the value from the calculated representation and checks for correctness.
+ bool checkRepresentation(u256 const& _value, AssemblyItems const& _routine);
bigint gasNeeded(AssemblyItems const& _routine);
/// Counter for the complexity of optimization, will stop when it reaches zero.
diff --git a/libevmasm/EVMSchedule.h b/libevmasm/EVMSchedule.h
index ce9003bd..65d307ae 100644
--- a/libevmasm/EVMSchedule.h
+++ b/libevmasm/EVMSchedule.h
@@ -34,7 +34,7 @@ struct EVMSchedule
unsigned expByteGas = 10;
unsigned sha3Gas = 30;
unsigned sha3WordGas = 6;
- unsigned sloadGas = 50;
+ unsigned sloadGas = 200;
unsigned sstoreSetGas = 20000;
unsigned sstoreResetGas = 5000;
unsigned sstoreRefundGas = 15000;
diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp
index a0adc35d..f5fd00ea 100644
--- a/libevmasm/GasMeter.cpp
+++ b/libevmasm/GasMeter.cpp
@@ -149,6 +149,10 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
}
break;
}
+ case Instruction::SELFDESTRUCT:
+ gas = GasCosts::selfdestructGas;
+ gas += GasCosts::callNewAccountGas; // We very rarely know whether the address exists.
+ break;
case Instruction::CREATE:
if (_includeExternalCosts)
// We assume that we do not know the target contract and thus, the consumption is infinite.
@@ -232,6 +236,8 @@ unsigned GasMeter::runGas(Instruction _instruction)
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.");
diff --git a/libevmasm/GasMeter.h b/libevmasm/GasMeter.h
index 8ade838a..3169ff2a 100644
--- a/libevmasm/GasMeter.h
+++ b/libevmasm/GasMeter.h
@@ -44,11 +44,13 @@ 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;
static unsigned const expGas = 10;
- static unsigned const expByteGas = 10;
+ static unsigned const expByteGas = 50;
static unsigned const sha3Gas = 30;
static unsigned const sha3WordGas = 6;
- static unsigned const sloadGas = 50;
+ static unsigned const sloadGas = 200;
static unsigned const sstoreSetGas = 20000;
static unsigned const sstoreResetGas = 5000;
static unsigned const sstoreRefundGas = 15000;
@@ -57,10 +59,11 @@ namespace GasCosts
static unsigned const logDataGas = 8;
static unsigned const logTopicGas = 375;
static unsigned const createGas = 32000;
- static unsigned const callGas = 40;
+ static unsigned const callGas = 700;
static unsigned const callStipend = 2300;
static unsigned const callValueTransferGas = 9000;
static unsigned const callNewAccountGas = 25000;
+ static unsigned const selfdestructGas = 5000;
static unsigned const selfdestructRefundGas = 24000;
static unsigned const memoryGas = 3;
static unsigned const quadCoeffDiv = 512;
diff --git a/libevmasm/Instruction.cpp b/libevmasm/Instruction.cpp
index de6630f3..5e92c6e6 100644
--- a/libevmasm/Instruction.cpp
+++ b/libevmasm/Instruction.cpp
@@ -191,7 +191,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::SIGNEXTEND, { "SIGNEXTEND", 0, 2, 1, false, Tier::Low } },
{ Instruction::SHA3, { "SHA3", 0, 2, 1, false, Tier::Special } },
{ Instruction::ADDRESS, { "ADDRESS", 0, 0, 1, false, Tier::Base } },
- { Instruction::BALANCE, { "BALANCE", 0, 1, 1, false, Tier::Ext } },
+ { Instruction::BALANCE, { "BALANCE", 0, 1, 1, false, Tier::Balance } },
{ Instruction::ORIGIN, { "ORIGIN", 0, 0, 1, false, Tier::Base } },
{ Instruction::CALLER, { "CALLER", 0, 0, 1, false, Tier::Base } },
{ Instruction::CALLVALUE, { "CALLVALUE", 0, 0, 1, false, Tier::Base } },
@@ -201,8 +201,8 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::CODESIZE, { "CODESIZE", 0, 0, 1, false, Tier::Base } },
{ Instruction::CODECOPY, { "CODECOPY", 0, 3, 0, true, Tier::VeryLow } },
{ Instruction::GASPRICE, { "GASPRICE", 0, 0, 1, false, Tier::Base } },
- { Instruction::EXTCODESIZE, { "EXTCODESIZE", 0, 1, 1, false, Tier::Ext } },
- { Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0, true, Tier::Ext } },
+ { Instruction::EXTCODESIZE, { "EXTCODESIZE", 0, 1, 1, false, Tier::ExtCode } },
+ { Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0, true, Tier::ExtCode } },
{ Instruction::BLOCKHASH, { "BLOCKHASH", 0, 1, 1, false, Tier::Ext } },
{ Instruction::COINBASE, { "COINBASE", 0, 0, 1, false, Tier::Base } },
{ Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1, false, Tier::Base } },
@@ -297,7 +297,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::DELEGATECALL, { "DELEGATECALL", 0, 6, 1, true, Tier::Special } },
{ Instruction::REVERT, { "REVERT", 0, 2, 0, true, Tier::Zero } },
{ Instruction::INVALID, { "INVALID", 0, 0, 0, true, Tier::Zero } },
- { Instruction::SELFDESTRUCT, { "SELFDESTRUCT", 0, 1, 0, true, Tier::Zero } }
+ { Instruction::SELFDESTRUCT, { "SELFDESTRUCT", 0, 1, 0, true, Tier::Special } }
};
void dev::solidity::eachInstruction(
diff --git a/libevmasm/Instruction.h b/libevmasm/Instruction.h
index d79ec969..192fe090 100644
--- a/libevmasm/Instruction.h
+++ b/libevmasm/Instruction.h
@@ -237,6 +237,8 @@ enum class Tier : unsigned
Mid, // 8, Mid
High, // 10, Slow
Ext, // 20, Ext
+ ExtCode, // 700, Extcode
+ Balance, // 400, Balance
Special, // multiparam or otherwise special
Invalid // Invalid.
};