mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
commit
6dc137317f
@ -3,6 +3,7 @@
|
||||
Features:
|
||||
* C99/C++-style scoping rules (instead of JavaScript function scoping) take effect as experimental v0.5.0 feature.
|
||||
* Code Generator: Assert that ``k != 0`` for ``molmod(a, b, k)`` and ``addmod(a, b, k)`` as experimental 0.5.0 feature.
|
||||
* Interface: Provide ability to select target EVM version (homestead or byzantium, with byzantium being the default).
|
||||
* Standard JSON: Reject badly formatted invalid JSON inputs.
|
||||
* Type Checker: Disallow uninitialized storage pointers as experimental 0.5.0 feature.
|
||||
* Support and recommend using ``emit EventName();`` to call events explicitly.
|
||||
|
@ -5,10 +5,6 @@ jobs:
|
||||
- image: trzeci/emscripten:sdk-tag-1.37.21-64bit
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Init submodules
|
||||
command: |
|
||||
git submodule update --init
|
||||
- restore_cache:
|
||||
name: Restore Boost build
|
||||
key: &boost-cache-key emscripten-boost-{{ checksum "scripts/travis-emscripten/install_deps.sh" }}{{ checksum "scripts/travis-emscripten/build_emscripten.sh" }}
|
||||
@ -94,10 +90,6 @@ jobs:
|
||||
command: |
|
||||
apt-get -qq update
|
||||
apt-get -qy install ccache cmake libboost-all-dev libz3-dev
|
||||
- run:
|
||||
name: Init submodules
|
||||
command: |
|
||||
git submodule update --init
|
||||
- run:
|
||||
name: Store commit hash and prerelease
|
||||
command: |
|
||||
|
@ -101,6 +101,7 @@ Input Description
|
||||
enabled: true,
|
||||
runs: 500
|
||||
},
|
||||
evmVersion: "byzantium", // Version of the EVM to compile for. Affects type checking and code generation. Can be homestead, tangerineWhistle, spuriousDragon, byzantium or constantinople
|
||||
// Metadata settings (optional)
|
||||
metadata: {
|
||||
// Use only literal content and not URLs (false by default)
|
||||
|
@ -353,7 +353,7 @@ void Assembly::injectStart(AssemblyItem const& _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;
|
||||
settings.isCreation = _isCreation;
|
||||
@ -365,6 +365,7 @@ Assembly& Assembly::optimise(bool _enable, bool _isCreation, size_t _runs)
|
||||
settings.runCSE = true;
|
||||
settings.runConstantOptimiser = true;
|
||||
}
|
||||
settings.evmVersion = _evmVersion;
|
||||
settings.expectedExecutionsPerDeployment = _runs;
|
||||
optimise(settings);
|
||||
return *this;
|
||||
@ -482,6 +483,7 @@ map<u256, u256> Assembly::optimiseInternal(
|
||||
ConstantOptimisationMethod::optimiseConstants(
|
||||
_settings.isCreation,
|
||||
_settings.isCreation ? 1 : _settings.expectedExecutionsPerDeployment,
|
||||
_settings.evmVersion,
|
||||
*this,
|
||||
m_items
|
||||
);
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include <libevmasm/LinkerObject.h>
|
||||
#include <libevmasm/Exceptions.h>
|
||||
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <libdevcore/Common.h>
|
||||
#include <libdevcore/Assertions.h>
|
||||
#include <libdevcore/SHA3.h>
|
||||
@ -107,6 +109,7 @@ public:
|
||||
bool runDeduplicate = false;
|
||||
bool runCSE = false;
|
||||
bool runConstantOptimiser = false;
|
||||
solidity::EVMVersion evmVersion;
|
||||
/// 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.
|
||||
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,
|
||||
/// 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.
|
||||
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.
|
||||
std::string assemblyString(
|
||||
|
@ -29,6 +29,7 @@ using namespace dev::eth;
|
||||
unsigned ConstantOptimisationMethod::optimiseConstants(
|
||||
bool _isCreation,
|
||||
size_t _runs,
|
||||
solidity::EVMVersion _evmVersion,
|
||||
Assembly& _assembly,
|
||||
AssemblyItems& _items
|
||||
)
|
||||
@ -48,6 +49,7 @@ unsigned ConstantOptimisationMethod::optimiseConstants(
|
||||
params.multiplicity = it.second;
|
||||
params.isCreation = _isCreation;
|
||||
params.runs = _runs;
|
||||
params.evmVersion = _evmVersion;
|
||||
LiteralMethod lit(params, item.data());
|
||||
bigint literalGas = lit.gasNeeded();
|
||||
CodeCopyMethod copy(params, item.data());
|
||||
@ -80,7 +82,12 @@ bigint ConstantOptimisationMethod::simpleRunGas(AssemblyItems const& _items)
|
||||
if (item.type() == Push)
|
||||
gas += GasMeter::runGas(Instruction::PUSH1);
|
||||
else if (item.type() == Operation)
|
||||
gas += GasMeter::runGas(item.instruction());
|
||||
{
|
||||
if (item.instruction() == Instruction::EXP)
|
||||
gas += GasCosts::expGas;
|
||||
else
|
||||
gas += GasMeter::runGas(item.instruction());
|
||||
}
|
||||
return gas;
|
||||
}
|
||||
|
||||
@ -286,7 +293,7 @@ bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine) const
|
||||
{
|
||||
size_t numExps = count(_routine.begin(), _routine.end(), Instruction::EXP);
|
||||
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.
|
||||
bytesRequired(_routine) * (m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas),
|
||||
0
|
||||
|
@ -23,6 +23,8 @@
|
||||
|
||||
#include <libevmasm/Exceptions.h>
|
||||
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <libdevcore/Assertions.h>
|
||||
#include <libdevcore/CommonData.h>
|
||||
#include <libdevcore/CommonIO.h>
|
||||
@ -50,6 +52,7 @@ public:
|
||||
static unsigned optimiseConstants(
|
||||
bool _isCreation,
|
||||
size_t _runs,
|
||||
solidity::EVMVersion _evmVersion,
|
||||
Assembly& _assembly,
|
||||
AssemblyItems& _items
|
||||
);
|
||||
@ -59,6 +62,7 @@ public:
|
||||
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 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):
|
||||
|
@ -61,7 +61,6 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
||||
case Operation:
|
||||
{
|
||||
ExpressionClasses& classes = m_state->expressionClasses();
|
||||
gas = runGas(_item.instruction());
|
||||
switch (_item.instruction())
|
||||
{
|
||||
case Instruction::SSTORE:
|
||||
@ -72,26 +71,29 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
||||
m_state->storageContent().count(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
|
||||
gas += GasCosts::sstoreSetGas;
|
||||
gas = GasCosts::sstoreSetGas;
|
||||
break;
|
||||
}
|
||||
case Instruction::SLOAD:
|
||||
gas += GasCosts::sloadGas;
|
||||
gas = GasCosts::sloadGas(m_evmVersion);
|
||||
break;
|
||||
case Instruction::RETURN:
|
||||
case Instruction::REVERT:
|
||||
gas = runGas(_item.instruction());
|
||||
gas += memoryGas(0, -1);
|
||||
break;
|
||||
case Instruction::MLOAD:
|
||||
case Instruction::MSTORE:
|
||||
gas = runGas(_item.instruction());
|
||||
gas += memoryGas(classes.find(Instruction::ADD, {
|
||||
m_state->relativeStackElement(0),
|
||||
classes.find(AssemblyItem(32))
|
||||
}));
|
||||
break;
|
||||
case Instruction::MSTORE8:
|
||||
gas = runGas(_item.instruction());
|
||||
gas += memoryGas(classes.find(Instruction::ADD, {
|
||||
m_state->relativeStackElement(0),
|
||||
classes.find(AssemblyItem(1))
|
||||
@ -105,10 +107,15 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
||||
case Instruction::CALLDATACOPY:
|
||||
case Instruction::CODECOPY:
|
||||
case Instruction::RETURNDATACOPY:
|
||||
gas = runGas(_item.instruction());
|
||||
gas += memoryGas(0, -2);
|
||||
gas += wordGas(GasCosts::copyGas, m_state->relativeStackElement(-2));
|
||||
break;
|
||||
case Instruction::EXTCODESIZE:
|
||||
gas = GasCosts::extCodeGas(m_evmVersion);
|
||||
break;
|
||||
case Instruction::EXTCODECOPY:
|
||||
gas = GasCosts::extCodeGas(m_evmVersion);
|
||||
gas += memoryGas(-1, -3);
|
||||
gas += wordGas(GasCosts::copyGas, m_state->relativeStackElement(-3));
|
||||
break;
|
||||
@ -137,7 +144,7 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
||||
gas = GasConsumption::infinite();
|
||||
else
|
||||
{
|
||||
gas = GasCosts::callGas;
|
||||
gas = GasCosts::callGas(m_evmVersion);
|
||||
if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(0)))
|
||||
gas += (*value);
|
||||
else
|
||||
@ -155,7 +162,7 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
||||
break;
|
||||
}
|
||||
case Instruction::SELFDESTRUCT:
|
||||
gas = GasCosts::selfdestructGas;
|
||||
gas = GasCosts::selfdestructGas(m_evmVersion);
|
||||
gas += GasCosts::callNewAccountGas; // We very rarely know whether the address exists.
|
||||
break;
|
||||
case Instruction::CREATE:
|
||||
@ -172,11 +179,15 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
||||
case Instruction::EXP:
|
||||
gas = GasCosts::expGas;
|
||||
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
|
||||
gas += GasCosts::expByteGas * 32;
|
||||
gas += GasCosts::expByteGas(m_evmVersion) * 32;
|
||||
break;
|
||||
case Instruction::BALANCE:
|
||||
gas = GasCosts::balanceGas(m_evmVersion);
|
||||
break;
|
||||
default:
|
||||
gas = runGas(_item.instruction());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -241,12 +252,9 @@ unsigned GasMeter::runGas(Instruction _instruction)
|
||||
case Tier::Mid: return GasCosts::tier4Gas;
|
||||
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.");
|
||||
assertThrow(false, OptimizerException, "Invalid gas tier for instruction " + instructionInfo(_instruction).name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -21,11 +21,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
#include <tuple>
|
||||
#include <libevmasm/ExpressionClasses.h>
|
||||
#include <libevmasm/AssemblyItem.h>
|
||||
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <tuple>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace eth
|
||||
@ -44,13 +47,25 @@ 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;
|
||||
inline unsigned extCodeGas(EVMVersion _evmVersion)
|
||||
{
|
||||
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 expByteGas = 50;
|
||||
inline unsigned expByteGas(EVMVersion _evmVersion)
|
||||
{
|
||||
return _evmVersion >= EVMVersion::spuriousDragon() ? 50 : 10;
|
||||
}
|
||||
static unsigned const keccak256Gas = 30;
|
||||
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 sstoreResetGas = 5000;
|
||||
static unsigned const sstoreRefundGas = 15000;
|
||||
@ -59,11 +74,17 @@ namespace GasCosts
|
||||
static unsigned const logDataGas = 8;
|
||||
static unsigned const logTopicGas = 375;
|
||||
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 callValueTransferGas = 9000;
|
||||
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 memoryGas = 3;
|
||||
static unsigned const quadCoeffDiv = 512;
|
||||
@ -100,8 +121,8 @@ public:
|
||||
};
|
||||
|
||||
/// Constructs a new gas meter given the current state.
|
||||
explicit GasMeter(std::shared_ptr<KnownState> const& _state, u256 const& _largestMemoryAccess = 0):
|
||||
m_state(_state), m_largestMemoryAccess(_largestMemoryAccess) {}
|
||||
GasMeter(std::shared_ptr<KnownState> const& _state, solidity::EVMVersion _evmVersion, u256 const& _largestMemoryAccess = 0):
|
||||
m_state(_state), m_evmVersion(_evmVersion), m_largestMemoryAccess(_largestMemoryAccess) {}
|
||||
|
||||
/// @returns an upper bound on the gas consumed by the given instruction and updates
|
||||
/// the state.
|
||||
@ -110,6 +131,8 @@ public:
|
||||
|
||||
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);
|
||||
|
||||
private:
|
||||
@ -123,6 +146,7 @@ private:
|
||||
GasConsumption memoryGas(int _stackPosOffset, int _stackPosSize);
|
||||
|
||||
std::shared_ptr<KnownState> m_state;
|
||||
EVMVersion m_evmVersion;
|
||||
/// Largest point where memory was accessed since the creation of this object.
|
||||
u256 m_largestMemoryAccess;
|
||||
};
|
||||
|
@ -27,8 +27,8 @@ using namespace std;
|
||||
using namespace dev;
|
||||
using namespace dev::eth;
|
||||
|
||||
PathGasMeter::PathGasMeter(AssemblyItems const& _items):
|
||||
m_items(_items)
|
||||
PathGasMeter::PathGasMeter(AssemblyItems const& _items, solidity::EVMVersion _evmVersion):
|
||||
m_items(_items), m_evmVersion(_evmVersion)
|
||||
{
|
||||
for (size_t i = 0; i < m_items.size(); ++i)
|
||||
if (m_items[i].type() == Tag)
|
||||
@ -59,7 +59,7 @@ GasMeter::GasConsumption PathGasMeter::handleQueueItem()
|
||||
m_queue.pop_back();
|
||||
|
||||
shared_ptr<KnownState> state = path->state;
|
||||
GasMeter meter(state, path->largestMemoryAccess);
|
||||
GasMeter meter(state, m_evmVersion, path->largestMemoryAccess);
|
||||
ExpressionClasses& classes = state->expressionClasses();
|
||||
GasMeter::GasConsumption gas = path->gas;
|
||||
size_t index = path->index;
|
||||
|
@ -21,10 +21,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libevmasm/GasMeter.h>
|
||||
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <libevmasm/GasMeter.h>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
@ -50,7 +53,7 @@ struct GasPath
|
||||
class PathGasMeter
|
||||
{
|
||||
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);
|
||||
|
||||
@ -60,6 +63,7 @@ private:
|
||||
std::vector<std::unique_ptr<GasPath>> m_queue;
|
||||
std::map<u256, size_t> m_tagPositions;
|
||||
AssemblyItems const& m_items;
|
||||
solidity::EVMVersion m_evmVersion;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -19,17 +19,16 @@
|
||||
* @date 2014
|
||||
*/
|
||||
|
||||
#include "Compiler.h"
|
||||
#include "Parser.h"
|
||||
#include "CompilerState.h"
|
||||
#include "CodeFragment.h"
|
||||
#include <liblll/Compiler.h>
|
||||
#include <liblll/Parser.h>
|
||||
#include <liblll/CompilerState.h>
|
||||
#include <liblll/CodeFragment.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
using namespace dev::eth;
|
||||
|
||||
|
||||
bytes dev::eth::compileLLL(string const& _src, bool _opt, vector<string>* _errors, ReadCallback const& _readFile)
|
||||
bytes dev::eth::compileLLL(string const& _src, dev::solidity::EVMVersion _evmVersion, bool _opt, std::vector<std::string>* _errors, dev::eth::ReadCallback const& _readFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -37,7 +36,7 @@ bytes dev::eth::compileLLL(string const& _src, bool _opt, vector<string>* _error
|
||||
cs.populateStandard();
|
||||
auto assembly = CodeFragment::compile(_src, cs, _readFile).assembly(cs);
|
||||
if (_opt)
|
||||
assembly = assembly.optimise(true);
|
||||
assembly = assembly.optimise(true, _evmVersion);
|
||||
bytes ret = assembly.assemble().bytecode;
|
||||
for (auto i: cs.treesToKill)
|
||||
killBigints(i);
|
||||
@ -67,7 +66,7 @@ bytes dev::eth::compileLLL(string const& _src, bool _opt, vector<string>* _error
|
||||
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
|
||||
{
|
||||
@ -75,7 +74,7 @@ std::string dev::eth::compileLLLToAsm(std::string const& _src, bool _opt, std::v
|
||||
cs.populateStandard();
|
||||
auto assembly = CodeFragment::compile(_src, cs, _readFile).assembly(cs);
|
||||
if (_opt)
|
||||
assembly = assembly.optimise(true);
|
||||
assembly = assembly.optimise(true, _evmVersion);
|
||||
string ret = assembly.assemblyString();
|
||||
for (auto i: cs.treesToKill)
|
||||
killBigints(i);
|
||||
|
@ -21,9 +21,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libdevcore/Common.h>
|
||||
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <libdevcore/Common.h>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
@ -33,8 +36,8 @@ namespace eth
|
||||
using ReadCallback = std::function<std::string(std::string const&)>;
|
||||
|
||||
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());
|
||||
bytes compileLLL(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, solidity::EVMVersion _evmVersion, bool _opt = true, std::vector<std::string>* _errors = nullptr, ReadCallback const& _readFile = ReadCallback());
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -278,8 +278,9 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
|
||||
};
|
||||
|
||||
// Will be re-generated later with correct information
|
||||
// We use the latest EVM version because we will re-run it anyway.
|
||||
assembly::AsmAnalysisInfo analysisInfo;
|
||||
assembly::AsmAnalyzer(analysisInfo, errorsIgnored, assembly::AsmFlavour::Loose, resolver).analyze(_inlineAssembly.operations());
|
||||
assembly::AsmAnalyzer(analysisInfo, errorsIgnored, EVMVersion(), assembly::AsmFlavour::Loose, resolver).analyze(_inlineAssembly.operations());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -875,6 +875,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
assembly::AsmAnalyzer analyzer(
|
||||
*_inlineAssembly.annotation().analysisInfo,
|
||||
m_errorReporter,
|
||||
m_evmVersion,
|
||||
assembly::AsmFlavour::Loose,
|
||||
identifierAccess
|
||||
);
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <libsolidity/ast/Types.h>
|
||||
#include <libsolidity/ast/ASTAnnotations.h>
|
||||
#include <libsolidity/ast/ASTForward.h>
|
||||
@ -43,7 +45,10 @@ class TypeChecker: private ASTConstVisitor
|
||||
{
|
||||
public:
|
||||
/// @param _errorReporter provides the error logging functionality.
|
||||
TypeChecker(ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
|
||||
TypeChecker(EVMVersion _evmVersion, ErrorReporter& _errorReporter):
|
||||
m_evmVersion(_evmVersion),
|
||||
m_errorReporter(_errorReporter)
|
||||
{}
|
||||
|
||||
/// Performs type checking on the given contract and all of its sub-nodes.
|
||||
/// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings
|
||||
@ -132,6 +137,8 @@ private:
|
||||
|
||||
ContractDefinition const* m_scope = nullptr;
|
||||
|
||||
EVMVersion m_evmVersion;
|
||||
|
||||
/// Flag indicating whether we are currently inside an EmitStatement.
|
||||
bool m_insideEmitStatement = false;
|
||||
|
||||
|
@ -22,10 +22,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/codegen/CompilerContext.h>
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <libevmasm/Assembly.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <functional>
|
||||
#include <libsolidity/codegen/CompilerContext.h>
|
||||
#include <libevmasm/Assembly.h>
|
||||
|
||||
namespace dev {
|
||||
namespace solidity {
|
||||
@ -33,11 +36,11 @@ namespace solidity {
|
||||
class Compiler
|
||||
{
|
||||
public:
|
||||
explicit Compiler(bool _optimize = false, unsigned _runs = 200):
|
||||
explicit Compiler(EVMVersion _evmVersion = EVMVersion{}, bool _optimize = false, unsigned _runs = 200):
|
||||
m_optimize(_optimize),
|
||||
m_optimizeRuns(_runs),
|
||||
m_runtimeContext(),
|
||||
m_context(&m_runtimeContext)
|
||||
m_runtimeContext(_evmVersion),
|
||||
m_context(_evmVersion, &m_runtimeContext)
|
||||
{ }
|
||||
|
||||
/// Compiles a contract.
|
||||
|
@ -329,6 +329,7 @@ void CompilerContext::appendInlineAssembly(
|
||||
analyzerResult = assembly::AsmAnalyzer(
|
||||
analysisInfo,
|
||||
errorReporter,
|
||||
m_evmVersion,
|
||||
assembly::AsmFlavour::Strict,
|
||||
identifierAccess.resolve
|
||||
).analyze(*parserResult);
|
||||
|
@ -24,6 +24,8 @@
|
||||
|
||||
#include <libsolidity/codegen/ABIFunctions.h>
|
||||
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <libsolidity/ast/ASTForward.h>
|
||||
#include <libsolidity/ast/Types.h>
|
||||
#include <libsolidity/ast/ASTAnnotations.h>
|
||||
@ -50,14 +52,17 @@ namespace solidity {
|
||||
class CompilerContext
|
||||
{
|
||||
public:
|
||||
explicit CompilerContext(CompilerContext* _runtimeContext = nullptr):
|
||||
explicit CompilerContext(EVMVersion _evmVersion = EVMVersion{}, CompilerContext* _runtimeContext = nullptr):
|
||||
m_asm(std::make_shared<eth::Assembly>()),
|
||||
m_evmVersion(_evmVersion),
|
||||
m_runtimeContext(_runtimeContext)
|
||||
{
|
||||
if (m_runtimeContext)
|
||||
m_runtimeSub = size_t(m_asm->newSub(m_runtimeContext->m_asm).data());
|
||||
}
|
||||
|
||||
EVMVersion const& evmVersion() const { return m_evmVersion; }
|
||||
|
||||
/// Update currently enabled set of experimental features.
|
||||
void setExperimentalFeatures(std::set<ExperimentalFeature> const& _features) { m_experimentalFeatures = _features; }
|
||||
/// @returns true if the given feature is enabled.
|
||||
@ -204,7 +209,7 @@ public:
|
||||
void appendAuxiliaryData(bytes const& _data) { m_asm->appendAuxiliaryDataToEnd(_data); }
|
||||
|
||||
/// 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.
|
||||
CompilerContext* runtimeContext() { return m_runtimeContext; }
|
||||
@ -287,6 +292,8 @@ private:
|
||||
} m_functionCompilationQueue;
|
||||
|
||||
eth::AssemblyPointer m_asm;
|
||||
/// Version of the EVM to compile against.
|
||||
EVMVersion m_evmVersion;
|
||||
/// Activated experimental features.
|
||||
std::set<ExperimentalFeature> m_experimentalFeatures;
|
||||
/// Other already compiled contracts to be used in contract creation calls.
|
||||
|
@ -1059,7 +1059,7 @@ void ContractCompiler::compileExpression(Expression const& _expression, TypePoin
|
||||
CompilerUtils(m_context).convertType(*_expression.annotation().type, *_targetType);
|
||||
}
|
||||
|
||||
eth::AssemblyPointer ContractCompiler::cloneRuntime()
|
||||
eth::AssemblyPointer ContractCompiler::cloneRuntime() const
|
||||
{
|
||||
eth::Assembly a;
|
||||
a << Instruction::CALLDATASIZE;
|
||||
@ -1070,7 +1070,7 @@ eth::AssemblyPointer ContractCompiler::cloneRuntime()
|
||||
// this is the address which has to be substituted by the linker.
|
||||
//@todo implement as special "marker" AssemblyItem.
|
||||
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;
|
||||
//Propagate error condition (if DELEGATECALL pushes 0 on stack).
|
||||
a << Instruction::ISZERO;
|
||||
|
@ -43,7 +43,7 @@ public:
|
||||
m_runtimeCompiler(_runtimeCompiler),
|
||||
m_context(_context)
|
||||
{
|
||||
m_context = CompilerContext(_runtimeCompiler ? &_runtimeCompiler->m_context : nullptr);
|
||||
m_context = CompilerContext(_context.evmVersion(), _runtimeCompiler ? &_runtimeCompiler->m_context : nullptr);
|
||||
}
|
||||
|
||||
void compileContract(
|
||||
@ -125,7 +125,7 @@ private:
|
||||
void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer());
|
||||
|
||||
/// @returns the runtime assembly for clone contracts.
|
||||
static eth::AssemblyPointer cloneRuntime();
|
||||
eth::AssemblyPointer cloneRuntime() const;
|
||||
|
||||
bool const m_optimise;
|
||||
/// 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"
|
||||
// @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())
|
||||
gasNeededByCaller += eth::GasCosts::callValueTransferGas;
|
||||
if (!existenceChecked)
|
||||
|
@ -533,33 +533,47 @@ void AsmAnalyzer::expectValidType(string const& type, SourceLocation const& _loc
|
||||
|
||||
void AsmAnalyzer::warnOnInstructions(solidity::Instruction _instr, SourceLocation const& _location)
|
||||
{
|
||||
static set<solidity::Instruction> futureInstructions{
|
||||
solidity::Instruction::CREATE2,
|
||||
solidity::Instruction::RETURNDATACOPY,
|
||||
solidity::Instruction::RETURNDATASIZE,
|
||||
solidity::Instruction::STATICCALL
|
||||
};
|
||||
if (futureInstructions.count(_instr))
|
||||
m_errorReporter.warning(
|
||||
_location,
|
||||
"The \"" +
|
||||
boost::to_lower_copy(instructionInfo(_instr).name)
|
||||
+ "\" instruction is only available after " +
|
||||
"the Metropolis hard fork. Before that it acts as an invalid instruction."
|
||||
);
|
||||
// We assume that returndatacopy, returndatasize and staticcall are either all available
|
||||
// or all not available.
|
||||
solAssert(m_evmVersion.supportsReturndata() == m_evmVersion.hasStaticCall(), "");
|
||||
|
||||
static set<solidity::Instruction> experimentalInstructions{
|
||||
solidity::Instruction::SHL,
|
||||
solidity::Instruction::SHR,
|
||||
solidity::Instruction::SAR
|
||||
};
|
||||
if (experimentalInstructions.count(_instr))
|
||||
if (_instr == solidity::Instruction::CREATE2)
|
||||
m_errorReporter.warning(
|
||||
_location,
|
||||
"The \"" +
|
||||
boost::to_lower_copy(instructionInfo(_instr).name)
|
||||
+ "\" instruction is only available after " +
|
||||
"the Constantinople hard fork. Before that it acts as an invalid instruction."
|
||||
+ "\" instruction is not supported by the VM version \"" +
|
||||
"" + m_evmVersion.name() +
|
||||
"\" you are currently compiling for. " +
|
||||
"It will be interpreted as an invalid instruction on this VM."
|
||||
);
|
||||
else if ((
|
||||
_instr == solidity::Instruction::RETURNDATACOPY ||
|
||||
_instr == solidity::Instruction::RETURNDATASIZE ||
|
||||
_instr == solidity::Instruction::STATICCALL
|
||||
) && !m_evmVersion.supportsReturndata())
|
||||
m_errorReporter.warning(
|
||||
_location,
|
||||
"The \"" +
|
||||
boost::to_lower_copy(instructionInfo(_instr).name)
|
||||
+ "\" instruction is only available for Byzantium-compatible VMs. " +
|
||||
"You are currently compiling for \"" +
|
||||
m_evmVersion.name() +
|
||||
"\", where it will be interpreted as an invalid instruction."
|
||||
);
|
||||
else if ((
|
||||
_instr == solidity::Instruction::SHL ||
|
||||
_instr == solidity::Instruction::SHR ||
|
||||
_instr == solidity::Instruction::SAR
|
||||
) && !m_evmVersion.hasBitwiseShifting())
|
||||
m_errorReporter.warning(
|
||||
_location,
|
||||
"The \"" +
|
||||
boost::to_lower_copy(instructionInfo(_instr).name)
|
||||
+ "\" instruction is only available for Constantinople-compatible VMs. " +
|
||||
"You are currently compiling for \"" +
|
||||
m_evmVersion.name() +
|
||||
"\", where it will be interpreted as an invalid instruction."
|
||||
);
|
||||
|
||||
if (_instr == solidity::Instruction::JUMP || _instr == solidity::Instruction::JUMPI || _instr == solidity::Instruction::JUMPDEST)
|
||||
|
@ -21,6 +21,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/interface/Exceptions.h>
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <libsolidity/inlineasm/AsmScope.h>
|
||||
|
||||
@ -54,9 +55,10 @@ public:
|
||||
explicit AsmAnalyzer(
|
||||
AsmAnalysisInfo& _analysisInfo,
|
||||
ErrorReporter& _errorReporter,
|
||||
EVMVersion _evmVersion,
|
||||
AsmFlavour _flavour = AsmFlavour::Loose,
|
||||
julia::ExternalIdentifierAccess::Resolver const& _resolver = julia::ExternalIdentifierAccess::Resolver()
|
||||
): m_resolver(_resolver), m_info(_analysisInfo), m_errorReporter(_errorReporter), m_flavour(_flavour) {}
|
||||
): m_resolver(_resolver), m_info(_analysisInfo), m_errorReporter(_errorReporter), m_evmVersion(_evmVersion), m_flavour(_flavour) {}
|
||||
|
||||
bool analyze(assembly::Block const& _block);
|
||||
|
||||
@ -97,6 +99,7 @@ private:
|
||||
std::set<Scope::Variable const*> m_activeVariables;
|
||||
AsmAnalysisInfo& m_info;
|
||||
ErrorReporter& m_errorReporter;
|
||||
EVMVersion m_evmVersion;
|
||||
AsmFlavour m_flavour = AsmFlavour::Loose;
|
||||
};
|
||||
|
||||
|
@ -91,7 +91,7 @@ bool AssemblyStack::analyze(assembly::Block const& _block, Scanner const* _scann
|
||||
bool AssemblyStack::analyzeParsed()
|
||||
{
|
||||
m_analysisInfo = make_shared<assembly::AsmAnalysisInfo>();
|
||||
assembly::AsmAnalyzer analyzer(*m_analysisInfo, m_errorReporter, languageToAsmFlavour(m_language));
|
||||
assembly::AsmAnalyzer analyzer(*m_analysisInfo, m_errorReporter, m_evmVersion, languageToAsmFlavour(m_language));
|
||||
m_analysisSuccessful = analyzer.analyze(*m_parserResult);
|
||||
return m_analysisSuccessful;
|
||||
}
|
||||
|
@ -22,6 +22,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/interface/ErrorReporter.h>
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <libevmasm/LinkerObject.h>
|
||||
|
||||
#include <string>
|
||||
@ -54,8 +56,8 @@ public:
|
||||
enum class Language { JULIA, Assembly, StrictAssembly };
|
||||
enum class Machine { EVM, EVM15, eWasm };
|
||||
|
||||
explicit AssemblyStack(Language _language = Language::Assembly):
|
||||
m_language(_language), m_errorReporter(m_errors)
|
||||
explicit AssemblyStack(EVMVersion _evmVersion = EVMVersion(), Language _language = Language::Assembly):
|
||||
m_language(_language), m_evmVersion(_evmVersion), m_errorReporter(m_errors)
|
||||
{}
|
||||
|
||||
/// @returns the scanner used during parsing
|
||||
@ -82,6 +84,7 @@ private:
|
||||
bool analyzeParsed();
|
||||
|
||||
Language m_language = Language::Assembly;
|
||||
EVMVersion m_evmVersion;
|
||||
|
||||
std::shared_ptr<Scanner> m_scanner;
|
||||
|
||||
|
@ -74,6 +74,12 @@ void CompilerStack::setRemappings(vector<string> const& _remappings)
|
||||
swap(m_remappings, remappings);
|
||||
}
|
||||
|
||||
void CompilerStack::setEVMVersion(EVMVersion _version)
|
||||
{
|
||||
solAssert(m_stackState < State::ParsingSuccessful, "Set EVM version after parsing.");
|
||||
m_evmVersion = _version;
|
||||
}
|
||||
|
||||
void CompilerStack::reset(bool _keepSources)
|
||||
{
|
||||
if (_keepSources)
|
||||
@ -88,6 +94,7 @@ void CompilerStack::reset(bool _keepSources)
|
||||
m_sources.clear();
|
||||
}
|
||||
m_libraries.clear();
|
||||
m_evmVersion = EVMVersion();
|
||||
m_optimize = false;
|
||||
m_optimizeRuns = 200;
|
||||
m_globalContext.reset();
|
||||
@ -198,7 +205,7 @@ bool CompilerStack::analyze()
|
||||
m_contracts[contract->fullyQualifiedName()].contract = contract;
|
||||
}
|
||||
|
||||
TypeChecker typeChecker(m_errorReporter);
|
||||
TypeChecker typeChecker(m_evmVersion, m_errorReporter);
|
||||
for (Source const* source: m_sourceOrder)
|
||||
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
@ -677,7 +684,7 @@ void CompilerStack::compileContract(
|
||||
for (auto const* dependency: _contract.annotation().contractDependencies)
|
||||
compileContract(*dependency, _compiledContracts);
|
||||
|
||||
shared_ptr<Compiler> compiler = make_shared<Compiler>(m_optimize, m_optimizeRuns);
|
||||
shared_ptr<Compiler> compiler = make_shared<Compiler>(m_evmVersion, m_optimize, m_optimizeRuns);
|
||||
Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
|
||||
string metadata = createMetadata(compiledContract);
|
||||
bytes cborEncodedHash =
|
||||
@ -736,7 +743,7 @@ void CompilerStack::compileContract(
|
||||
{
|
||||
if (!_contract.isLibrary())
|
||||
{
|
||||
Compiler cloneCompiler(m_optimize, m_optimizeRuns);
|
||||
Compiler cloneCompiler(m_evmVersion, m_optimize, m_optimizeRuns);
|
||||
cloneCompiler.compileClone(_contract, _compiledContracts);
|
||||
compiledContract.cloneObject = cloneCompiler.assembledObject();
|
||||
}
|
||||
@ -838,6 +845,7 @@ string CompilerStack::createMetadata(Contract const& _contract) const
|
||||
}
|
||||
meta["settings"]["optimizer"]["enabled"] = m_optimize;
|
||||
meta["settings"]["optimizer"]["runs"] = m_optimizeRuns;
|
||||
meta["settings"]["evmVersion"] = m_evmVersion.name();
|
||||
meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] =
|
||||
_contract.contract->annotation().canonicalName;
|
||||
|
||||
@ -951,11 +959,12 @@ Json::Value CompilerStack::gasEstimates(string const& _contractName) const
|
||||
return Json::Value();
|
||||
|
||||
using Gas = GasEstimator::GasConsumption;
|
||||
GasEstimator gasEstimator(m_evmVersion);
|
||||
Json::Value output(Json::objectValue);
|
||||
|
||||
if (eth::AssemblyItems const* items = assemblyItems(_contractName))
|
||||
{
|
||||
Gas executionGas = GasEstimator::functionalEstimation(*items);
|
||||
Gas executionGas = gasEstimator.functionalEstimation(*items);
|
||||
u256 bytecodeSize(runtimeObject(_contractName).bytecode.size());
|
||||
Gas codeDepositGas = bytecodeSize * eth::GasCosts::createDataGas;
|
||||
|
||||
@ -976,14 +985,14 @@ Json::Value CompilerStack::gasEstimates(string const& _contractName) const
|
||||
for (auto it: contract.interfaceFunctions())
|
||||
{
|
||||
string sig = it.second->externalSignature();
|
||||
externalFunctions[sig] = gasToJson(GasEstimator::functionalEstimation(*items, sig));
|
||||
externalFunctions[sig] = gasToJson(gasEstimator.functionalEstimation(*items, sig));
|
||||
}
|
||||
|
||||
if (contract.fallbackFunction())
|
||||
/// 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.
|
||||
/// 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())
|
||||
output["external"] = externalFunctions;
|
||||
@ -999,7 +1008,7 @@ Json::Value CompilerStack::gasEstimates(string const& _contractName) const
|
||||
size_t entry = functionEntryPoint(_contractName, *it);
|
||||
GasEstimator::GasConsumption gas = GasEstimator::GasConsumption::infinite();
|
||||
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()
|
||||
FunctionType type(*it);
|
||||
|
@ -23,20 +23,26 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/interface/ErrorReporter.h>
|
||||
#include <libsolidity/interface/ReadFile.h>
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <libevmasm/SourceLocation.h>
|
||||
#include <libevmasm/LinkerObject.h>
|
||||
|
||||
#include <libdevcore/Common.h>
|
||||
#include <libdevcore/FixedHash.h>
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <json/json.h>
|
||||
#include <libdevcore/Common.h>
|
||||
#include <libdevcore/FixedHash.h>
|
||||
#include <libevmasm/SourceLocation.h>
|
||||
#include <libevmasm/LinkerObject.h>
|
||||
#include <libsolidity/interface/ErrorReporter.h>
|
||||
#include <libsolidity/interface/ReadFile.h>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
@ -116,6 +122,8 @@ public:
|
||||
m_optimizeRuns = _runs;
|
||||
}
|
||||
|
||||
void setEVMVersion(EVMVersion _version = EVMVersion{});
|
||||
|
||||
/// Sets the list of requested contract names. If empty, no filtering is performed and every contract
|
||||
/// found in the supplied sources is compiled. Names are cleared iff @a _contractNames is missing.
|
||||
void setRequestedContractNames(std::set<std::string> const& _contractNames = std::set<std::string>{})
|
||||
@ -310,6 +318,7 @@ private:
|
||||
ReadCallback::Callback m_smtQuery;
|
||||
bool m_optimize = false;
|
||||
unsigned m_optimizeRuns = 200;
|
||||
EVMVersion m_evmVersion;
|
||||
std::set<std::string> m_requestedContractNames;
|
||||
std::map<std::string, h160> m_libraries;
|
||||
/// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum
|
||||
|
93
libsolidity/interface/EVMVersion.h
Normal file
93
libsolidity/interface/EVMVersion.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* EVM versioning.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/operators.hpp>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace solidity
|
||||
{
|
||||
|
||||
/**
|
||||
* A version specifier of the EVM we want to compile to.
|
||||
* Defaults to the latest version.
|
||||
*/
|
||||
class EVMVersion:
|
||||
boost::less_than_comparable<EVMVersion>,
|
||||
boost::equality_comparable<EVMVersion>
|
||||
{
|
||||
public:
|
||||
EVMVersion() {}
|
||||
|
||||
static EVMVersion homestead() { return {Version::Homestead}; }
|
||||
static EVMVersion tangerineWhistle() { return {Version::TangerineWhistle}; }
|
||||
static EVMVersion spuriousDragon() { return {Version::SpuriousDragon}; }
|
||||
static EVMVersion byzantium() { return {Version::Byzantium}; }
|
||||
static EVMVersion constantinople() { return {Version::Constantinople}; }
|
||||
|
||||
static boost::optional<EVMVersion> fromString(std::string const& _version)
|
||||
{
|
||||
for (auto const& v: {homestead(), tangerineWhistle(), spuriousDragon(), byzantium()})
|
||||
if (_version == v.name())
|
||||
return v;
|
||||
return {};
|
||||
}
|
||||
|
||||
bool operator==(EVMVersion const& _other) const { return m_version == _other.m_version; }
|
||||
bool operator<(EVMVersion const& _other) const { return m_version < _other.m_version; }
|
||||
|
||||
std::string name() const
|
||||
{
|
||||
switch (m_version)
|
||||
{
|
||||
case Version::Homestead: return "homestead";
|
||||
case Version::TangerineWhistle: return "tangerineWhistle";
|
||||
case Version::SpuriousDragon: return "spuriousDragon";
|
||||
case Version::Byzantium: return "byzantium";
|
||||
case Version::Constantinople: return "constantinople";
|
||||
}
|
||||
return "INVALID";
|
||||
}
|
||||
|
||||
/// Has the RETURNDATACOPY and RETURNDATASIZE opcodes.
|
||||
bool supportsReturndata() const { return *this >= byzantium(); }
|
||||
bool hasStaticCall() const { return *this >= byzantium(); }
|
||||
bool hasBitwiseShifting() const { return *this >= constantinople(); }
|
||||
|
||||
/// Whether we have to retain the costs for the call opcode itself (false),
|
||||
/// or whether we can just forward easily all remaining gas (true).
|
||||
bool canOverchargeGasForCall() const { return *this >= tangerineWhistle(); }
|
||||
|
||||
private:
|
||||
enum class Version { Homestead, TangerineWhistle, SpuriousDragon, Byzantium, Constantinople };
|
||||
|
||||
EVMVersion(Version _version): m_version(_version) {}
|
||||
|
||||
Version m_version = Version::Byzantium;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -40,7 +40,7 @@ using namespace dev::solidity;
|
||||
GasEstimator::ASTGasConsumptionSelfAccumulated GasEstimator::structuralEstimation(
|
||||
AssemblyItems const& _items,
|
||||
vector<ASTNode const*> const& _ast
|
||||
)
|
||||
) const
|
||||
{
|
||||
solAssert(std::count(_ast.begin(), _ast.end(), nullptr) == 0, "");
|
||||
map<SourceLocation, GasConsumption> particularCosts;
|
||||
@ -49,7 +49,7 @@ GasEstimator::ASTGasConsumptionSelfAccumulated GasEstimator::structuralEstimatio
|
||||
for (BasicBlock const& block: cfg.optimisedBlocks())
|
||||
{
|
||||
solAssert(!!block.startState, "");
|
||||
GasMeter meter(block.startState->copy());
|
||||
GasMeter meter(block.startState->copy(), m_evmVersion);
|
||||
auto const end = _items.begin() + block.end;
|
||||
for (auto iter = _items.begin() + block.begin; iter != end; ++iter)
|
||||
particularCosts[iter->location()] += meter.estimateMax(*iter);
|
||||
@ -127,7 +127,7 @@ map<ASTNode const*, GasMeter::GasConsumption> GasEstimator::breakToStatementLeve
|
||||
GasEstimator::GasConsumption GasEstimator::functionalEstimation(
|
||||
AssemblyItems const& _items,
|
||||
string const& _signature
|
||||
)
|
||||
) const
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -152,7 +152,7 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation(
|
||||
AssemblyItems const& _items,
|
||||
size_t const& _offset,
|
||||
FunctionDefinition const& _function
|
||||
)
|
||||
) const
|
||||
{
|
||||
auto state = make_shared<KnownState>();
|
||||
|
||||
@ -167,7 +167,7 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation(
|
||||
if (parametersSize > 0)
|
||||
state->feedItem(swapInstruction(parametersSize));
|
||||
|
||||
return PathGasMeter(_items).estimateMax(_offset, state);
|
||||
return PathGasMeter(_items, m_evmVersion).estimateMax(_offset, state);
|
||||
}
|
||||
|
||||
set<ASTNode const*> GasEstimator::finestNodesAtLocation(
|
||||
|
@ -22,11 +22,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <libevmasm/GasMeter.h>
|
||||
#include <libevmasm/Assembly.h>
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <array>
|
||||
#include <libevmasm/GasMeter.h>
|
||||
#include <libevmasm/Assembly.h>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
@ -44,13 +47,15 @@ public:
|
||||
using ASTGasConsumptionSelfAccumulated =
|
||||
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
|
||||
/// it by source location.
|
||||
/// @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,
|
||||
std::vector<ASTNode const*> const& _ast
|
||||
);
|
||||
) const;
|
||||
/// @returns a mapping from nodes with non-overlapping source locations to gas consumptions such that
|
||||
/// the following source locations are part of the mapping:
|
||||
/// 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
|
||||
/// given signature. If no signature is given, estimates the maximum gas usage.
|
||||
static GasConsumption functionalEstimation(
|
||||
GasConsumption functionalEstimation(
|
||||
eth::AssemblyItems const& _items,
|
||||
std::string const& _signature = ""
|
||||
);
|
||||
) const;
|
||||
|
||||
/// @returns the estimated gas consumption by the given function which starts at the given
|
||||
/// offset into the list of assembly items.
|
||||
/// @note this does not work correctly for recursive functions.
|
||||
static GasConsumption functionalEstimation(
|
||||
GasConsumption functionalEstimation(
|
||||
eth::AssemblyItems const& _items,
|
||||
size_t const& _offset,
|
||||
FunctionDefinition const& _function
|
||||
);
|
||||
) const;
|
||||
|
||||
private:
|
||||
/// @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);
|
||||
EVMVersion m_evmVersion;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -318,6 +318,14 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
|
||||
|
||||
Json::Value const& settings = _input.get("settings", Json::Value());
|
||||
|
||||
if (settings.isMember("evmVersion"))
|
||||
{
|
||||
boost::optional<EVMVersion> version = EVMVersion::fromString(settings.get("evmVersion", {}).asString());
|
||||
if (!version)
|
||||
return formatFatalError("JSONError", "Invalid EVM version requested.");
|
||||
m_compilerStack.setEVMVersion(*version);
|
||||
}
|
||||
|
||||
vector<string> remappings;
|
||||
for (auto const& remapping: settings.get("remappings", Json::Value()))
|
||||
remappings.push_back(remapping.asString());
|
||||
|
@ -133,7 +133,7 @@ int main(int argc, char** argv)
|
||||
}
|
||||
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)
|
||||
cout << toHex(bs) << endl;
|
||||
else if (mode == Binary)
|
||||
@ -145,7 +145,7 @@ int main(int argc, char** argv)
|
||||
}
|
||||
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)
|
||||
|
@ -37,11 +37,9 @@ then
|
||||
echo "Usage: $0 [--junit_report <report_directory>]"
|
||||
exit 1
|
||||
fi
|
||||
testargs_no_opt="--logger=JUNIT,test_suite,$2/no_opt.xml"
|
||||
testargs_opt="--logger=JUNIT,test_suite,$2/opt.xml"
|
||||
log_directory="$2"
|
||||
else
|
||||
testargs_no_opt=''
|
||||
testargs_opt=''
|
||||
log_directory=""
|
||||
fi
|
||||
|
||||
echo "Running commandline tests..."
|
||||
@ -98,10 +96,26 @@ then
|
||||
progress=""
|
||||
fi
|
||||
|
||||
echo "--> Running tests without optimizer..."
|
||||
"$REPO_ROOT"/build/test/soltest $testargs_no_opt $progress -- --ipcpath /tmp/test/geth.ipc
|
||||
echo "--> Running tests WITH optimizer..."
|
||||
"$REPO_ROOT"/build/test/soltest $testargs_opt $progress -- --optimize --ipcpath /tmp/test/geth.ipc
|
||||
# And then run the Solidity unit-tests in the matrix combination of optimizer / no optimizer
|
||||
# and homestead / byzantium VM, # pointing to that IPC endpoint.
|
||||
for optimize in "" "--optimize"
|
||||
do
|
||||
for vm in homestead byzantium
|
||||
do
|
||||
echo "--> Running tests using "$optimize" --evm-version "$vm"..."
|
||||
log=""
|
||||
if [ -n "$log_directory" ]
|
||||
then
|
||||
if [ -n "$optimize" ]
|
||||
then
|
||||
log=--logger=JUNIT,test_suite,$log_directory/opt_$vm.xml $testargs
|
||||
else
|
||||
log=--logger=JUNIT,test_suite,$log_directory/noopt_$vm.xml $testargs_no_opt
|
||||
fi
|
||||
fi
|
||||
"$REPO_ROOT"/build/test/soltest $progress $log -- "$optimize" --evm-version "$vm" --ipcpath /tmp/test/geth.ipc
|
||||
done
|
||||
done
|
||||
|
||||
wait $CMDLINE_PID
|
||||
|
||||
|
@ -71,7 +71,6 @@ namespace solidity
|
||||
|
||||
static string const g_stdinFileNameStr = "<stdin>";
|
||||
static string const g_strAbi = "abi";
|
||||
static string const g_strAddStandard = "add-std";
|
||||
static string const g_strAllowPaths = "allow-paths";
|
||||
static string const g_strAsm = "asm";
|
||||
static string const g_strAsmJson = "asm-json";
|
||||
@ -87,6 +86,7 @@ static string const g_strCompactJSON = "compact-format";
|
||||
static string const g_strContracts = "contracts";
|
||||
static string const g_strEVM = "evm";
|
||||
static string const g_strEVM15 = "evm15";
|
||||
static string const g_strEVMVersion = "evm-version";
|
||||
static string const g_streWasm = "ewasm";
|
||||
static string const g_strFormal = "formal";
|
||||
static string const g_strGas = "gas";
|
||||
@ -118,7 +118,6 @@ static string const g_strPrettyJson = "pretty-json";
|
||||
static string const g_strVersion = "version";
|
||||
|
||||
static string const g_argAbi = g_strAbi;
|
||||
static string const g_argAddStandard = g_strAddStandard;
|
||||
static string const g_argPrettyJson = g_strPrettyJson;
|
||||
static string const g_argAllowPaths = g_strAllowPaths;
|
||||
static string const g_argAsm = g_strAsm;
|
||||
@ -537,13 +536,17 @@ Allowed options)",
|
||||
(g_argHelp.c_str(), "Show help message and exit.")
|
||||
(g_argVersion.c_str(), "Show version and exit.")
|
||||
(g_strLicense.c_str(), "Show licensing information and exit.")
|
||||
(
|
||||
g_strEVMVersion.c_str(),
|
||||
po::value<string>()->value_name("version"),
|
||||
"Select desired EVM version. Either homestead, tangerineWhistle, spuriousDragon, byzantium (default) or constantinople."
|
||||
)
|
||||
(g_argOptimize.c_str(), "Enable bytecode optimizer.")
|
||||
(
|
||||
g_argOptimizeRuns.c_str(),
|
||||
po::value<unsigned>()->value_name("n")->default_value(200),
|
||||
"Estimated number of contract runs for optimizer tuning."
|
||||
)
|
||||
(g_argAddStandard.c_str(), "Add standard contracts.")
|
||||
(g_argPrettyJson.c_str(), "Output JSON in pretty format. Currently it only works with the combined JSON output.")
|
||||
(
|
||||
g_argLibraries.c_str(),
|
||||
@ -745,6 +748,18 @@ bool CommandLineInterface::processInput()
|
||||
if (!parseLibraryOption(library))
|
||||
return false;
|
||||
|
||||
if (m_args.count(g_strEVMVersion))
|
||||
{
|
||||
string versionOptionStr = m_args[g_strEVMVersion].as<string>();
|
||||
boost::optional<EVMVersion> versionOption = EVMVersion::fromString(versionOptionStr);
|
||||
if (!versionOption)
|
||||
{
|
||||
cerr << "Invalid option for --evm-version: " << versionOptionStr << endl;
|
||||
return false;
|
||||
}
|
||||
m_evmVersion = *versionOption;
|
||||
}
|
||||
|
||||
if (m_args.count(g_argAssemble) || m_args.count(g_argStrictAssembly) || m_args.count(g_argJulia))
|
||||
{
|
||||
// switch to assembly mode
|
||||
@ -792,6 +807,7 @@ bool CommandLineInterface::processInput()
|
||||
m_compiler->addSource(sourceCode.first, sourceCode.second);
|
||||
if (m_args.count(g_argLibraries))
|
||||
m_compiler->setLibraries(m_libraries);
|
||||
m_compiler->setEVMVersion(m_evmVersion);
|
||||
// TODO: Perhaps we should not compile unless requested
|
||||
bool optimize = m_args.count(g_argOptimize) > 0;
|
||||
unsigned runs = m_args[g_argOptimizeRuns].as<unsigned>();
|
||||
@ -950,7 +966,7 @@ void CommandLineInterface::handleAst(string const& _argStr)
|
||||
// FIXME: shouldn't this be done for every contract?
|
||||
if (m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()))
|
||||
gasCosts = GasEstimator::breakToStatementLevel(
|
||||
GasEstimator::structuralEstimation(*m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()), asts),
|
||||
GasEstimator(m_evmVersion).structuralEstimation(*m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()), asts),
|
||||
asts
|
||||
);
|
||||
|
||||
@ -1071,7 +1087,7 @@ bool CommandLineInterface::assemble(
|
||||
map<string, AssemblyStack> assemblyStacks;
|
||||
for (auto const& src: m_sourceCodes)
|
||||
{
|
||||
auto& stack = assemblyStacks[src.first] = AssemblyStack(_language);
|
||||
auto& stack = assemblyStacks[src.first] = AssemblyStack(m_evmVersion, _language);
|
||||
try
|
||||
{
|
||||
if (!stack.parseAndAnalyze(src.first, src.second))
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include <libsolidity/interface/CompilerStack.h>
|
||||
#include <libsolidity/interface/AssemblyStack.h>
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
@ -102,6 +103,8 @@ private:
|
||||
std::map<std::string, h160> m_libraries;
|
||||
/// Solidity compiler stack
|
||||
std::unique_ptr<dev::solidity::CompilerStack> m_compiler;
|
||||
/// EVM version to use
|
||||
EVMVersion m_evmVersion;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -20,13 +20,15 @@
|
||||
* Framework for executing contracts and testing them using RPC.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <boost/test/framework.hpp>
|
||||
#include <libdevcore/CommonIO.h>
|
||||
#include <test/ExecutionFramework.h>
|
||||
|
||||
#include <libdevcore/CommonIO.h>
|
||||
|
||||
#include <boost/test/framework.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
using namespace dev::test;
|
||||
@ -49,6 +51,7 @@ string getIPCSocketPath()
|
||||
|
||||
ExecutionFramework::ExecutionFramework() :
|
||||
m_rpc(RPCSession::instance(getIPCSocketPath())),
|
||||
m_evmVersion(dev::test::Options::get().evmVersion()),
|
||||
m_optimize(dev::test::Options::get().optimize),
|
||||
m_showMessages(dev::test::Options::get().showMessages),
|
||||
m_sender(m_rpc.account(0))
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include <test/TestHelper.h>
|
||||
#include <test/RPCSession.h>
|
||||
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <libdevcore/FixedHash.h>
|
||||
#include <libdevcore/SHA3.h>
|
||||
|
||||
@ -227,6 +229,7 @@ protected:
|
||||
bytes data;
|
||||
};
|
||||
|
||||
solidity::EVMVersion m_evmVersion;
|
||||
unsigned m_optimizeRuns = 200;
|
||||
bool m_optimize = false;
|
||||
bool m_showMessages = false;
|
||||
|
@ -60,7 +60,8 @@ bool isValidMetadata(string const& _metadata)
|
||||
!metadata.isMember("compiler") ||
|
||||
!metadata.isMember("settings") ||
|
||||
!metadata.isMember("sources") ||
|
||||
!metadata.isMember("output")
|
||||
!metadata.isMember("output") ||
|
||||
!metadata["settings"].isMember("evmVersion")
|
||||
)
|
||||
return false;
|
||||
|
||||
|
@ -19,7 +19,11 @@
|
||||
/// @file RPCSession.cpp
|
||||
/// Low-level IPC communication between the test framework and the Ethereum node.
|
||||
|
||||
#include "RPCSession.h"
|
||||
#include <test/RPCSession.h>
|
||||
|
||||
#include <test/TestHelper.h>
|
||||
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <libdevcore/CommonData.h>
|
||||
|
||||
@ -215,6 +219,13 @@ string RPCSession::personal_newAccount(string const& _password)
|
||||
|
||||
void RPCSession::test_setChainParams(vector<string> const& _accounts)
|
||||
{
|
||||
string forks;
|
||||
if (test::Options::get().evmVersion() >= solidity::EVMVersion::tangerineWhistle())
|
||||
forks += "\"EIP150ForkBlock\": \"0x00\",\n";
|
||||
if (test::Options::get().evmVersion() >= solidity::EVMVersion::spuriousDragon())
|
||||
forks += "\"EIP158ForkBlock\": \"0x00\",\n";
|
||||
if (test::Options::get().evmVersion() >= solidity::EVMVersion::byzantium())
|
||||
forks += "\"byzantiumForkBlock\": \"0x00\",\n";
|
||||
static string const c_configString = R"(
|
||||
{
|
||||
"sealEngine": "NoProof",
|
||||
@ -223,9 +234,8 @@ void RPCSession::test_setChainParams(vector<string> const& _accounts)
|
||||
"maximumExtraDataSize": "0x1000000",
|
||||
"blockReward": "0x",
|
||||
"allowFutureBlocks": true,
|
||||
"homesteadForkBlock": "0x00",
|
||||
"EIP150ForkBlock": "0x00",
|
||||
"EIP158ForkBlock": "0x00"
|
||||
)" + forks + R"(
|
||||
"homesteadForkBlock": "0x00"
|
||||
},
|
||||
"genesis": {
|
||||
"author": "0000000000000010000000000000000000000000",
|
||||
|
@ -19,8 +19,12 @@
|
||||
* @date 2014
|
||||
*/
|
||||
|
||||
#include <test/TestHelper.h>
|
||||
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <boost/test/framework.hpp>
|
||||
#include "TestHelper.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace dev::test;
|
||||
|
||||
@ -41,6 +45,11 @@ Options::Options()
|
||||
}
|
||||
else if (string(suite.argv[i]) == "--optimize")
|
||||
optimize = true;
|
||||
else if (string(suite.argv[i]) == "--evm-version")
|
||||
{
|
||||
evmVersionString = i + 1 < suite.argc ? suite.argv[i + 1] : "INVALID";
|
||||
++i;
|
||||
}
|
||||
else if (string(suite.argv[i]) == "--show-messages")
|
||||
showMessages = true;
|
||||
else if (string(suite.argv[i]) == "--no-ipc")
|
||||
@ -52,3 +61,17 @@ Options::Options()
|
||||
if (auto path = getenv("ETH_TEST_IPC"))
|
||||
ipcPath = path;
|
||||
}
|
||||
|
||||
dev::solidity::EVMVersion Options::evmVersion() const
|
||||
{
|
||||
if (!evmVersionString.empty())
|
||||
{
|
||||
// We do this check as opposed to in the constructor because the BOOST_REQUIRE
|
||||
// macros cannot yet be used in the constructor.
|
||||
auto version = solidity::EVMVersion::fromString(evmVersionString);
|
||||
BOOST_REQUIRE_MESSAGE(version, "Invalid EVM version: " + evmVersionString);
|
||||
return *version;
|
||||
}
|
||||
else
|
||||
return dev::solidity::EVMVersion();
|
||||
}
|
||||
|
@ -19,11 +19,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <libsolidity/interface/EVMVersion.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace test
|
||||
@ -37,9 +40,13 @@ struct Options: boost::noncopyable
|
||||
bool disableIPC = false;
|
||||
bool disableSMT = false;
|
||||
|
||||
solidity::EVMVersion evmVersion() const;
|
||||
|
||||
static Options const& get();
|
||||
|
||||
private:
|
||||
std::string evmVersionString;
|
||||
|
||||
Options();
|
||||
};
|
||||
|
||||
|
@ -345,7 +345,7 @@ protected:
|
||||
if (!s_compiledEns)
|
||||
{
|
||||
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());
|
||||
}
|
||||
sendMessage(*s_compiledEns, true);
|
||||
|
@ -396,7 +396,7 @@ protected:
|
||||
if (!s_compiledErc20)
|
||||
{
|
||||
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());
|
||||
}
|
||||
sendMessage(*s_compiledErc20, true);
|
||||
|
@ -76,6 +76,7 @@ void testConstantOptimizer()
|
||||
ConstantOptimisationMethod::optimiseConstants(
|
||||
isCreation,
|
||||
runs,
|
||||
EVMVersion{},
|
||||
assembly,
|
||||
const_cast<AssemblyItems&>(assembly.items())
|
||||
);
|
||||
|
@ -20,6 +20,8 @@
|
||||
* Tests for the Solidity optimizer.
|
||||
*/
|
||||
|
||||
#include <test/TestHelper.h>
|
||||
|
||||
#include <libevmasm/CommonSubexpressionEliminator.h>
|
||||
#include <libevmasm/PeepholeOptimiser.h>
|
||||
#include <libevmasm/JumpdestRemover.h>
|
||||
@ -916,7 +918,7 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies)
|
||||
main.append(t1.toSubAssemblyTag(subId));
|
||||
main.append(u256(8));
|
||||
|
||||
main.optimise(true);
|
||||
main.optimise(true, dev::test::Options::get().evmVersion());
|
||||
|
||||
AssemblyItems expectationMain{
|
||||
AssemblyItem(PushSubSize, 0),
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
#include <test/libjulia/Common.h>
|
||||
|
||||
#include <test/TestHelper.h>
|
||||
|
||||
#include <libjulia/optimiser/Disambiguator.h>
|
||||
|
||||
#include <libsolidity/parsing/Scanner.h>
|
||||
@ -61,7 +63,12 @@ pair<shared_ptr<Block>, shared_ptr<assembly::AsmAnalysisInfo>> dev::julia::test:
|
||||
{
|
||||
BOOST_REQUIRE(errorReporter.errors().empty());
|
||||
auto analysisInfo = make_shared<assembly::AsmAnalysisInfo>();
|
||||
assembly::AsmAnalyzer analyzer(*analysisInfo, errorReporter, flavour);
|
||||
assembly::AsmAnalyzer analyzer(
|
||||
*analysisInfo,
|
||||
errorReporter,
|
||||
dev::test::Options::get().evmVersion(),
|
||||
flavour
|
||||
);
|
||||
if (analyzer.analyze(*parserResult))
|
||||
{
|
||||
BOOST_REQUIRE(errorReporter.errors().empty());
|
||||
|
@ -56,7 +56,12 @@ bool parse(string const& _source, ErrorReporter& errorReporter)
|
||||
if (parserResult)
|
||||
{
|
||||
assembly::AsmAnalysisInfo analysisInfo;
|
||||
return (assembly::AsmAnalyzer(analysisInfo, errorReporter, assembly::AsmFlavour::IULIA)).analyze(*parserResult);
|
||||
return (assembly::AsmAnalyzer(
|
||||
analysisInfo,
|
||||
errorReporter,
|
||||
dev::test::Options::get().evmVersion(),
|
||||
assembly::AsmFlavour::IULIA
|
||||
)).analyze(*parserResult);
|
||||
}
|
||||
}
|
||||
catch (FatalError const&)
|
||||
|
@ -20,11 +20,16 @@
|
||||
* 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 <memory>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <liblll/Compiler.h>
|
||||
#include <libdevcore/FixedHash.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -41,7 +46,7 @@ namespace
|
||||
bool successCompile(string const& _sourceCode)
|
||||
{
|
||||
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())
|
||||
return false;
|
||||
if (bytecode.empty())
|
||||
@ -353,7 +358,7 @@ BOOST_AUTO_TEST_CASE(valid_opcodes_functional)
|
||||
|
||||
for (size_t i = 0; i < opcodes_bytecode.size(); i++) {
|
||||
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]);
|
||||
|
||||
@ -641,7 +646,7 @@ BOOST_AUTO_TEST_CASE(valid_opcodes_asm)
|
||||
|
||||
for (size_t i = 0; i < opcodes_bytecode.size(); i++) {
|
||||
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]);
|
||||
|
||||
|
@ -20,10 +20,13 @@
|
||||
* End to end tests for LLL.
|
||||
*/
|
||||
|
||||
#include <test/liblll/ExecutionFramework.h>
|
||||
#include <test/TestHelper.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <test/liblll/ExecutionFramework.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -583,24 +586,34 @@ BOOST_AUTO_TEST_CASE(allgas)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(send_two_args)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(send 0xdead 42))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
callFallbackWithValue(42);
|
||||
BOOST_CHECK(balanceAt(Address(0xdead)) == 42);
|
||||
// "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"(
|
||||
(returnlll
|
||||
(send 0xdead 42))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
callFallbackWithValue(42);
|
||||
BOOST_CHECK(balanceAt(Address(0xdead)) == 42);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(send_three_args)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(send allgas 0xdead 42))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
callFallbackWithValue(42);
|
||||
BOOST_CHECK(balanceAt(Address(0xdead)) == 42);
|
||||
// "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"(
|
||||
(returnlll
|
||||
(send allgas 0xdead 42))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
callFallbackWithValue(42);
|
||||
BOOST_CHECK(balanceAt(Address(0xdead)) == 42);
|
||||
}
|
||||
}
|
||||
|
||||
// Regression test for edge case that previously failed
|
||||
@ -708,56 +721,76 @@ BOOST_AUTO_TEST_CASE(msg_four_args)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(msg_three_args)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(seq
|
||||
(when (= 0 (calldatasize))
|
||||
(return (msg (address) 42 0xff)))
|
||||
(return (callvalue))))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42)));
|
||||
// "msg" does not retain enough gas.
|
||||
// Disabling for non-tangerineWhistle VMs.
|
||||
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(seq
|
||||
(when (= 0 (calldatasize))
|
||||
(return (msg (address) 42 0xff)))
|
||||
(return (callvalue))))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42)));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(msg_two_args)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(seq
|
||||
(when (= 0 (calldatasize))
|
||||
(return (msg (address) 0xff)))
|
||||
(return 42)))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallback() == encodeArgs(u256(42)));
|
||||
// "msg" does not retain enough gas.
|
||||
// Disabling for non-tangerineWhistle VMs.
|
||||
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(seq
|
||||
(when (= 0 (calldatasize))
|
||||
(return (msg (address) 0xff)))
|
||||
(return 42)))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallback() == encodeArgs(u256(42)));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(create_one_arg)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(seq
|
||||
(call allgas
|
||||
(create (returnlll (return 42)))
|
||||
0 0 0 0x00 0x20)
|
||||
(return 0x00 0x20)))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallback() == encodeArgs(u256(42)));
|
||||
// "call" does not retain enough gas.
|
||||
// Disabling for non-tangerineWhistle VMs.
|
||||
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(seq
|
||||
(call allgas
|
||||
(create (returnlll (return 42)))
|
||||
0 0 0 0x00 0x20)
|
||||
(return 0x00 0x20)))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallback() == encodeArgs(u256(42)));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(create_two_args)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(seq
|
||||
(call allgas
|
||||
(create 42 (returnlll (return (balance (address)))))
|
||||
0 0 0 0x00 0x20)
|
||||
(return 0x00 0x20)))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42)));
|
||||
// "call" does not retain enough gas.
|
||||
// Disabling for non-tangerineWhistle VMs.
|
||||
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(seq
|
||||
(call allgas
|
||||
(create 42 (returnlll (return (balance (address)))))
|
||||
0 0 0 0x00 0x20)
|
||||
(return 0x00 0x20)))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42)));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(sha3_two_args)
|
||||
@ -822,77 +855,102 @@ BOOST_AUTO_TEST_CASE(makeperm) // Covers makeperm (implicit), permcount and perm
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ecrecover)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(return
|
||||
(ecrecover
|
||||
; Hash of 'hello world'
|
||||
0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad
|
||||
; v = 1 + 27
|
||||
0x1c
|
||||
; r
|
||||
0xdebaaa0cddb321b2dcaaf846d39605de7b97e77ba6106587855b9106cb104215
|
||||
; s
|
||||
0x61a22d94fa8b8a687ff9c911c844d1c016d1a685a9166858f9c7c1bc85128aca)))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallback() == encodeArgs(fromHex("0x8743523d96a1b2cbe0c6909653a56da18ed484af")));
|
||||
// "ecrecover" does not retain enough gas.
|
||||
// Disabling for non-tangerineWhistle VMs.
|
||||
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(return
|
||||
(ecrecover
|
||||
; Hash of 'hello world'
|
||||
0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad
|
||||
; v = 1 + 27
|
||||
0x1c
|
||||
; r
|
||||
0xdebaaa0cddb321b2dcaaf846d39605de7b97e77ba6106587855b9106cb104215
|
||||
; s
|
||||
0x61a22d94fa8b8a687ff9c911c844d1c016d1a685a9166858f9c7c1bc85128aca)))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallback() == encodeArgs(fromHex("0x8743523d96a1b2cbe0c6909653a56da18ed484af")));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(sha256_two_args)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(seq
|
||||
(lit 0x20 "abcdefghijklmnopqrstuvwxyzABCDEF")
|
||||
(lit 0x40 "GHIJKLMNOPQRSTUVWXYZ0123456789?!")
|
||||
(sha256 0x20 0x40)
|
||||
(return 0x00 0x20)))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallback() == encodeArgs(
|
||||
fromHex("0xcf25a9fe3d86ae228c226c81d2d8c64c687cd6dc4586d10d8e7e4e5b6706d429")));
|
||||
// "sha256" does not retain enough gas.
|
||||
// Disabling for non-tangerineWhistle VMs.
|
||||
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(seq
|
||||
(lit 0x20 "abcdefghijklmnopqrstuvwxyzABCDEF")
|
||||
(lit 0x40 "GHIJKLMNOPQRSTUVWXYZ0123456789?!")
|
||||
(sha256 0x20 0x40)
|
||||
(return 0x00 0x20)))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallback() == encodeArgs(
|
||||
fromHex("0xcf25a9fe3d86ae228c226c81d2d8c64c687cd6dc4586d10d8e7e4e5b6706d429")));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ripemd160_two_args)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(seq
|
||||
(lit 0x20 "abcdefghijklmnopqrstuvwxyzABCDEF")
|
||||
(lit 0x40 "GHIJKLMNOPQRSTUVWXYZ0123456789?!")
|
||||
(ripemd160 0x20 0x40)
|
||||
(return 0x00 0x20)))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallback() == encodeArgs(
|
||||
fromHex("0x36c6b90a49e17d4c1e1b0e634ec74124d9b207da")));
|
||||
// "ripemd160" does not retain enough gas.
|
||||
// Disabling for non-tangerineWhistle VMs.
|
||||
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(seq
|
||||
(lit 0x20 "abcdefghijklmnopqrstuvwxyzABCDEF")
|
||||
(lit 0x40 "GHIJKLMNOPQRSTUVWXYZ0123456789?!")
|
||||
(ripemd160 0x20 0x40)
|
||||
(return 0x00 0x20)))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallback() == encodeArgs(
|
||||
fromHex("0x36c6b90a49e17d4c1e1b0e634ec74124d9b207da")));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(sha256_one_arg)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(seq
|
||||
(sha256 0x6162636465666768696a6b6c6d6e6f707172737475767778797a414243444546)
|
||||
(return 0x00 0x20)))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallback() == encodeArgs(
|
||||
fromHex("0xcfd2f1fad75a1978da0a444883db7251414b139f31f5a04704c291fdb0e175e6")));
|
||||
// "sha256" does not retain enough gas.
|
||||
// Disabling for non-tangerineWhistle VMs.
|
||||
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(seq
|
||||
(sha256 0x6162636465666768696a6b6c6d6e6f707172737475767778797a414243444546)
|
||||
(return 0x00 0x20)))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallback() == encodeArgs(
|
||||
fromHex("0xcfd2f1fad75a1978da0a444883db7251414b139f31f5a04704c291fdb0e175e6")));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ripemd160_one_arg)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(seq
|
||||
(ripemd160 0x6162636465666768696a6b6c6d6e6f707172737475767778797a414243444546)
|
||||
(return 0x00 0x20)))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallback() == encodeArgs(
|
||||
fromHex("0xac5ab22e07b0fb80c69b6207902f725e2507e546")));
|
||||
// "ripemd160" does not retain enough gas.
|
||||
// Disabling for non-tangerineWhistle VMs.
|
||||
if (dev::test::Options::get().evmVersion().canOverchargeGasForCall())
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
(returnlll
|
||||
(seq
|
||||
(ripemd160 0x6162636465666768696a6b6c6d6e6f707172737475767778797a414243444546)
|
||||
(return 0x00 0x20)))
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callFallback() == encodeArgs(
|
||||
fromHex("0xac5ab22e07b0fb80c69b6207902f725e2507e546")));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(wei_szabo_finney_ether)
|
||||
|
@ -56,7 +56,7 @@ public:
|
||||
BOOST_REQUIRE(_libraryAddresses.empty());
|
||||
|
||||
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())
|
||||
{
|
||||
for (auto const& error: errors)
|
||||
|
@ -20,12 +20,16 @@
|
||||
* Tests for the json ast output.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <test/TestHelper.h>
|
||||
|
||||
#include <libsolidity/interface/Exceptions.h>
|
||||
#include <libsolidity/interface/CompilerStack.h>
|
||||
#include <libsolidity/ast/ASTJsonConverter.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace dev
|
||||
@ -41,6 +45,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C {}");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
@ -52,6 +57,7 @@ BOOST_AUTO_TEST_CASE(source_location)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { function f() { var x = 2; x++; } }");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
@ -66,6 +72,7 @@ BOOST_AUTO_TEST_CASE(inheritance_specifier)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C1 {} contract C2 is C1 {}");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
@ -81,6 +88,7 @@ BOOST_AUTO_TEST_CASE(using_for_directive)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "library L {} contract C { using L for uint; }");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
@ -98,6 +106,7 @@ BOOST_AUTO_TEST_CASE(enum_value)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { enum E { A, B } }");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
@ -115,6 +124,7 @@ BOOST_AUTO_TEST_CASE(modifier_definition)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { modifier M(uint i) { _; } function F() M(1) {} }");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
@ -129,6 +139,7 @@ BOOST_AUTO_TEST_CASE(modifier_invocation)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { modifier M(uint i) { _; } function F() M(1) {} }");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
@ -145,6 +156,7 @@ BOOST_AUTO_TEST_CASE(event_definition)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { event E(); }");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
@ -159,6 +171,7 @@ BOOST_AUTO_TEST_CASE(array_type_name)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { uint[] i; }");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
@ -172,6 +185,7 @@ BOOST_AUTO_TEST_CASE(placeholder_statement)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { modifier M { _; } }");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
@ -185,6 +199,7 @@ BOOST_AUTO_TEST_CASE(non_utf8)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { function f() { var x = hex\"ff\"; } }");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
@ -204,6 +219,7 @@ BOOST_AUTO_TEST_CASE(function_type)
|
||||
"contract C { function f(function() external payable returns (uint) x) "
|
||||
"returns (function() external constant returns (uint)) {} }"
|
||||
);
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
@ -244,6 +260,7 @@ BOOST_AUTO_TEST_CASE(documentation)
|
||||
" /** Some comment on fn.*/ function fn() public {}"
|
||||
"}"
|
||||
);
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 0;
|
||||
|
@ -20,6 +20,8 @@
|
||||
|
||||
#include <test/libsolidity/AnalysisFramework.h>
|
||||
|
||||
#include <test/TestHelper.h>
|
||||
|
||||
#include <libsolidity/interface/CompilerStack.h>
|
||||
#include <libsolidity/interface/SourceReferenceFormatter.h>
|
||||
|
||||
@ -46,6 +48,7 @@ AnalysisFramework::parseAnalyseAndReturnError(
|
||||
{
|
||||
m_compiler.reset();
|
||||
m_compiler.addSource("", _insertVersionPragma ? "pragma solidity >=0.0;\n" + _source : _source);
|
||||
m_compiler.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
if (!m_compiler.parse())
|
||||
{
|
||||
BOOST_ERROR("Parsing contract failed in analysis test suite:" + formatErrors());
|
||||
|
@ -20,11 +20,11 @@
|
||||
* Unit tests for Assembly Items from evmasm/Assembly.h
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <test/TestHelper.h>
|
||||
|
||||
#include <libevmasm/SourceLocation.h>
|
||||
#include <libevmasm/Assembly.h>
|
||||
|
||||
#include <libsolidity/parsing/Scanner.h>
|
||||
#include <libsolidity/parsing/Parser.h>
|
||||
#include <libsolidity/analysis/NameAndTypeResolver.h>
|
||||
@ -33,6 +33,11 @@
|
||||
#include <libsolidity/analysis/TypeChecker.h>
|
||||
#include <libsolidity/interface/ErrorReporter.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev::eth;
|
||||
|
||||
@ -46,7 +51,7 @@ namespace test
|
||||
namespace
|
||||
{
|
||||
|
||||
eth::AssemblyItems compileContract(const string& _sourceCode)
|
||||
eth::AssemblyItems compileContract(string const& _sourceCode)
|
||||
{
|
||||
ErrorList errors;
|
||||
ErrorReporter errorReporter(errors);
|
||||
@ -69,7 +74,7 @@ eth::AssemblyItems compileContract(const string& _sourceCode)
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
TypeChecker checker(errorReporter);
|
||||
TypeChecker checker(dev::test::Options::get().evmVersion(), errorReporter);
|
||||
BOOST_REQUIRE_NO_THROW(checker.checkTypeRequirements(*contract));
|
||||
if (!Error::containsOnlyWarnings(errorReporter.errors()))
|
||||
return AssemblyItems();
|
||||
@ -77,7 +82,7 @@ eth::AssemblyItems compileContract(const string& _sourceCode)
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
Compiler compiler;
|
||||
Compiler compiler(dev::test::Options::get().evmVersion());
|
||||
compiler.compileContract(*contract, map<ContractDefinition const*, Assembly const*>{}, bytes());
|
||||
|
||||
return compiler.runtimeAssemblyItems();
|
||||
|
@ -49,13 +49,14 @@ public:
|
||||
m_compiler.reset(false);
|
||||
m_compiler.addSource("", "pragma solidity >=0.0;\n" + _sourceCode);
|
||||
m_compiler.setOptimiserSettings(dev::test::Options::get().optimize);
|
||||
m_compiler.setEVMVersion(m_evmVersion);
|
||||
BOOST_REQUIRE_MESSAGE(m_compiler.compile(), "Compiling contract failed");
|
||||
|
||||
AssemblyItems const* items = m_compiler.runtimeAssemblyItems(m_compiler.lastContractName());
|
||||
ASTNode const& sourceUnit = m_compiler.ast("");
|
||||
BOOST_REQUIRE(items != nullptr);
|
||||
m_gasCosts = GasEstimator::breakToStatementLevel(
|
||||
GasEstimator::structuralEstimation(*items, vector<ASTNode const*>({&sourceUnit})),
|
||||
GasEstimator(dev::test::Options::get().evmVersion()).structuralEstimation(*items, vector<ASTNode const*>({&sourceUnit})),
|
||||
{&sourceUnit}
|
||||
);
|
||||
}
|
||||
@ -64,7 +65,7 @@ public:
|
||||
{
|
||||
compileAndRun(_sourceCode);
|
||||
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);
|
||||
u256 bytecodeSize(m_compiler.runtimeObject(m_compiler.lastContractName()).bytecode.size());
|
||||
// costs for deployment
|
||||
@ -73,7 +74,7 @@ public:
|
||||
gas += gasForTransaction(m_compiler.object(m_compiler.lastContractName()).bytecode, true);
|
||||
|
||||
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)
|
||||
@ -90,12 +91,12 @@ public:
|
||||
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()),
|
||||
_sig
|
||||
);
|
||||
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)
|
||||
|
@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
#include <test/libsolidity/ErrorCheck.h>
|
||||
#include <test/TestHelper.h>
|
||||
|
||||
#include <libsolidity/interface/Exceptions.h>
|
||||
#include <libsolidity/interface/CompilerStack.h>
|
||||
@ -44,6 +45,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
}
|
||||
|
||||
@ -52,6 +54,7 @@ BOOST_AUTO_TEST_CASE(regular_import)
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C {} pragma solidity >=0.0;");
|
||||
c.addSource("b", "import \"a\"; contract D is C {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
}
|
||||
|
||||
@ -60,6 +63,7 @@ BOOST_AUTO_TEST_CASE(import_does_not_clutter_importee)
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { D d; } pragma solidity >=0.0;");
|
||||
c.addSource("b", "import \"a\"; contract D is C {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(!c.compile());
|
||||
}
|
||||
|
||||
@ -69,6 +73,7 @@ BOOST_AUTO_TEST_CASE(import_is_transitive)
|
||||
c.addSource("a", "contract C { } pragma solidity >=0.0;");
|
||||
c.addSource("b", "import \"a\"; pragma solidity >=0.0;");
|
||||
c.addSource("c", "import \"b\"; contract D is C {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
}
|
||||
|
||||
@ -77,6 +82,7 @@ BOOST_AUTO_TEST_CASE(circular_import)
|
||||
CompilerStack c;
|
||||
c.addSource("a", "import \"b\"; contract C { D d; } pragma solidity >=0.0;");
|
||||
c.addSource("b", "import \"a\"; contract D { C c; } pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
}
|
||||
|
||||
@ -86,6 +92,7 @@ BOOST_AUTO_TEST_CASE(relative_import)
|
||||
c.addSource("a", "import \"./dir/b\"; contract A is B {} pragma solidity >=0.0;");
|
||||
c.addSource("dir/b", "contract B {} pragma solidity >=0.0;");
|
||||
c.addSource("dir/c", "import \"../a\"; contract C is A {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
}
|
||||
|
||||
@ -94,6 +101,7 @@ BOOST_AUTO_TEST_CASE(relative_import_multiplex)
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract A {} pragma solidity >=0.0;");
|
||||
c.addSource("dir/a/b/c", "import \"../../.././a\"; contract B is A {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
}
|
||||
|
||||
@ -102,6 +110,7 @@ BOOST_AUTO_TEST_CASE(simple_alias)
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract A {} pragma solidity >=0.0;");
|
||||
c.addSource("dir/a/b/c", "import \"../../.././a\" as x; contract B is x.A { function() { x.A r = x.A(20); } } pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
}
|
||||
|
||||
@ -111,6 +120,7 @@ BOOST_AUTO_TEST_CASE(library_name_clash)
|
||||
c.addSource("a", "library A {} pragma solidity >=0.0;");
|
||||
c.addSource("b", "library A {} pragma solidity >=0.0;");
|
||||
c.addSource("c", "import {A} from \"./a\"; import {A} from \"./b\";");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(!c.compile());
|
||||
}
|
||||
|
||||
@ -119,6 +129,7 @@ BOOST_AUTO_TEST_CASE(library_name_clash_with_contract)
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract A {} pragma solidity >=0.0;");
|
||||
c.addSource("b", "library A {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
}
|
||||
|
||||
@ -128,6 +139,7 @@ BOOST_AUTO_TEST_CASE(complex_import)
|
||||
c.addSource("a", "contract A {} contract B {} contract C { struct S { uint a; } } pragma solidity >=0.0;");
|
||||
c.addSource("b", "import \"a\" as x; import {B as b, C as c, C} from \"a\"; "
|
||||
"contract D is b { function f(c.S var1, x.C.S var2, C.S var3) internal {} } pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
}
|
||||
|
||||
@ -136,14 +148,19 @@ BOOST_AUTO_TEST_CASE(name_clash_in_import)
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract A {} pragma solidity >=0.0;");
|
||||
c.addSource("b", "import \"a\"; contract A {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(!c.compile());
|
||||
c.addSource("b", "import \"a\" as A; contract A {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(!c.compile());
|
||||
c.addSource("b", "import {A as b} from \"a\"; contract b {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(!c.compile());
|
||||
c.addSource("b", "import {A} from \"a\"; contract A {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(!c.compile());
|
||||
c.addSource("b", "import {A} from \"a\"; contract B {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
}
|
||||
|
||||
@ -155,6 +172,7 @@ BOOST_AUTO_TEST_CASE(remappings)
|
||||
c.addSource("b", "import \"t/tee.sol\"; contract A is Tee {} pragma solidity >=0.0;");
|
||||
c.addSource("s_1.4.6/s.sol", "contract S {} pragma solidity >=0.0;");
|
||||
c.addSource("Tee/tee.sol", "contract Tee {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
}
|
||||
|
||||
@ -166,6 +184,7 @@ BOOST_AUTO_TEST_CASE(context_dependent_remappings)
|
||||
c.addSource("b/b.sol", "import \"s/s.sol\"; contract B is SSeven {} pragma solidity >=0.0;");
|
||||
c.addSource("s_1.4.6/s.sol", "contract SSix {} pragma solidity >=0.0;");
|
||||
c.addSource("s_1.4.7/s.sol", "contract SSeven {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
}
|
||||
|
||||
@ -174,6 +193,7 @@ BOOST_AUTO_TEST_CASE(filename_with_period)
|
||||
CompilerStack c;
|
||||
c.addSource("a/a.sol", "import \".b.sol\"; contract A is B {} pragma solidity >=0.0;");
|
||||
c.addSource("a/.b.sol", "contract B {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(!c.compile());
|
||||
}
|
||||
|
||||
@ -185,6 +205,7 @@ BOOST_AUTO_TEST_CASE(context_dependent_remappings_ensure_default_and_module_pres
|
||||
c.addSource("vendor/bar/bar.sol", "import \"foo/foo.sol\"; contract Bar {Foo1 foo;} pragma solidity >=0.0;");
|
||||
c.addSource("vendor/foo_1.0.0/foo.sol", "contract Foo1 {} pragma solidity >=0.0;");
|
||||
c.addSource("vendor/foo_2.0.0/foo.sol", "contract Foo2 {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
}
|
||||
|
||||
@ -196,6 +217,7 @@ BOOST_AUTO_TEST_CASE(context_dependent_remappings_order_independent)
|
||||
c.addSource("a/b/main.sol", "import \"x/y/z/z.sol\"; contract Main is E {} pragma solidity >=0.0;");
|
||||
c.addSource("d/z.sol", "contract D {} pragma solidity >=0.0;");
|
||||
c.addSource("e/y/z/z.sol", "contract E {} pragma solidity >=0.0;");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
CompilerStack d;
|
||||
d.setRemappings(vector<string>{"a/b:x=e", "a:x/y/z=d"});
|
||||
@ -203,6 +225,7 @@ BOOST_AUTO_TEST_CASE(context_dependent_remappings_order_independent)
|
||||
d.addSource("a/b/main.sol", "import \"x/y/z/z.sol\"; contract Main is E {} pragma solidity >=0.0;");
|
||||
d.addSource("d/z.sol", "contract D {} pragma solidity >=0.0;");
|
||||
d.addSource("e/y/z/z.sol", "contract E {} pragma solidity >=0.0;");
|
||||
d.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(d.compile());
|
||||
}
|
||||
|
||||
@ -212,6 +235,7 @@ BOOST_AUTO_TEST_CASE(shadowing_via_import)
|
||||
c.addSource("a", "library A {} pragma solidity >=0.0;");
|
||||
c.addSource("b", "library A {} pragma solidity >=0.0;");
|
||||
c.addSource("c", "import {A} from \"./a\"; import {A} from \"./b\";");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(!c.compile());
|
||||
}
|
||||
|
||||
@ -225,6 +249,7 @@ BOOST_AUTO_TEST_CASE(shadowing_builtins_with_imports)
|
||||
contract C {
|
||||
}
|
||||
)");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
size_t errorCount = 0;
|
||||
for (auto const& e: c.errors())
|
||||
@ -251,6 +276,7 @@ BOOST_AUTO_TEST_CASE(shadowing_builtins_with_multiple_imports)
|
||||
contract C {
|
||||
}
|
||||
)");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
auto numErrors = c.errors().size();
|
||||
// Sometimes we get the prerelease warning, sometimes not.
|
||||
@ -274,6 +300,7 @@ BOOST_AUTO_TEST_CASE(shadowing_builtins_with_alias)
|
||||
pragma solidity >=0.0;
|
||||
import {C as msg} from "B.sol";
|
||||
)");
|
||||
c.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(c.compile());
|
||||
auto numErrors = c.errors().size();
|
||||
// Sometimes we get the prerelease warning, sometimes not.
|
||||
|
@ -55,7 +55,7 @@ boost::optional<Error> parseAndReturnFirstError(
|
||||
AssemblyStack::Machine _machine = AssemblyStack::Machine::EVM
|
||||
)
|
||||
{
|
||||
AssemblyStack stack(_language);
|
||||
AssemblyStack stack(dev::test::Options::get().evmVersion(), _language);
|
||||
bool success = false;
|
||||
try
|
||||
{
|
||||
@ -117,7 +117,7 @@ Error expectError(
|
||||
|
||||
void parsePrintCompare(string const& _source, bool _canWarn = false)
|
||||
{
|
||||
AssemblyStack stack;
|
||||
AssemblyStack stack(dev::test::Options::get().evmVersion());
|
||||
BOOST_REQUIRE(stack.parseAndAnalyze("", _source));
|
||||
if (_canWarn)
|
||||
BOOST_REQUIRE(Error::containsOnlyWarnings(stack.errors()));
|
||||
@ -567,7 +567,7 @@ BOOST_AUTO_TEST_CASE(print_string_literal_unicode)
|
||||
{
|
||||
string source = "{ let x := \"\\u1bac\" }";
|
||||
string parsed = "{\n let x := \"\\xe1\\xae\\xac\"\n}";
|
||||
AssemblyStack stack;
|
||||
AssemblyStack stack(dev::test::Options::get().evmVersion());
|
||||
BOOST_REQUIRE(stack.parseAndAnalyze("", source));
|
||||
BOOST_REQUIRE(stack.errors().empty());
|
||||
BOOST_CHECK_EQUAL(stack.print(), parsed);
|
||||
@ -783,9 +783,9 @@ BOOST_AUTO_TEST_CASE(shift)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(shift_constantinople_warning)
|
||||
{
|
||||
CHECK_PARSE_WARNING("{ pop(shl(10, 32)) }", Warning, "The \"shl\" instruction is only available after the Constantinople hard fork");
|
||||
CHECK_PARSE_WARNING("{ pop(shr(10, 32)) }", Warning, "The \"shr\" instruction is only available after the Constantinople hard fork");
|
||||
CHECK_PARSE_WARNING("{ pop(sar(10, 32)) }", Warning, "The \"sar\" instruction is only available after the Constantinople hard fork");
|
||||
CHECK_PARSE_WARNING("{ pop(shl(10, 32)) }", Warning, "The \"shl\" instruction is only available for Constantinople-compatible VMs.");
|
||||
CHECK_PARSE_WARNING("{ pop(shr(10, 32)) }", Warning, "The \"shr\" instruction is only available for Constantinople-compatible VMs.");
|
||||
CHECK_PARSE_WARNING("{ pop(sar(10, 32)) }", Warning, "The \"sar\" instruction is only available for Constantinople-compatible VMs.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(jump_warning)
|
||||
|
@ -46,6 +46,7 @@ BOOST_AUTO_TEST_CASE(metadata_stamp)
|
||||
)";
|
||||
CompilerStack compilerStack;
|
||||
compilerStack.addSource("", std::string(sourceCode));
|
||||
compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
compilerStack.setOptimiserSettings(dev::test::Options::get().optimize);
|
||||
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");
|
||||
bytes const& bytecode = compilerStack.runtimeObject("test").bytecode;
|
||||
@ -72,6 +73,7 @@ BOOST_AUTO_TEST_CASE(metadata_stamp_experimental)
|
||||
)";
|
||||
CompilerStack compilerStack;
|
||||
compilerStack.addSource("", std::string(sourceCode));
|
||||
compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
compilerStack.setOptimiserSettings(dev::test::Options::get().optimize);
|
||||
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");
|
||||
bytes const& bytecode = compilerStack.runtimeObject("test").bytecode;
|
||||
@ -106,6 +108,7 @@ BOOST_AUTO_TEST_CASE(metadata_relevant_sources)
|
||||
}
|
||||
)";
|
||||
compilerStack.addSource("B", std::string(sourceCode));
|
||||
compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
compilerStack.setOptimiserSettings(dev::test::Options::get().optimize);
|
||||
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");
|
||||
|
||||
@ -144,6 +147,7 @@ BOOST_AUTO_TEST_CASE(metadata_relevant_sources_imports)
|
||||
}
|
||||
)";
|
||||
compilerStack.addSource("C", std::string(sourceCode));
|
||||
compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
compilerStack.setOptimiserSettings(dev::test::Options::get().optimize);
|
||||
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");
|
||||
|
||||
|
@ -44,6 +44,8 @@ public:
|
||||
{
|
||||
m_compilerStack.reset(false);
|
||||
m_compilerStack.addSource("", "pragma solidity >=0.0;\n" + _code);
|
||||
m_compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
m_compilerStack.setOptimiserSettings(dev::test::Options::get().optimize);
|
||||
BOOST_REQUIRE_MESSAGE(m_compilerStack.parseAndAnalyze(), "Parsing contract failed");
|
||||
|
||||
Json::Value generatedInterface = m_compilerStack.contractABI(m_compilerStack.lastContractName());
|
||||
|
@ -68,6 +68,7 @@ public:
|
||||
m_compiler.reset(false);
|
||||
m_compiler.addSource("", sourceCode);
|
||||
m_compiler.setLibraries(_libraryAddresses);
|
||||
m_compiler.setEVMVersion(m_evmVersion);
|
||||
m_compiler.setOptimiserSettings(m_optimize, m_optimizeRuns);
|
||||
if (!m_compiler.compile())
|
||||
{
|
||||
|
@ -132,7 +132,7 @@ bytes compileFirstExpression(
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
ErrorReporter errorReporter(errors);
|
||||
TypeChecker typeChecker(errorReporter);
|
||||
TypeChecker typeChecker(dev::test::Options::get().evmVersion(), errorReporter);
|
||||
BOOST_REQUIRE(typeChecker.checkTypeRequirements(*contract));
|
||||
}
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
@ -141,7 +141,7 @@ bytes compileFirstExpression(
|
||||
FirstExpressionExtractor extractor(*contract);
|
||||
BOOST_REQUIRE(extractor.expression() != nullptr);
|
||||
|
||||
CompilerContext context;
|
||||
CompilerContext context(dev::test::Options::get().evmVersion());
|
||||
context.resetVisitedNodes(contract);
|
||||
context.setInheritanceHierarchy(inheritanceHierarchy);
|
||||
unsigned parametersSize = _localVariables.size(); // assume they are all one slot on the stack
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#include <test/libsolidity/AnalysisFramework.h>
|
||||
|
||||
#include <test/TestHelper.h>
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
|
||||
#include <libdevcore/SHA3.h>
|
||||
@ -7100,11 +7102,13 @@ BOOST_AUTO_TEST_CASE(returndatacopy_as_variable)
|
||||
char const* text = R"(
|
||||
contract c { function f() public { uint returndatasize; assembly { returndatasize }}}
|
||||
)";
|
||||
CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
|
||||
vector<pair<Error::Type, std::string>> expectations(vector<pair<Error::Type, std::string>>{
|
||||
{Error::Type::Warning, "Variable is shadowed in inline assembly by an instruction of the same name"},
|
||||
{Error::Type::DeclarationError, "Unbalanced stack"},
|
||||
{Error::Type::Warning, "only available after the Metropolis"}
|
||||
}));
|
||||
{Error::Type::DeclarationError, "Unbalanced stack"}
|
||||
});
|
||||
if (!dev::test::Options::get().evmVersion().supportsReturndata())
|
||||
expectations.emplace_back(make_pair(Error::Type::Warning, std::string("\"returndatasize\" instruction is only available for Byzantium-compatible")));
|
||||
CHECK_ALLOW_MULTI(text, expectations);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(create2_as_variable)
|
||||
@ -7114,7 +7118,7 @@ BOOST_AUTO_TEST_CASE(create2_as_variable)
|
||||
)";
|
||||
CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
|
||||
{Error::Type::Warning, "Variable is shadowed in inline assembly by an instruction of the same name"},
|
||||
{Error::Type::Warning, "only available after the Metropolis"},
|
||||
{Error::Type::Warning, "The \"create2\" instruction is not supported by the VM version"},
|
||||
{Error::Type::DeclarationError, "Unbalanced stack"}
|
||||
}));
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ public:
|
||||
{
|
||||
m_compilerStack.reset(false);
|
||||
m_compilerStack.addSource("", "pragma solidity >=0.0;\n" + _code);
|
||||
m_compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_REQUIRE_MESSAGE(m_compilerStack.parseAndAnalyze(), "Parsing contract failed");
|
||||
|
||||
Json::Value generatedDocumentation;
|
||||
@ -67,6 +68,7 @@ public:
|
||||
{
|
||||
m_compilerStack.reset(false);
|
||||
m_compilerStack.addSource("", "pragma solidity >=0.0;\n" + _code);
|
||||
m_compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
BOOST_CHECK(!m_compilerStack.parseAndAnalyze());
|
||||
BOOST_REQUIRE(Error::containsErrorOfType(m_compilerStack.errors(), Error::Type::DocstringParsingError));
|
||||
}
|
||||
|
@ -724,6 +724,43 @@ BOOST_AUTO_TEST_CASE(library_linking)
|
||||
BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["library2.sol"]["L2"][0].isObject());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(evm_version)
|
||||
{
|
||||
auto inputForVersion = [](string const& _version)
|
||||
{
|
||||
return R"(
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources": { "fileA": { "content": "contract A { }" } },
|
||||
"settings": {
|
||||
)" + _version + R"(
|
||||
"outputSelection": {
|
||||
"fileA": {
|
||||
"A": [ "metadata" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)";
|
||||
};
|
||||
Json::Value result;
|
||||
result = compile(inputForVersion("\"evmVersion\": \"homestead\","));
|
||||
BOOST_CHECK(result["contracts"]["fileA"]["A"]["metadata"].asString().find("\"evmVersion\":\"homestead\"") != string::npos);
|
||||
result = compile(inputForVersion("\"evmVersion\": \"tangerineWhistle\","));
|
||||
BOOST_CHECK(result["contracts"]["fileA"]["A"]["metadata"].asString().find("\"evmVersion\":\"tangerineWhistle\"") != string::npos);
|
||||
result = compile(inputForVersion("\"evmVersion\": \"spuriousDragon\","));
|
||||
BOOST_CHECK(result["contracts"]["fileA"]["A"]["metadata"].asString().find("\"evmVersion\":\"spuriousDragon\"") != string::npos);
|
||||
result = compile(inputForVersion("\"evmVersion\": \"byzantium\","));
|
||||
BOOST_CHECK(result["contracts"]["fileA"]["A"]["metadata"].asString().find("\"evmVersion\":\"byzantium\"") != string::npos);
|
||||
// test default
|
||||
result = compile(inputForVersion(""));
|
||||
BOOST_CHECK(result["contracts"]["fileA"]["A"]["metadata"].asString().find("\"evmVersion\":\"byzantium\"") != string::npos);
|
||||
// test invalid
|
||||
result = compile(inputForVersion("\"evmVersion\": \"invalid\","));
|
||||
BOOST_CHECK(result["errors"][0]["message"].asString() == "Invalid EVM version requested.");
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
@ -20,6 +20,8 @@
|
||||
|
||||
#include <test/libsolidity/AnalysisFramework.h>
|
||||
|
||||
#include <test/TestHelper.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <string>
|
||||
@ -423,7 +425,10 @@ BOOST_AUTO_TEST_CASE(assembly_staticcall)
|
||||
}
|
||||
}
|
||||
)";
|
||||
CHECK_WARNING(text, "only available after the Metropolis");
|
||||
if (!dev::test::Options::get().evmVersion().hasStaticCall())
|
||||
CHECK_WARNING(text, "\"staticcall\" instruction is only available for Byzantium-compatible");
|
||||
else
|
||||
CHECK_SUCCESS_NO_WARNINGS(text);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(assembly_jump)
|
||||
|
Loading…
Reference in New Issue
Block a user