Merge pull request #1585 from ethereum/libraryfallback

Provide fallback for linking.
This commit is contained in:
chriseth 2017-01-18 19:28:14 +01:00 committed by GitHub
commit 9ce30e9da0
4 changed files with 42 additions and 21 deletions

View File

@ -1,6 +1,7 @@
### 0.4.9 (unreleased) ### 0.4.9 (unreleased)
Features: Features:
* Compiler Interface: Contracts and libraries can be referenced with a `file:` prefix to make them unique.
* AST: Use deterministic node identifiers. * AST: Use deterministic node identifiers.
* Metadata: Do not include platform in the version number. * 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 ``..``. * 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 * 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) ### 0.4.7 (2016-12-15)
Features: Features:

View File

@ -37,13 +37,10 @@ void LinkerObject::link(map<string, h160> const& _libraryAddresses)
{ {
std::map<size_t, std::string> remainingRefs; std::map<size_t, std::string> remainingRefs;
for (auto const& linkRef: linkReferences) for (auto const& linkRef: linkReferences)
{ if (h160 const* address = matchLibrary(linkRef.second, _libraryAddresses))
auto it = _libraryAddresses.find(linkRef.second); address->ref().copyTo(ref(bytecode).cropped(linkRef.first, 20));
if (it == _libraryAddresses.end())
remainingRefs.insert(linkRef);
else else
it->second.ref().copyTo(ref(bytecode).cropped(linkRef.first, 20)); remainingRefs.insert(linkRef);
}
linkReferences.swap(remainingRefs); linkReferences.swap(remainingRefs);
} }
@ -60,3 +57,23 @@ string LinkerObject::toHex() const
} }
return hex; return hex;
} }
h160 const*
LinkerObject::matchLibrary(
string const& _linkRefName,
map<string, h160> 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;
}

View File

@ -49,6 +49,12 @@ struct LinkerObject
/// @returns a hex representation of the bytecode of the given object, replacing unlinked /// @returns a hex representation of the bytecode of the given object, replacing unlinked
/// addresses by placeholders. /// addresses by placeholders.
std::string toHex() const; std::string toHex() const;
private:
static h160 const* matchLibrary(
std::string const& _linkRefName,
std::map<std::string, h160> const& _libraryAddresses
);
}; };
} }

View File

@ -3192,7 +3192,7 @@ BOOST_AUTO_TEST_CASE(library_call_in_homestead)
} }
)"; )";
compileAndRun(sourceCode, 0, "Lib"); compileAndRun(sourceCode, 0, "Lib");
compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{":Lib", m_contractAddress}}); compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{"Lib", m_contractAddress}});
BOOST_CHECK(callContractFunction("f()") == encodeArgs()); BOOST_CHECK(callContractFunction("f()") == encodeArgs());
BOOST_CHECK(callContractFunction("sender()") == encodeArgs(u160(m_sender))); 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, "Lib");
compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{":Lib", m_contractAddress}}); compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{"Lib", m_contractAddress}});
BOOST_CHECK(callContractFunction("f(uint256)", u256(33)) == encodeArgs(u256(33) * 9)); 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, "Lib");
compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{":Lib", m_contractAddress}}); compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{"Lib", m_contractAddress}});
BOOST_CHECK(callContractFunction("f(uint256)", u256(33)) == encodeArgs(u256(42))); 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, "Lib");
compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{":Lib", m_contractAddress}}); compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{"Lib", m_contractAddress}});
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(4), u256(17))); 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, "Lib");
compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{":Lib", m_contractAddress}}); compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{"Lib", m_contractAddress}});
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7), u256(8))); 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, "D");
compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{":D", m_contractAddress}}); compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{"D", m_contractAddress}});
BOOST_CHECK(callContractFunction("f(uint256)", u256(9)) == encodeArgs(u256(2 * 9))); 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, "D");
compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{":D", m_contractAddress}}); compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{"D", m_contractAddress}});
BOOST_CHECK(callContractFunction("f(uint256)", u256(7)) == encodeArgs(u256(3 * 7))); BOOST_CHECK(callContractFunction("f(uint256)", u256(7)) == encodeArgs(u256(3 * 7)));
BOOST_CHECK(callContractFunction("x()") == 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, "D");
compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{":D", m_contractAddress}}); compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{"D", m_contractAddress}});
BOOST_CHECK(callContractFunction("f(uint256)", u256(7)) == encodeArgs(u256(6 * 7))); BOOST_CHECK(callContractFunction("f(uint256)", u256(7)) == encodeArgs(u256(6 * 7)));
BOOST_CHECK(callContractFunction("x()") == 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, "D");
compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{":D", m_contractAddress}}); compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{"D", m_contractAddress}});
BOOST_CHECK(callContractFunction("f(uint256)", u256(7)) == encodeArgs(u256(6 * 7))); BOOST_CHECK(callContractFunction("f(uint256)", u256(7)) == encodeArgs(u256(6 * 7)));
BOOST_CHECK(callContractFunction("x()") == 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, "D");
compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{":D", m_contractAddress}}); compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{"D", m_contractAddress}});
BOOST_CHECK(callContractFunction("f(uint256)", u256(7)) == encodeArgs(u256(6 * 7))); BOOST_CHECK(callContractFunction("f(uint256)", u256(7)) == encodeArgs(u256(6 * 7)));
BOOST_CHECK(callContractFunction("x()") == 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, "D");
compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{":D", m_contractAddress}}); compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{"D", m_contractAddress}});
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(3))); BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(3)));
BOOST_CHECK(callContractFunction("g()") == 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, "L");
compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{":L", m_contractAddress}}); compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{"L", m_contractAddress}});
BOOST_CHECK(callContractFunctionWithValue("f()", 27) == encodeArgs(u256(7))); BOOST_CHECK(callContractFunctionWithValue("f()", 27) == encodeArgs(u256(7)));
} }