From 12328b784875bad30156a2c66912652f89fa8222 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 10 May 2017 10:54:23 +0100 Subject: Split ABI out of InterfaceHandler --- libsolidity/interface/ABI.cpp | 116 +++++++++++++++++++++++++++++ libsolidity/interface/ABI.h | 56 ++++++++++++++ libsolidity/interface/CompilerStack.cpp | 17 +++-- libsolidity/interface/CompilerStack.h | 6 +- libsolidity/interface/InterfaceHandler.cpp | 115 ++++++---------------------- libsolidity/interface/InterfaceHandler.h | 7 +- 6 files changed, 212 insertions(+), 105 deletions(-) create mode 100644 libsolidity/interface/ABI.cpp create mode 100644 libsolidity/interface/ABI.h (limited to 'libsolidity') diff --git a/libsolidity/interface/ABI.cpp b/libsolidity/interface/ABI.cpp new file mode 100644 index 00000000..12f958fc --- /dev/null +++ b/libsolidity/interface/ABI.cpp @@ -0,0 +1,116 @@ +/* + 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 . +*/ +/** + * Utilities to handle the Contract ABI (https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) + */ + +#include +#include +#include + +using namespace std; +using namespace dev; +using namespace dev::solidity; + +Json::Value ABI::generate(ContractDefinition const& _contractDef) +{ + Json::Value abi(Json::arrayValue); + + for (auto it: _contractDef.interfaceFunctions()) + { + auto externalFunctionType = it.second->interfaceFunctionType(); + Json::Value method; + method["type"] = "function"; + method["name"] = it.second->declaration().name(); + method["constant"] = it.second->isConstant(); + method["payable"] = it.second->isPayable(); + method["inputs"] = formatTypeList( + externalFunctionType->parameterNames(), + externalFunctionType->parameterTypes(), + _contractDef.isLibrary() + ); + method["outputs"] = formatTypeList( + externalFunctionType->returnParameterNames(), + externalFunctionType->returnParameterTypes(), + _contractDef.isLibrary() + ); + abi.append(method); + } + if (_contractDef.constructor()) + { + Json::Value method; + method["type"] = "constructor"; + auto externalFunction = FunctionType(*_contractDef.constructor(), false).interfaceFunctionType(); + solAssert(!!externalFunction, ""); + method["payable"] = externalFunction->isPayable(); + method["inputs"] = formatTypeList( + externalFunction->parameterNames(), + externalFunction->parameterTypes(), + _contractDef.isLibrary() + ); + abi.append(method); + } + if (_contractDef.fallbackFunction()) + { + auto externalFunctionType = FunctionType(*_contractDef.fallbackFunction(), false).interfaceFunctionType(); + solAssert(!!externalFunctionType, ""); + Json::Value method; + method["type"] = "fallback"; + method["payable"] = externalFunctionType->isPayable(); + abi.append(method); + } + for (auto const& it: _contractDef.interfaceEvents()) + { + Json::Value event; + event["type"] = "event"; + event["name"] = it->name(); + event["anonymous"] = it->isAnonymous(); + Json::Value params(Json::arrayValue); + for (auto const& p: it->parameters()) + { + solAssert(!!p->annotation().type->interfaceType(false), ""); + Json::Value input; + input["name"] = p->name(); + input["type"] = p->annotation().type->interfaceType(false)->canonicalName(false); + input["indexed"] = p->isIndexed(); + params.append(input); + } + event["inputs"] = params; + abi.append(event); + } + + return abi; +} + +Json::Value ABI::formatTypeList( + vector const& _names, + vector const& _types, + bool _forLibrary +) +{ + Json::Value params(Json::arrayValue); + solAssert(_names.size() == _types.size(), "Names and types vector size does not match"); + for (unsigned i = 0; i < _names.size(); ++i) + { + solAssert(_types[i], ""); + Json::Value param; + param["name"] = _names[i]; + param["type"] = _types[i]->canonicalName(_forLibrary); + params.append(param); + } + return params; +} diff --git a/libsolidity/interface/ABI.h b/libsolidity/interface/ABI.h new file mode 100644 index 00000000..95b162a9 --- /dev/null +++ b/libsolidity/interface/ABI.h @@ -0,0 +1,56 @@ +/* + 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 . +*/ +/** + * Utilities to handle the Contract ABI (https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) + */ + +#pragma once + +#include +#include +#include + +namespace dev +{ +namespace solidity +{ + +// Forward declarations +class ContractDefinition; +class Type; +using TypePointer = std::shared_ptr; + +class ABI +{ +public: + /// Get the ABI Interface of the contract + /// @param _contractDef The contract definition + /// @return A JSONrepresentation of the contract's ABI Interface + static Json::Value generate(ContractDefinition const& _contractDef); +private: + /// @returns a json value suitable for a list of types in function input or output + /// parameters or other places. If @a _forLibrary is true, complex types are referenced + /// by name, otherwise they are anonymously expanded. + static Json::Value formatTypeList( + std::vector const& _names, + std::vector const& _types, + bool _forLibrary + ); +}; + +} +} diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 1f235656..4b57b34c 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -446,12 +447,21 @@ map CompilerStack::sourceIndices() const Json::Value const& CompilerStack::contractABI(string const& _contractName) const { - return metadata(_contractName, DocumentationType::ABIInterface); + return contractABI(contract(_contractName)); } Json::Value const& CompilerStack::contractABI(Contract const& _contract) const { - return metadata(_contract, DocumentationType::ABIInterface); + if (m_stackState < AnalysisSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + + solAssert(_contract.contract, ""); + + // caches the result + if (!_contract.abi) + _contract.abi.reset(new Json::Value(ABI::generate(*_contract.contract))); + + return *_contract.abi; } Json::Value const& CompilerStack::metadata(string const& _contractName, DocumentationType _type) const @@ -476,9 +486,6 @@ Json::Value const& CompilerStack::metadata(Contract const& _contract, Documentat case DocumentationType::NatspecDev: doc = &_contract.devDocumentation; break; - case DocumentationType::ABIInterface: - doc = &_contract.interface; - break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type.")); } diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index e98c3b82..dd8d671e 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -66,8 +66,7 @@ class DeclarationContainer; enum class DocumentationType: uint8_t { NatspecUser = 1, - NatspecDev, - ABIInterface + NatspecDev }; /** @@ -230,7 +229,7 @@ private: eth::LinkerObject runtimeObject; eth::LinkerObject cloneObject; std::string onChainMetadata; ///< The metadata json that will be hashed into the chain. - mutable std::unique_ptr interface; + mutable std::unique_ptr abi; mutable std::unique_ptr userDocumentation; mutable std::unique_ptr devDocumentation; mutable std::unique_ptr sourceMapping; @@ -267,6 +266,7 @@ private: std::string createOnChainMetadata(Contract const& _contract) const; std::string computeSourceMapping(eth::AssemblyItems const& _items) const; + Json::Value const& contractABI(Contract const&) const; Json::Value const& metadata(Contract const&, DocumentationType _type) const; struct Remapping diff --git a/libsolidity/interface/InterfaceHandler.cpp b/libsolidity/interface/InterfaceHandler.cpp index 6c1bb0c4..b73cf46e 100644 --- a/libsolidity/interface/InterfaceHandler.cpp +++ b/libsolidity/interface/InterfaceHandler.cpp @@ -1,3 +1,27 @@ +/* + 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 . +*/ +/** + * @author Lefteris + * @date 2014 + * Takes the parsed AST and produces the Natspec documentation: + * https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format + * + * Can generally deal with JSON files + */ #include #include @@ -19,83 +43,11 @@ Json::Value InterfaceHandler::documentation( return userDocumentation(_contractDef); case DocumentationType::NatspecDev: return devDocumentation(_contractDef); - case DocumentationType::ABIInterface: - return abiInterface(_contractDef); } BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown documentation type")); } -Json::Value InterfaceHandler::abiInterface(ContractDefinition const& _contractDef) -{ - Json::Value abi(Json::arrayValue); - - for (auto it: _contractDef.interfaceFunctions()) - { - auto externalFunctionType = it.second->interfaceFunctionType(); - Json::Value method; - method["type"] = "function"; - method["name"] = it.second->declaration().name(); - method["constant"] = it.second->isConstant(); - method["payable"] = it.second->isPayable(); - method["inputs"] = formatTypeList( - externalFunctionType->parameterNames(), - externalFunctionType->parameterTypes(), - _contractDef.isLibrary() - ); - method["outputs"] = formatTypeList( - externalFunctionType->returnParameterNames(), - externalFunctionType->returnParameterTypes(), - _contractDef.isLibrary() - ); - abi.append(method); - } - if (_contractDef.constructor()) - { - Json::Value method; - method["type"] = "constructor"; - auto externalFunction = FunctionType(*_contractDef.constructor(), false).interfaceFunctionType(); - solAssert(!!externalFunction, ""); - method["payable"] = externalFunction->isPayable(); - method["inputs"] = formatTypeList( - externalFunction->parameterNames(), - externalFunction->parameterTypes(), - _contractDef.isLibrary() - ); - abi.append(method); - } - if (_contractDef.fallbackFunction()) - { - auto externalFunctionType = FunctionType(*_contractDef.fallbackFunction(), false).interfaceFunctionType(); - solAssert(!!externalFunctionType, ""); - Json::Value method; - method["type"] = "fallback"; - method["payable"] = externalFunctionType->isPayable(); - abi.append(method); - } - for (auto const& it: _contractDef.interfaceEvents()) - { - Json::Value event; - event["type"] = "event"; - event["name"] = it->name(); - event["anonymous"] = it->isAnonymous(); - Json::Value params(Json::arrayValue); - for (auto const& p: it->parameters()) - { - solAssert(!!p->annotation().type->interfaceType(false), ""); - Json::Value input; - input["name"] = p->name(); - input["type"] = p->annotation().type->interfaceType(false)->canonicalName(false); - input["indexed"] = p->isIndexed(); - params.append(input); - } - event["inputs"] = params; - abi.append(event); - } - - return abi; -} - Json::Value InterfaceHandler::userDocumentation(ContractDefinition const& _contractDef) { Json::Value doc; @@ -168,25 +120,6 @@ Json::Value InterfaceHandler::devDocumentation(ContractDefinition const& _contra return doc; } -Json::Value InterfaceHandler::formatTypeList( - vector const& _names, - vector const& _types, - bool _forLibrary -) -{ - Json::Value params(Json::arrayValue); - solAssert(_names.size() == _types.size(), "Names and types vector size does not match"); - for (unsigned i = 0; i < _names.size(); ++i) - { - solAssert(_types[i], ""); - Json::Value param; - param["name"] = _names[i]; - param["type"] = _types[i]->canonicalName(_forLibrary); - params.append(param); - } - return params; -} - string InterfaceHandler::extractDoc(multimap const& _tags, string const& _name) { string value; diff --git a/libsolidity/interface/InterfaceHandler.h b/libsolidity/interface/InterfaceHandler.h index 56927d44..883ef3b9 100644 --- a/libsolidity/interface/InterfaceHandler.h +++ b/libsolidity/interface/InterfaceHandler.h @@ -17,8 +17,7 @@ /** * @author Lefteris * @date 2014 - * Takes the parsed AST and produces the Natspec - * documentation and the ABI interface + * Takes the parsed AST and produces the Natspec documentation: * https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format * * Can generally deal with JSON files @@ -71,10 +70,6 @@ public: ContractDefinition const& _contractDef, DocumentationType _type ); - /// Get the ABI Interface of the contract - /// @param _contractDef The contract definition - /// @return A JSONrepresentation of the contract's ABI Interface - static Json::Value abiInterface(ContractDefinition const& _contractDef); /// Get the User documentation of the contract /// @param _contractDef The contract definition /// @return A JSON representation of the contract's user documentation -- cgit v1.2.3