diff --git a/Changelog.md b/Changelog.md index 1d3c47c12..1e5dd8e1c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,7 @@ ### 0.4.9 (unreleased) Features: + * Compiler Interface: Contracts and libraries can be referenced with a `file:` prefix to make them unique. * AST: Use deterministic node identifiers. * Metadata: Do not include platform in the version number. @@ -16,9 +17,6 @@ Bugfixes: * Imports: ``import ".dir/a"`` is not a relative path. Relative paths begin with directory ``.`` or ``..``. * Type checker, disallow inheritances of different kinds (e.g. a function and a modifier) of members of the same name -Features: - * Contracts and libraries are now unique to their source files, rather than globally. - ### 0.4.7 (2016-12-15) Features: diff --git a/libevmasm/LinkerObject.cpp b/libevmasm/LinkerObject.cpp index 93e4067c9..06607089e 100644 --- a/libevmasm/LinkerObject.cpp +++ b/libevmasm/LinkerObject.cpp @@ -37,13 +37,10 @@ void LinkerObject::link(map const& _libraryAddresses) { std::map remainingRefs; for (auto const& linkRef: linkReferences) - { - auto it = _libraryAddresses.find(linkRef.second); - if (it == _libraryAddresses.end()) - remainingRefs.insert(linkRef); + if (h160 const* address = matchLibrary(linkRef.second, _libraryAddresses)) + address->ref().copyTo(ref(bytecode).cropped(linkRef.first, 20)); else - it->second.ref().copyTo(ref(bytecode).cropped(linkRef.first, 20)); - } + remainingRefs.insert(linkRef); linkReferences.swap(remainingRefs); } @@ -60,3 +57,23 @@ string LinkerObject::toHex() const } return hex; } + +h160 const* +LinkerObject::matchLibrary( + string const& _linkRefName, + map const& _libraryAddresses +) +{ + auto it = _libraryAddresses.find(_linkRefName); + if (it != _libraryAddresses.end()) + return &it->second; + // If the user did not supply a fully qualified library name, + // try to match only the simple libary name + size_t colon = _linkRefName.find(':'); + if (colon == string::npos) + return nullptr; + it = _libraryAddresses.find(_linkRefName.substr(colon + 1)); + if (it != _libraryAddresses.end()) + return &it->second; + return nullptr; +} diff --git a/libevmasm/LinkerObject.h b/libevmasm/LinkerObject.h index d3ec3e972..152487b44 100644 --- a/libevmasm/LinkerObject.h +++ b/libevmasm/LinkerObject.h @@ -49,6 +49,12 @@ struct LinkerObject /// @returns a hex representation of the bytecode of the given object, replacing unlinked /// addresses by placeholders. std::string toHex() const; + +private: + static h160 const* matchLibrary( + std::string const& _linkRefName, + std::map const& _libraryAddresses + ); }; } diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 03aa26999..191618317 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -3192,7 +3192,7 @@ BOOST_AUTO_TEST_CASE(library_call_in_homestead) } )"; compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{":Lib", m_contractAddress}}); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); BOOST_CHECK(callContractFunction("f()") == encodeArgs()); BOOST_CHECK(callContractFunction("sender()") == encodeArgs(u160(m_sender))); } @@ -6191,7 +6191,7 @@ BOOST_AUTO_TEST_CASE(library_call) } )"; compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{":Lib", m_contractAddress}}); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); BOOST_CHECK(callContractFunction("f(uint256)", u256(33)) == encodeArgs(u256(33) * 9)); } @@ -6208,7 +6208,7 @@ BOOST_AUTO_TEST_CASE(library_stray_values) } )"; compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{":Lib", m_contractAddress}}); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); BOOST_CHECK(callContractFunction("f(uint256)", u256(33)) == encodeArgs(u256(42))); } @@ -6341,7 +6341,7 @@ BOOST_AUTO_TEST_CASE(internal_types_in_library) } )"; compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{":Lib", m_contractAddress}}); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(4), u256(17))); } @@ -6368,7 +6368,7 @@ BOOST_AUTO_TEST_CASE(using_library_structs) } )"; compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{":Lib", m_contractAddress}}); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7), u256(8))); } @@ -6902,7 +6902,7 @@ BOOST_AUTO_TEST_CASE(using_for_function_on_int) } )"; compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{":D", m_contractAddress}}); + compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); BOOST_CHECK(callContractFunction("f(uint256)", u256(9)) == encodeArgs(u256(2 * 9))); } @@ -6920,7 +6920,7 @@ BOOST_AUTO_TEST_CASE(using_for_function_on_struct) } )"; compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{":D", m_contractAddress}}); + compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); BOOST_CHECK(callContractFunction("f(uint256)", u256(7)) == encodeArgs(u256(3 * 7))); BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(3 * 7))); } @@ -6943,7 +6943,7 @@ BOOST_AUTO_TEST_CASE(using_for_overload) } )"; compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{":D", m_contractAddress}}); + compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); BOOST_CHECK(callContractFunction("f(uint256)", u256(7)) == encodeArgs(u256(6 * 7))); BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(6 * 7))); } @@ -6962,7 +6962,7 @@ BOOST_AUTO_TEST_CASE(using_for_by_name) } )"; compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{":D", m_contractAddress}}); + compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); BOOST_CHECK(callContractFunction("f(uint256)", u256(7)) == encodeArgs(u256(6 * 7))); BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(6 * 7))); } @@ -6982,7 +6982,7 @@ BOOST_AUTO_TEST_CASE(bound_function_in_var) } )"; compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{":D", m_contractAddress}}); + compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); BOOST_CHECK(callContractFunction("f(uint256)", u256(7)) == encodeArgs(u256(6 * 7))); BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(6 * 7))); } @@ -7005,7 +7005,7 @@ BOOST_AUTO_TEST_CASE(bound_function_to_string) } )"; compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{":D", m_contractAddress}}); + compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(3))); BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(3))); } @@ -7751,7 +7751,7 @@ BOOST_AUTO_TEST_CASE(payable_function_calls_library) } )"; compileAndRun(sourceCode, 0, "L"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{":L", m_contractAddress}}); + compileAndRun(sourceCode, 0, "C", bytes(), map{{"L", m_contractAddress}}); BOOST_CHECK(callContractFunctionWithValue("f()", 27) == encodeArgs(u256(7))); }