diff options
Diffstat (limited to 'libevmasm')
| -rw-r--r-- | libevmasm/Assembly.cpp | 3 | ||||
| -rw-r--r-- | libevmasm/AssemblyItem.cpp | 17 | ||||
| -rw-r--r-- | libevmasm/ConstantOptimiser.cpp | 57 | ||||
| -rw-r--r-- | libevmasm/ConstantOptimiser.h | 13 | ||||
| -rw-r--r-- | libevmasm/EVMSchedule.h | 2 | ||||
| -rw-r--r-- | libevmasm/GasMeter.cpp | 6 | ||||
| -rw-r--r-- | libevmasm/GasMeter.h | 9 | ||||
| -rw-r--r-- | libevmasm/Instruction.cpp | 8 | ||||
| -rw-r--r-- | libevmasm/Instruction.h | 2 |
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. }; |
