diff options
author | chriseth <c@ethdev.com> | 2016-11-14 18:46:43 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2016-12-01 23:03:59 +0800 |
commit | 5789eaa78d0e00f6289101e02f7de5e9decdc7e5 (patch) | |
tree | 8964f493235d310baa50806fdff65138054d2439 /libsolidity | |
parent | 55a719a79c1ab5b78ea6e1bcb4f27a888494a538 (diff) | |
download | dexon-solidity-5789eaa78d0e00f6289101e02f7de5e9decdc7e5.tar.gz dexon-solidity-5789eaa78d0e00f6289101e02f7de5e9decdc7e5.tar.zst dexon-solidity-5789eaa78d0e00f6289101e02f7de5e9decdc7e5.zip |
Metadata stamp.
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/ast/AST.cpp | 8 | ||||
-rw-r--r-- | libsolidity/ast/AST.h | 4 | ||||
-rw-r--r-- | libsolidity/codegen/Compiler.cpp | 10 | ||||
-rw-r--r-- | libsolidity/codegen/Compiler.h | 3 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerContext.cpp | 7 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerContext.h | 3 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.cpp | 98 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.h | 20 | ||||
-rw-r--r-- | libsolidity/parsing/Scanner.h | 4 |
9 files changed, 126 insertions, 31 deletions
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 9b478393..f8eb7108 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -63,6 +63,14 @@ SourceUnitAnnotation& SourceUnit::annotation() const return static_cast<SourceUnitAnnotation&>(*m_annotation); } +string Declaration::sourceUnitName() const +{ + ASTNode const* scope = m_scope; + while (dynamic_cast<Declaration const*>(scope) && dynamic_cast<Declaration const*>(scope)->m_scope) + scope = dynamic_cast<Declaration const*>(scope)->m_scope; + return dynamic_cast<SourceUnit const&>(*scope).annotation().path; +} + ImportAnnotation& ImportDirective::annotation() const { if (!m_annotation) diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 89b96f09..ab4be1ea 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -158,6 +158,10 @@ public: ASTNode const* scope() const { return m_scope; } void setScope(ASTNode const* _scope) { m_scope = _scope; } + /// @returns the source name this declaration is present in. + /// Can be combined with annotation().canonicalName to form a globally unique name. + std::string sourceUnitName() const; + virtual bool isLValue() const { return false; } virtual bool isPartOfExternalInterface() const { return false; } diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp index 22d25698..168e9462 100644 --- a/libsolidity/codegen/Compiler.cpp +++ b/libsolidity/codegen/Compiler.cpp @@ -30,7 +30,8 @@ using namespace dev::solidity; void Compiler::compileContract( ContractDefinition const& _contract, - std::map<const ContractDefinition*, eth::Assembly const*> const& _contracts + std::map<const ContractDefinition*, eth::Assembly const*> const& _contracts, + h256 const& _metadataHash ) { ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimize); @@ -43,11 +44,8 @@ void Compiler::compileContract( m_context.optimise(m_optimize, m_optimizeRuns); - if (_contract.isLibrary()) - { - solAssert(m_runtimeSub != size_t(-1), ""); - m_context.injectVersionStampIntoSub(m_runtimeSub); - } + solAssert(m_runtimeSub != size_t(-1), ""); + m_context.injectMetadataHashIntoSub(m_runtimeSub, _metadataHash); } void Compiler::compileClone( diff --git a/libsolidity/codegen/Compiler.h b/libsolidity/codegen/Compiler.h index c8bf7861..58ef1963 100644 --- a/libsolidity/codegen/Compiler.h +++ b/libsolidity/codegen/Compiler.h @@ -42,7 +42,8 @@ public: void compileContract( ContractDefinition const& _contract, - std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts + std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts, + h256 const& _metadataHash ); /// Compiles a contract that uses DELEGATECALL to call into a pre-deployed version of the given /// contract at runtime, but contains the full creation-time code. diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index b99b0548..9b921e9d 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -227,6 +227,13 @@ void CompilerContext::injectVersionStampIntoSub(size_t _subIndex) sub.injectStart(fromBigEndian<u256>(binaryVersion())); } +void CompilerContext::injectMetadataHashIntoSub(size_t _subIndex, h256 const& _metadataHash) +{ + eth::Assembly& sub = m_asm->sub(_subIndex); + sub.injectStart(Instruction::POP); + sub.injectStart(u256(_metadataHash)); +} + FunctionDefinition const& CompilerContext::resolveVirtualFunction( FunctionDefinition const& _function, vector<ContractDefinition const*>::const_iterator _searchStart diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 3c6d9d73..c8a35f93 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -155,6 +155,9 @@ public: /// Prepends "PUSH <compiler version number> POP" void injectVersionStampIntoSub(size_t _subIndex); + /// Prepends "PUSH <metadata hash> POP" + void injectMetadataHashIntoSub(size_t _subIndex, h256 const& _metadataHash); + void optimise(bool _fullOptimsation, unsigned _runs = 200) { m_asm->optimise(_fullOptimsation, true, _runs); } /// @returns the runtime context if in creation mode and runtime context is set, nullptr otherwise. 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 <libsolidity/formal/Why3Translator.h> #include <libevmasm/Exceptions.h> -#include <libdevcore/SHA3.h> + +#include <libdevcore/SwarmHash.h> + +#include <json/json.h> #include <boost/algorithm/string.hpp> #include <boost/filesystem.hpp> @@ -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<string> CompilerStack::contractNames() const } -bool CompilerStack::compile(bool _optimize, unsigned _runs) +bool CompilerStack::compile(bool _optimize, unsigned _runs, map<string, h160> const& _libraries) { if (!m_parseSuccessful) if (!parse()) return false; + m_optimize = _optimize; + m_optimizeRuns = _runs; + m_libraries = _libraries; + map<ContractDefinition const*, eth::Assembly const*> compiledContracts; for (Source const* source: m_sourceOrder) for (ASTPointer<ASTNode> const& node: source->ast->nodes()) if (auto contract = dynamic_cast<ContractDefinition const*>(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<string, h160>& _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); } } @@ -356,20 +366,27 @@ Json::Value const& CompilerStack::metadata(string const& _contractName, Document 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<Json::Value const>* 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<ContractDefinition const*, eth::Assembly const*>& _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> compiler = make_shared<Compiler>(_optimize, _runs); - compiler->compileContract(_contract, _compiledContracts); + shared_ptr<Compiler> compiler = make_shared<Compiler>(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<string> 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<std::string, h160> const& _libraries = std::map<std::string, h160>{} + ); /// 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<std::string, h160> 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<Json::Value const> interface; mutable std::unique_ptr<Json::Value const> userDocumentation; mutable std::unique_ptr<Json::Value const> 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<ContractDefinition const*, eth::Assembly const*>& _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<std::string, h160> m_libraries; /// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum /// "context:prefix=target" std::vector<Remapping> m_remappings; diff --git a/libsolidity/parsing/Scanner.h b/libsolidity/parsing/Scanner.h index 65de8bd4..d6b48c6f 100644 --- a/libsolidity/parsing/Scanner.h +++ b/libsolidity/parsing/Scanner.h @@ -80,6 +80,8 @@ public: void reset() { m_position = 0; } + std::string const& source() const { return m_source; } + ///@{ ///@name Error printing helper functions /// Functions that help pretty-printing parse errors @@ -102,6 +104,8 @@ public: explicit Scanner(CharStream const& _source = CharStream(), std::string const& _sourceName = "") { reset(_source, _sourceName); } + std::string source() const { return m_source.source(); } + /// Resets the scanner as if newly constructed with _source and _sourceName as input. void reset(CharStream const& _source, std::string const& _sourceName); /// Resets scanner to the start of input. |