From 03ea63e202fea0eb6af12aa3f77c63a26d28a1f0 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 28 Jan 2015 10:01:46 +0100 Subject: [PATCH 1/4] Dockerfile to build the solidity compiler using emscripten. --- solc/docker_emscripten/Dockerfile | 57 +++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 solc/docker_emscripten/Dockerfile diff --git a/solc/docker_emscripten/Dockerfile b/solc/docker_emscripten/Dockerfile new file mode 100644 index 000000000..c866d427a --- /dev/null +++ b/solc/docker_emscripten/Dockerfile @@ -0,0 +1,57 @@ +FROM ubuntu:14.04 + +ENV DEBIAN_FRONTEND noninteractive +RUN apt-get update +RUN apt-get upgrade -y + +# Ethereum dependencies +RUN apt-get install -qy build-essential git cmake libcurl4-openssl-dev wget +RUN apt-get install -qy automake libtool yasm scons + +RUN useradd -ms /bin/bash user +USER user +WORKDIR /home/user + +# Emscripten SDK +RUN wget -c https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz +RUN tar xzf emsdk-portable.tar.gz +WORKDIR /home/user/emsdk_portable +RUN ./emsdk update && ./emsdk install latest && ./emsdk activate latest +ENV PATH $PATH:/home/user/emsdk_portable:/home/user/emsdk_portable/clang/fastcomp/build_master_64/bin:/home/user/emsdk_portable/emscripten/master + +USER root +RUN apt-get install -qy nodejs +USER user +RUN sed -i "s/NODE_JS = 'node'/NODE_JS = 'nodejs'/g" ~/.emscripten + +# CryptoPP +WORKDIR /home/user +RUN git clone https://github.com/mmoss/cryptopp.git +WORKDIR /home/user/cryptopp +RUN emcmake cmake -DCRYPTOPP_LIBRARY_TYPE=STATIC -DCRYPTOPP_RUNTIME_TYPE=STATIC && emmake make -j 4 +RUN ln -s . src/cryptopp + +# Boost +WORKDIR /home/user +RUN wget 'http://downloads.sourceforge.net/project/boost/boost/1.57.0/boost_1_57_0.tar.bz2?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fboost%2Ffiles%2Fboost%2F1.57.0%2F&ts=1421887207&use_mirror=cznic' -O boost_1_57_0.tar.bz2 +RUN tar xjf boost_1_57_0.tar.bz2 +WORKDIR /home/user/boost_1_57_0 +RUN ./bootstrap.sh --with-libraries=thread,system,regex +RUN sed -i 's/using gcc ;/using gcc : : \/home\/user\/emsdk_portable\/emscripten\/master\/em++ ;/g' ./project-config.jam +RUN sed -i 's/$(archiver\[1\])/\/home\/user\/emsdk_portable\/emscripten\/master\/emar/g' ./tools/build/src/tools/gcc.jam +RUN sed -i 's/$(ranlib\[1\])/\/home\/user\/emsdk_portable\/emscripten\/master\/emranlib/g' ./tools/build/src/tools/gcc.jam +RUN ./b2 link=static variant=release threading=single runtime-link=static thread system regex + + +# Build soljs +WORKDIR /home/user +ADD https://api.github.com/repos/ethereum/cpp-ethereum/git/refs/heads/develop unused.txt +RUN git clone --depth=1 https://github.com/ethereum/cpp-ethereum +WORKDIR /home/user/cpp-ethereum +ADD https://api.github.com/repos/chriseth/cpp-ethereum/git/refs/heads/solidity-js unused2.txt +RUN git remote add -f solidityjs https://github.com/chriseth/cpp-ethereum +RUN git merge solidityjs/solidity-js +RUN emcmake cmake -DETH_STATIC=1 -DONLY_SOLIDITY=1 -DHEADLESS=1 -DCMAKE_CXX_COMPILER=/home/user/emsdk_portable/emscripten/master/em++ -DCMAKE_C_COMPILER=/home/user/emsdk_portable/emscripten/master/emcc +RUN emmake make -j 6 soljs + +ENTRYPOINT cat soljs/soljs.js From 54e5068268f6777cfc8bd7b24131c4e44af844c1 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 28 Jan 2015 11:28:22 +0100 Subject: [PATCH 2/4] Some fixes in parser. --- libsolidity/ASTPrinter.cpp | 12 ++++++++++++ libsolidity/ASTPrinter.h | 2 ++ libsolidity/ASTVisitor.h | 4 ++++ libsolidity/Parser.cpp | 15 +++++++++++---- libsolidity/Parser.h | 1 + 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index 85bc88254..05b24c63a 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -57,6 +57,13 @@ bool ASTPrinter::visit(ContractDefinition const& _node) return goDeeper(); } +bool ASTPrinter::visit(InheritanceSpecifier const& _node) +{ + writeLine("InheritanceSpecifier \"" + _node.getName()->getName() + "\""); + printSourcePart(_node); + return goDeeper(); +} + bool ASTPrinter::visit(StructDefinition const& _node) { writeLine("StructDefinition \"" + _node.getName() + "\""); @@ -323,6 +330,11 @@ void ASTPrinter::endVisit(ContractDefinition const&) m_indentation--; } +void ASTPrinter::endVisit(InheritanceSpecifier const&) +{ + m_indentation--; +} + void ASTPrinter::endVisit(StructDefinition const&) { m_indentation--; diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h index 7f267bdf0..77025b2d0 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -44,6 +44,7 @@ public: bool visit(ImportDirective const& _node) override; bool visit(ContractDefinition const& _node) override; + bool visit(InheritanceSpecifier const& _node) override; bool visit(StructDefinition const& _node) override; bool visit(ParameterList const& _node) override; bool visit(FunctionDefinition const& _node) override; @@ -81,6 +82,7 @@ public: void endVisit(ImportDirective const&) override; void endVisit(ContractDefinition const&) override; + void endVisit(InheritanceSpecifier const&) override; void endVisit(StructDefinition const&) override; void endVisit(ParameterList const&) override; void endVisit(FunctionDefinition const&) override; diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h index ecab00c31..53fbd1918 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ASTVisitor.h @@ -45,6 +45,7 @@ public: virtual bool visit(SourceUnit&) { return true; } virtual bool visit(ImportDirective&) { return true; } virtual bool visit(ContractDefinition&) { return true; } + virtual bool visit(InheritanceSpecifier&) { return true; } virtual bool visit(StructDefinition&) { return true; } virtual bool visit(ParameterList&) { return true; } virtual bool visit(FunctionDefinition&) { return true; } @@ -84,6 +85,7 @@ public: virtual void endVisit(SourceUnit&) { } virtual void endVisit(ImportDirective&) { } virtual void endVisit(ContractDefinition&) { } + virtual void endVisit(InheritanceSpecifier&) { } virtual void endVisit(StructDefinition&) { } virtual void endVisit(ParameterList&) { } virtual void endVisit(FunctionDefinition&) { } @@ -127,6 +129,7 @@ public: virtual bool visit(SourceUnit const&) { return true; } virtual bool visit(ImportDirective const&) { return true; } virtual bool visit(ContractDefinition const&) { return true; } + virtual bool visit(InheritanceSpecifier const&) { return true; } virtual bool visit(StructDefinition const&) { return true; } virtual bool visit(ParameterList const&) { return true; } virtual bool visit(FunctionDefinition const&) { return true; } @@ -166,6 +169,7 @@ public: virtual void endVisit(SourceUnit const&) { } virtual void endVisit(ImportDirective const&) { } virtual void endVisit(ContractDefinition const&) { } + virtual void endVisit(InheritanceSpecifier const&) { } virtual void endVisit(StructDefinition const&) { } virtual void endVisit(ParameterList const&) { } virtual void endVisit(FunctionDefinition const&) { } diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index baddbad86..d99d33acc 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -167,7 +167,7 @@ ASTPointer Parser::parseContractDefinition() ASTPointer Parser::parseInheritanceSpecifier() { ASTNodeFactory nodeFactory(*this); - ASTPointer name = ASTNodeFactory(*this).createNode(expectIdentifierToken()); + ASTPointer name(parseIdentifier()); vector> arguments; if (m_scanner->getCurrentToken() == Token::LPAREN) { @@ -283,7 +283,7 @@ ASTPointer Parser::parseModifierDefinition() ASTPointer Parser::parseModifierInvocation() { ASTNodeFactory nodeFactory(*this); - ASTPointer name = ASTNodeFactory(*this).createNode(expectIdentifierToken()); + ASTPointer name(parseIdentifier()); vector> arguments; if (m_scanner->getCurrentToken() == Token::LPAREN) { @@ -297,6 +297,13 @@ ASTPointer Parser::parseModifierInvocation() return nodeFactory.createNode(name, arguments); } +ASTPointer Parser::parseIdentifier() +{ + ASTNodeFactory nodeFactory(*this); + nodeFactory.markEndPosition(); + return nodeFactory.createNode(expectIdentifierToken()); +} + ASTPointer Parser::parseTypeName(bool _allowVar) { ASTPointer type; @@ -584,8 +591,8 @@ ASTPointer Parser::parseLeftHandSideExpression() if (m_scanner->getCurrentToken() == Token::NEW) { expectToken(Token::NEW); - ASTPointer contractName = ASTNodeFactory(*this).createNode(expectIdentifierToken()); - nodeFactory.markEndPosition(); + ASTPointer contractName(parseIdentifier()); + nodeFactory.setEndPositionFromNode(contractName); expression = nodeFactory.createNode(contractName); } else diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index f85c3186d..211e952d3 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -55,6 +55,7 @@ private: ASTPointer parseVariableDeclaration(bool _allowVar); ASTPointer parseModifierDefinition(); ASTPointer parseModifierInvocation(); + ASTPointer parseIdentifier(); ASTPointer parseTypeName(bool _allowVar); ASTPointer parseMapping(); ASTPointer parseParameterList(bool _allowEmpty = true); From fd1f7b527f7cace0c6ee247c8d5c2c29922d5876 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 28 Jan 2015 13:39:04 +0100 Subject: [PATCH 3/4] Cleaner solution to provide standard sources. --- libsolidity/AST.cpp | 3 +- libsolidity/CompilerStack.cpp | 88 ++++++++++--------------------- libsolidity/CompilerStack.h | 10 ++-- test/SolidityABIJSON.cpp | 2 + test/SolidityEndToEndTest.cpp | 15 ++++++ test/SolidityNatspecJSON.cpp | 2 + test/solidityExecutionFramework.h | 6 ++- 7 files changed, 55 insertions(+), 71 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index cc7da7154..e5967caa5 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -414,8 +414,7 @@ void FunctionCall::checkTypeRequirements() //@todo for structs, we have to check the number of arguments to be equal to the // number of non-mapping members if (m_arguments.size() != 1) - BOOST_THROW_EXCEPTION(createTypeError("More than one argument for " - "explicit type conersion.")); + BOOST_THROW_EXCEPTION(createTypeError("More than one argument for explicit type conversion.")); if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type.getActualType())) BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed.")); m_type = type.getActualType(); diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 2917a382a..044e0deab 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -40,18 +40,39 @@ namespace dev namespace solidity { +const map StandardSources = map{ + {"coin", R"(import "CoinReg";import "Config";import "configUser";contract coin is configUser{function coin(string3 name, uint denom) {CoinReg(Config(configAddr()).lookup(3)).register(name, denom);}})"}, + {"Coin", R"(contract Coin{function isApprovedFor(address _target,address _proxy)constant returns(bool _r){}function isApproved(address _proxy)constant returns(bool _r){}function sendCoinFrom(address _from,uint256 _val,address _to){}function coinBalanceOf(address _a)constant returns(uint256 _r){}function sendCoin(uint256 _val,address _to){}function coinBalance()constant returns(uint256 _r){}function approve(address _a){}})"}, + {"CoinReg", R"(contract CoinReg{function count()constant returns(uint256 r){}function info(uint256 i)constant returns(address addr,string3 name,uint256 denom){}function register(string3 name,uint256 denom){}function unregister(){}})"}, + {"configUser", R"(contract configUser{function configAddr()constant returns(address a){ return 0xc6d9d2cd449a754c494264e1809c50e34d64562b;}})"}, + {"Config", R"(contract Config{function lookup(uint256 service)constant returns(address a){}function kill(){}function unregister(uint256 id){}function register(uint256 id,address service){}})"}, + {"mortal", R"(import "owned";contract mortal is owned {function kill() { if (msg.sender == owner) suicide(owner); }})"}, + {"named", R"(import "Config";import "NameReg";import "configUser";contract named is configUser {function named(string32 name) {NameReg(Config(configAddr()).lookup(1)).register(name);}})"}, + {"NameReg", R"(contract NameReg{function register(string32 name){}function addressOf(string32 name)constant returns(address addr){}function unregister(){}function nameOf(address addr)constant returns(string32 name){}})"}, + {"owned", R"(contract owned{function owned(){owner = msg.sender;}modifier onlyowner(){if(msg.sender==owner)_}address owner;})"}, + {"service", R"(import "Config";import "configUser";contract service is configUser{function service(uint _n){Config(configAddr()).register(_n, this);}})"}, + {"std", R"(import "owned";import "mortal";import "Config";import "configUser";import "NameReg";import "named";)"} +}; + +CompilerStack::CompilerStack(bool _addStandardSources): + m_addStandardSources(_addStandardSources), m_parseSuccessful(false) +{ + if (m_addStandardSources) + addSources(StandardSources); +} + bool CompilerStack::addSource(string const& _name, string const& _content) { bool existed = m_sources.count(_name) != 0; reset(true); - m_sources[_name].scanner = make_shared(CharStream(expanded(_content)), _name); + m_sources[_name].scanner = make_shared(CharStream(_content), _name); return existed; } void CompilerStack::setSource(string const& _sourceCode) { reset(); - addSource("", expanded(_sourceCode)); + addSource("", _sourceCode); } void CompilerStack::parse() @@ -91,7 +112,6 @@ void CompilerStack::parse() void CompilerStack::parse(string const& _sourceCode) { setSource(_sourceCode); - addSources(StandardSources); parse(); } @@ -125,64 +145,6 @@ void CompilerStack::compile(bool _optimize) } } -const map StandardSources = map{ -/* { "Config", "contract Config{function lookup(uint256 service)constant returns(address a){}function kill(){}function unregister(uint256 id){}function register(uint256 id,address service){}}" }, - { "owned", "contract owned{function owned(){owner = msg.sender;}address owner;}" }, - { "mortal", "import \"owned\";\ncontract mortal is owned {function kill() { if (msg.sender == owner) suicide(owner); }}" }, - { "NameReg", "contract NameReg{function register(string32 name){}function addressOf(string32 name)constant returns(address addr){}function unregister(){}function nameOf(address addr)constant returns(string32 name){}}" }, - { "named", "import \"Config\";\nimport \"NameReg\";\ncontract named {function named(string32 name) {NameReg(Config().lookup(1)).register(name);}}" }, - { "std", "import \"owned\";\nimport \"mortal\";\nimport \"Config\";\nimport \"NameReg\";\nimport \"named\";\n" }, -*/}; - -////// BEGIN: TEMPORARY ONLY -/// remove once import works properly and we have genesis contracts - -string CompilerStack::expanded(string const& _sourceCode) -{ - const map c_standardSources = map{ - { "Config", "contract Config{function lookup(uint256 service)constant returns(address a){}function kill(){}function unregister(uint256 id){}function register(uint256 id,address service){}}" }, - { "Coin", "contract Coin{function isApprovedFor(address _target,address _proxy)constant returns(bool _r){}function isApproved(address _proxy)constant returns(bool _r){}function sendCoinFrom(address _from,uint256 _val,address _to){}function coinBalanceOf(address _a)constant returns(uint256 _r){}function sendCoin(uint256 _val,address _to){}function coinBalance()constant returns(uint256 _r){}function approve(address _a){}}"}, - { "CoinReg", "contract CoinReg{function count()constant returns(uint256 r){}function info(uint256 i)constant returns(address addr,string3 name,uint256 denom){}function register(string3 name,uint256 denom){}function unregister(){}}" }, - { "coin", "#require CoinReg\ncontract coin {function coin(string3 name, uint denom) {CoinReg(Config().lookup(3)).register(name, denom);}}" }, - { "service", "#require Config\ncontract service{function service(uint _n){Config().register(_n, this);}}" }, - { "owned", "contract owned{function owned(){owner = msg.sender;}modifier onlyowner(){if(msg.sender==owner)_}address owner;}" }, - { "mortal", "#require owned\ncontract mortal is owned {function kill() { if (msg.sender == owner) suicide(owner); }}" }, - { "NameReg", "contract NameReg{function register(string32 name){}function addressOf(string32 name)constant returns(address addr){}function unregister(){}function nameOf(address addr)constant returns(string32 name){}}" }, - { "named", "#require Config NameReg\ncontract named {function named(string32 name) {NameReg(Config().lookup(1)).register(name);}}" }, - { "std", "#require owned mortal Config NameReg named" }, - }; - - string sub; - set got; - function localExpanded; - localExpanded = [&](string const& s) -> string - { - string ret = s; - for (size_t p = 0; p != string::npos;) - if ((p = ret.find("#require ")) != string::npos) - { - string n = ret.substr(p + 9, ret.find_first_of('\n', p + 9) - p - 9); - ret.replace(p, n.size() + 9, ""); - vector rs; - boost::split(rs, n, boost::is_any_of(" \t,"), boost::token_compress_on); - for (auto const& r: rs) - if (!got.count(r)) - { - if (c_standardSources.count(r)) - sub.append("\n" + localExpanded(c_standardSources.at(r)) + "\n"); - got.insert(r); - } - } - // TODO: remove once we have genesis contracts. - else if ((p = ret.find("Config()")) != string::npos) - ret.replace(p, 8, "Config(0xc6d9d2cd449a754c494264e1809c50e34d64562b)"); - return ret; - }; - return sub + localExpanded(_sourceCode); -} - -////// END: TEMPORARY ONLY - bytes const& CompilerStack::compile(string const& _sourceCode, bool _optimize) { parse(_sourceCode); @@ -278,7 +240,11 @@ void CompilerStack::reset(bool _keepSources) for (auto sourcePair: m_sources) sourcePair.second.reset(); else + { m_sources.clear(); + if (m_addStandardSources) + addSources(StandardSources); + } m_globalContext.reset(); m_sourceOrder.clear(); m_contracts.clear(); diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 09a1ad348..cae0f4e27 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -59,7 +59,8 @@ extern const std::map StandardSources; class CompilerStack: boost::noncopyable { public: - CompilerStack(): m_parseSuccessful(false) {} + /// Creates a new compiler stack. Adds standard sources if @a _addStandardSources. + explicit CompilerStack(bool _addStandardSources = true); /// Adds a source object (e.g. file) to the parser. After this, parse has to be called again. /// @returns true if a source object by the name already existed and was replaced. @@ -68,7 +69,7 @@ public: void setSource(std::string const& _sourceCode); /// Parses all source units that were added void parse(); - /// Sets the given source code as the only source unit and parses it. + /// Sets the given source code as the only source unit apart from standard sources and parses it. void parse(std::string const& _sourceCode); /// Returns a list of the contract names in the sources. std::vector getContractNames() const; @@ -141,16 +142,13 @@ private: Contract(); }; - /// Expand source code with preprocessor-like includes. - /// @todo Replace with better framework. - std::string expanded(std::string const& _sourceCode); - void reset(bool _keepSources = false); void resolveImports(); Contract const& getContract(std::string const& _contractName = "") const; Source const& getSource(std::string const& _sourceName = "") const; + bool m_addStandardSources; ///< If true, standard sources are added. bool m_parseSuccessful; std::map m_sources; std::shared_ptr m_globalContext; diff --git a/test/SolidityABIJSON.cpp b/test/SolidityABIJSON.cpp index 892b71f15..4a44ebb84 100644 --- a/test/SolidityABIJSON.cpp +++ b/test/SolidityABIJSON.cpp @@ -35,6 +35,8 @@ namespace test class InterfaceChecker { public: + InterfaceChecker(): m_compilerStack(false) {} + void checkInterface(std::string const& _code, std::string const& _expectedInterfaceString) { try diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 97f444d22..23cd4f6d8 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -1862,6 +1862,21 @@ BOOST_AUTO_TEST_CASE(function_modifier_for_constructor) BOOST_CHECK(callContractFunction("getData()") == encodeArgs(4 | 2)); } +BOOST_AUTO_TEST_CASE(use_std_lib) +{ + char const* sourceCode = R"( + import "mortal"; + contract Icarus is mortal { } + )"; + u256 amount(130); + u160 address(23); + compileAndRun(sourceCode, amount, "Icarus"); + u256 balanceBefore = m_state.balance(m_sender); + BOOST_CHECK(callContractFunction("kill()") == bytes()); + BOOST_CHECK(!m_state.addressHasCode(m_contractAddress)); + BOOST_CHECK(m_state.balance(m_sender) > balanceBefore); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/SolidityNatspecJSON.cpp b/test/SolidityNatspecJSON.cpp index 743651d54..911820ddd 100644 --- a/test/SolidityNatspecJSON.cpp +++ b/test/SolidityNatspecJSON.cpp @@ -36,6 +36,8 @@ namespace test class DocumentationChecker { public: + DocumentationChecker(): m_compilerStack(false) {} + void checkNatspec(std::string const& _code, std::string const& _expectedDocumentationString, bool _userDocumentation) diff --git a/test/solidityExecutionFramework.h b/test/solidityExecutionFramework.h index 271a594c4..208e9ae80 100644 --- a/test/solidityExecutionFramework.h +++ b/test/solidityExecutionFramework.h @@ -45,10 +45,12 @@ public: bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") { - dev::solidity::CompilerStack compiler; + // add standard sources only if contract name is given + dev::solidity::CompilerStack compiler(!_contractName.empty()); try { - compiler.compile(_sourceCode, m_optimize); + compiler.addSource("", _sourceCode); + compiler.compile(m_optimize); } catch(boost::exception const& _e) { From b80aa77de0e4441dab0ae1cc371010b056ae5ed0 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 28 Jan 2015 14:16:15 +0100 Subject: [PATCH 4/4] Find some reasonable contract if nothing is supplied. --- libsolidity/CompilerStack.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 044e0deab..0b8218bb3 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -286,10 +286,12 @@ CompilerStack::Contract const& CompilerStack::getContract(string const& _contrac BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found.")); string contractName = _contractName; if (_contractName.empty()) - // try to find the "last contract" - for (ASTPointer const& node: m_sourceOrder.back()->ast->getNodes()) - if (auto contract = dynamic_cast(node.get())) - contractName = contract->getName(); + // try to find some user-supplied contract + for (auto const& it: m_sources) + if (!StandardSources.count(it.first)) + for (ASTPointer const& node: it.second.ast->getNodes()) + if (auto contract = dynamic_cast(node.get())) + contractName = contract->getName(); auto it = m_contracts.find(contractName); if (it == m_contracts.end()) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Contract " + _contractName + " not found."));