diff options
Diffstat (limited to 'libsolidity/interface')
-rw-r--r-- | libsolidity/interface/CompilerStack.cpp | 90 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.h | 17 | ||||
-rw-r--r-- | libsolidity/interface/ReadFile.h | 45 | ||||
-rw-r--r-- | libsolidity/interface/SourceReferenceFormatter.h | 11 |
4 files changed, 150 insertions, 13 deletions
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index effc8309..92b49cda 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -38,6 +38,7 @@ #include <libsolidity/analysis/SyntaxChecker.h> #include <libsolidity/codegen/Compiler.h> #include <libsolidity/interface/InterfaceHandler.h> +#include <libsolidity/interface/GasEstimator.h> #include <libsolidity/formal/Why3Translator.h> #include <libevmasm/Exceptions.h> @@ -55,7 +56,7 @@ using namespace std; using namespace dev; using namespace dev::solidity; -CompilerStack::CompilerStack(ReadFileCallback const& _readFile): +CompilerStack::CompilerStack(ReadFile::Callback const& _readFile): m_readFile(_readFile), m_parseSuccessful(false) {} void CompilerStack::setRemappings(vector<string> const& _remappings) @@ -522,7 +523,7 @@ StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string if (m_sources.count(importPath) || newSources.count(importPath)) continue; - ReadFileResult result{false, string("File not supplied initially.")}; + ReadFile::Result result{false, string("File not supplied initially.")}; if (m_readFile) result = m_readFile(importPath); @@ -841,3 +842,88 @@ string CompilerStack::computeSourceMapping(eth::AssemblyItems const& _items) con } return ret; } + +namespace +{ + +Json::Value gasToJson(GasEstimator::GasConsumption const& _gas) +{ + if (_gas.isInfinite) + return Json::Value("infinite"); + else + return Json::Value(toString(_gas.value)); +} + +} + +Json::Value CompilerStack::gasEstimates(string const& _contractName) const +{ + if (!assemblyItems(_contractName) && !runtimeAssemblyItems(_contractName)) + return Json::Value(); + + using Gas = GasEstimator::GasConsumption; + Json::Value output(Json::objectValue); + + if (eth::AssemblyItems const* items = assemblyItems(_contractName)) + { + Gas executionGas = GasEstimator::functionalEstimation(*items); + u256 bytecodeSize(runtimeObject(_contractName).bytecode.size()); + Gas codeDepositGas = bytecodeSize * eth::GasCosts::createDataGas; + + Json::Value creation(Json::objectValue); + creation["codeDepositCost"] = gasToJson(codeDepositGas); + creation["executionCost"] = gasToJson(executionGas); + /// TODO: implement + overload to avoid the need of += + executionGas += codeDepositGas; + creation["totalCost"] = gasToJson(executionGas); + output["creation"] = creation; + } + + if (eth::AssemblyItems const* items = runtimeAssemblyItems(_contractName)) + { + /// External functions + ContractDefinition const& contract = contractDefinition(_contractName); + Json::Value externalFunctions(Json::objectValue); + for (auto it: contract.interfaceFunctions()) + { + string sig = it.second->externalSignature(); + 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")); + + if (!externalFunctions.empty()) + output["external"] = externalFunctions; + + /// Internal functions + Json::Value internalFunctions(Json::objectValue); + for (auto const& it: contract.definedFunctions()) + { + /// Exclude externally visible functions, constructor and the fallback function + if (it->isPartOfExternalInterface() || it->isConstructor() || it->name().empty()) + continue; + + size_t entry = functionEntryPoint(_contractName, *it); + GasEstimator::GasConsumption gas = GasEstimator::GasConsumption::infinite(); + if (entry > 0) + gas = GasEstimator::functionalEstimation(*items, entry, *it); + + FunctionType type(*it); + string sig = it->name() + "("; + auto paramTypes = type.parameterTypes(); + for (auto it = paramTypes.begin(); it != paramTypes.end(); ++it) + sig += (*it)->toString() + (it + 1 == paramTypes.end() ? "" : ","); + sig += ")"; + internalFunctions[sig] = gasToJson(gas); + } + + if (!internalFunctions.empty()) + output["internal"] = internalFunctions; + } + + return output; +} diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 65850683..a34a34bb 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -36,6 +36,7 @@ #include <libevmasm/SourceLocation.h> #include <libevmasm/LinkerObject.h> #include <libsolidity/interface/Exceptions.h> +#include <libsolidity/interface/ReadFile.h> namespace dev { @@ -77,18 +78,9 @@ enum class DocumentationType: uint8_t class CompilerStack: boost::noncopyable { public: - struct ReadFileResult - { - bool success; - std::string contentsOrErrorMessage; - }; - - /// File reading callback. - using ReadFileCallback = std::function<ReadFileResult(std::string const&)>; - /// Creates a new compiler stack. /// @param _readFile callback to used to read files for import statements. Should return - explicit CompilerStack(ReadFileCallback const& _readFile = ReadFileCallback()); + explicit CompilerStack(ReadFile::Callback const& _readFile = ReadFile::Callback()); /// Sets path remappings in the format "context:prefix=target" void setRemappings(std::vector<std::string> const& _remappings); @@ -181,6 +173,9 @@ public: std::string const& onChainMetadata(std::string const& _contractName) const; void useMetadataLiteralSources(bool _metadataLiteralSources) { m_metadataLiteralSources = _metadataLiteralSources; } + /// @returns a JSON representing the estimated gas usage for contract creation, internal and external functions + Json::Value gasEstimates(std::string const& _contractName) const; + /// @returns the previously used scanner, useful for counting lines during error reporting. Scanner const& scanner(std::string const& _sourceName = "") const; /// @returns the parsed source unit with the supplied name. @@ -263,7 +258,7 @@ private: std::string target; }; - ReadFileCallback m_readFile; + ReadFile::Callback m_readFile; bool m_optimize = false; unsigned m_optimizeRuns = 200; std::map<std::string, h160> m_libraries; diff --git a/libsolidity/interface/ReadFile.h b/libsolidity/interface/ReadFile.h new file mode 100644 index 00000000..2e8a6bd8 --- /dev/null +++ b/libsolidity/interface/ReadFile.h @@ -0,0 +1,45 @@ +/* + 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/>. +*/ + +#pragma once + +#include <string> +#include <functional> +#include <boost/noncopyable.hpp> + +namespace dev +{ + +namespace solidity +{ + +class ReadFile: boost::noncopyable +{ +public: + /// File reading result. + struct Result + { + bool success; + std::string contentsOrErrorMessage; + }; + + /// File reading callback. + using Callback = std::function<Result(std::string const&)>; +}; + +} +} diff --git a/libsolidity/interface/SourceReferenceFormatter.h b/libsolidity/interface/SourceReferenceFormatter.h index 7034f4ab..e8676d60 100644 --- a/libsolidity/interface/SourceReferenceFormatter.h +++ b/libsolidity/interface/SourceReferenceFormatter.h @@ -23,6 +23,7 @@ #pragma once #include <ostream> +#include <sstream> #include <functional> #include <libevmasm/SourceLocation.h> @@ -53,6 +54,16 @@ public: std::string const& _name, ScannerFromSourceNameFun const& _scannerFromSourceName ); + static std::string formatExceptionInformation( + Exception const& _exception, + std::string const& _name, + ScannerFromSourceNameFun const& _scannerFromSourceName + ) + { + std::ostringstream errorOutput; + printExceptionInformation(errorOutput, _exception, _name, _scannerFromSourceName); + return errorOutput.str(); + } private: /// Prints source name if location is given. static void printSourceName( |