From 5789eaa78d0e00f6289101e02f7de5e9decdc7e5 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 14 Nov 2016 11:46:43 +0100 Subject: Metadata stamp. --- libsolidity/interface/CompilerStack.cpp | 98 +++++++++++++++++++++++++++------ libsolidity/interface/CompilerStack.h | 20 +++++-- 2 files changed, 94 insertions(+), 24 deletions(-) (limited to 'libsolidity/interface') diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 9305c5e3..ed44b109 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -38,7 +38,10 @@ #include #include -#include + +#include + +#include #include #include @@ -79,6 +82,8 @@ void CompilerStack::reset(bool _keepSources) { m_sources.clear(); } + m_optimize = false; + m_optimizeRuns = 200; m_globalContext.reset(); m_sourceOrder.clear(); m_contracts.clear(); @@ -217,17 +222,22 @@ vector CompilerStack::contractNames() const } -bool CompilerStack::compile(bool _optimize, unsigned _runs) +bool CompilerStack::compile(bool _optimize, unsigned _runs, map const& _libraries) { if (!m_parseSuccessful) if (!parse()) return false; + m_optimize = _optimize; + m_optimizeRuns = _runs; + m_libraries = _libraries; + map compiledContracts; for (Source const* source: m_sourceOrder) for (ASTPointer const& node: source->ast->nodes()) if (auto contract = dynamic_cast(node.get())) - compileContract(_optimize, _runs, *contract, compiledContracts); + compileContract(*contract, compiledContracts); + this->link(); return true; } @@ -236,13 +246,13 @@ bool CompilerStack::compile(string const& _sourceCode, bool _optimize) return parse(_sourceCode) && compile(_optimize); } -void CompilerStack::link(const std::map& _libraries) +void CompilerStack::link() { for (auto& contract: m_contracts) { - contract.second.object.link(_libraries); - contract.second.runtimeObject.link(_libraries); - contract.second.cloneObject.link(_libraries); + contract.second.object.link(m_libraries); + contract.second.runtimeObject.link(m_libraries); + contract.second.cloneObject.link(m_libraries); } } @@ -352,24 +362,31 @@ Json::Value const& CompilerStack::interface(string const& _contractName) const } Json::Value const& CompilerStack::metadata(string const& _contractName, DocumentationType _type) const +{ + if (!m_parseSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + + return metadata(contract(_contractName), _type); +} + +Json::Value const& CompilerStack::metadata(Contract const& _contract, DocumentationType _type) const { if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); std::unique_ptr* doc; - Contract const& currentContract = contract(_contractName); // checks wheather we already have the documentation switch (_type) { case DocumentationType::NatspecUser: - doc = ¤tContract.userDocumentation; + doc = &_contract.userDocumentation; break; case DocumentationType::NatspecDev: - doc = ¤tContract.devDocumentation; + doc = &_contract.devDocumentation; break; case DocumentationType::ABIInterface: - doc = ¤tContract.interface; + doc = &_contract.interface; break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type.")); @@ -377,11 +394,19 @@ Json::Value const& CompilerStack::metadata(string const& _contractName, Document // caches the result if (!*doc) - doc->reset(new Json::Value(InterfaceHandler::documentation(*currentContract.contract, _type))); + doc->reset(new Json::Value(InterfaceHandler::documentation(*_contract.contract, _type))); return *(*doc); } +string const& CompilerStack::onChainMetadata(string const& _contractName) const +{ + if (!m_parseSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + + return contract(_contractName).onChainMetadata; +} + Scanner const& CompilerStack::scanner(string const& _sourceName) const { return *source(_sourceName).scanner; @@ -572,8 +597,6 @@ string CompilerStack::absolutePath(string const& _path, string const& _reference } void CompilerStack::compileContract( - bool _optimize, - unsigned _runs, ContractDefinition const& _contract, map& _compiledContracts ) @@ -581,19 +604,21 @@ void CompilerStack::compileContract( if (_compiledContracts.count(&_contract) || !_contract.annotation().isFullyImplemented) return; for (auto const* dependency: _contract.annotation().contractDependencies) - compileContract(_optimize, _runs, *dependency, _compiledContracts); + compileContract(*dependency, _compiledContracts); - shared_ptr compiler = make_shared(_optimize, _runs); - compiler->compileContract(_contract, _compiledContracts); + shared_ptr compiler = make_shared(m_optimize, m_optimizeRuns); Contract& compiledContract = m_contracts.at(_contract.name()); + string onChainMetadata = createOnChainMetadata(compiledContract); + compiler->compileContract(_contract, _compiledContracts, dev::swarmHash(onChainMetadata)); compiledContract.compiler = compiler; compiledContract.object = compiler->assembledObject(); compiledContract.runtimeObject = compiler->runtimeObject(); + compiledContract.onChainMetadata = onChainMetadata; _compiledContracts[compiledContract.contract] = &compiler->assembly(); try { - Compiler cloneCompiler(_optimize, _runs); + Compiler cloneCompiler(m_optimize, m_optimizeRuns); cloneCompiler.compileClone(_contract, _compiledContracts); compiledContract.cloneObject = cloneCompiler.assembledObject(); } @@ -637,6 +662,43 @@ CompilerStack::Source const& CompilerStack::source(string const& _sourceName) co return it->second; } +string CompilerStack::createOnChainMetadata(Contract const& _contract) const +{ + Json::Value meta; + meta["version"] = 1; + meta["language"] = "Solidity"; + meta["compiler"]["version"] = VersionString; + meta["compilationTarget"] = + _contract.contract->sourceUnitName() + + ":" + + _contract.contract->annotation().canonicalName; + + for (auto const& s: m_sources) + { + solAssert(s.second.scanner, "Scanner not available"); + meta["sources"][s.first]["swarm"] = + "0x" + toHex(dev::swarmHash(s.second.scanner->source()).asBytes()); + } + meta["settings"]["optimizer"]["enabled"] = m_optimize; + meta["settings"]["optimizer"]["runs"] = m_optimizeRuns; + + set remappings; + for (auto const& r: m_remappings) + remappings.insert(r.context + ":" + r.prefix + "=" + r.target); + for (auto const& r: remappings) + meta["settings"]["remappings"].append(r); + + for (auto const& library: m_libraries) + meta["settings"]["libraries"][library.first] = "0x" + toHex(library.second.asBytes()); + + meta["output"]["abi"] = metadata(_contract, DocumentationType::ABIInterface); + meta["output"]["natspec"] = metadata(_contract, DocumentationType::NatspecUser); + + Json::FastWriter writer; + writer.omitEndingLineFeed(); + return writer.write(meta); +} + string CompilerStack::computeSourceMapping(eth::AssemblyItems const& _items) const { string ret; diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index ea706122..74a7dfc5 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -113,14 +113,15 @@ public: /// Compiles the source units that were previously added and parsed. /// @returns false on error. - bool compile(bool _optimize = false, unsigned _runs = 200); + bool compile( + bool _optimize = false, + unsigned _runs = 200, + std::map const& _libraries = std::map{} + ); /// Parses and compiles the given source code. /// @returns false on error. bool compile(std::string const& _sourceCode, bool _optimize = false); - /// Inserts the given addresses into the linker objects of all compiled contracts. - void link(std::map const& _libraries); - /// Tries to translate all source files into a language suitable for formal analysis. /// @param _errors list to store errors - defaults to the internal error list. /// @returns false on error. @@ -170,6 +171,7 @@ public: /// @param type The type of the documentation to get. /// Can be one of 4 types defined at @c DocumentationType Json::Value const& metadata(std::string const& _contractName, DocumentationType _type) const; + std::string const& onChainMetadata(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; @@ -213,6 +215,7 @@ private: eth::LinkerObject object; 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 userDocumentation; mutable std::unique_ptr devDocumentation; @@ -233,16 +236,18 @@ private: std::string absolutePath(std::string const& _path, std::string const& _reference) const; /// Compile a single contract and put the result in @a _compiledContracts. void compileContract( - bool _optimize, - unsigned _runs, ContractDefinition const& _contract, std::map& _compiledContracts ); + void link(); + Contract const& contract(std::string const& _contractName = "") const; Source const& source(std::string const& _sourceName = "") const; + std::string createOnChainMetadata(Contract const& _contract) const; std::string computeSourceMapping(eth::AssemblyItems const& _items) const; + Json::Value const& metadata(Contract const&, DocumentationType _type) const; struct Remapping { @@ -252,6 +257,9 @@ private: }; ReadFileCallback m_readFile; + bool m_optimize = false; + size_t m_optimizeRuns = 200; + std::map m_libraries; /// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum /// "context:prefix=target" std::vector m_remappings; -- cgit v1.2.3