Merge pull request #3569 from ethereum/evmVersion

EVM version
This commit is contained in:
chriseth
2018-03-05 12:10:49 +01:00
committed by GitHub
65 changed files with 773 additions and 294 deletions
+2 -1
View File
@@ -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;
}
+1
View File
@@ -875,6 +875,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
assembly::AsmAnalyzer analyzer(
*_inlineAssembly.annotation().analysisInfo,
m_errorReporter,
m_evmVersion,
assembly::AsmFlavour::Loose,
identifierAccess
);
+8 -1
View File
@@ -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;
+8 -5
View File
@@ -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.
+1
View File
@@ -329,6 +329,7 @@ void CompilerContext::appendInlineAssembly(
analyzerResult = assembly::AsmAnalyzer(
analysisInfo,
errorReporter,
m_evmVersion,
assembly::AsmFlavour::Strict,
identifierAccess.resolve
).analyze(*parserResult);
+9 -2
View File
@@ -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.
+2 -2
View File
@@ -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;
+2 -2
View File
@@ -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.
+1 -1
View File
@@ -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)
+36 -22
View File
@@ -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)
+4 -1
View File
@@ -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;
};
+1 -1
View File
@@ -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;
}
+5 -2
View File
@@ -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;
+16 -7
View File
@@ -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);
+18 -9
View File
@@ -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
View 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;
};
}
}
+6 -6
View File
@@ -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(
+14 -8
View File
@@ -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());