From 5251099b14239c4f216e4e43c9fc5a88d7878ad6 Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Thu, 4 Apr 2019 18:28:53 +0200 Subject: [PATCH] Fix external ABI type name for contracts --- Changelog.md | 1 + libsolidity/ast/Types.cpp | 64 ++++++++++++++--------- test/libsolidity/SolidityEndToEndTest.cpp | 28 ++++++++++ 3 files changed, 67 insertions(+), 26 deletions(-) diff --git a/Changelog.md b/Changelog.md index d271f2f66..6f8c48f6e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ Important Bugfixes: * Code Generator: Fix initialization routine of uninitialized internal function pointers in constructor context. + * Type System: Use correct type name for contracts in event parameters when used in libraries. This affected code generation. Bugfixes: * General: Split rule list such that JavaScript environments with small stacks can use the compiler. diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 60e3183c3..7824287dd 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -121,6 +121,21 @@ bool fitsPrecisionBase2(bigint const& _mantissa, uint32_t _expBase2) return fitsPrecisionBaseX(_mantissa, 1.0, _expBase2); } +boost::optional transformParametersToExternal(TypePointers const& _parameters, bool _inLibrary) +{ + TypePointers transformed; + + for (auto const& type: _parameters) + { + if (TypePointer ext = type->interfaceType(_inLibrary)) + transformed.push_back(ext); + else + return {}; + } + + return transformed; +} + } void StorageOffsets::computeOffsets(TypePointers const& _types) @@ -2669,32 +2684,27 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const { // Note that m_declaration might also be a state variable! solAssert(m_declaration, "Declaration needed to determine interface function type."); - bool isLibraryFunction = dynamic_cast(*m_declaration->scope()).isLibrary(); + bool isLibraryFunction = kind() != Kind::Event && dynamic_cast(*m_declaration->scope()).isLibrary(); - TypePointers paramTypes; - TypePointers retParamTypes; + boost::optional paramTypes = + transformParametersToExternal(m_parameterTypes, isLibraryFunction); + + if (!paramTypes) + return FunctionTypePointer(); + + boost::optional retParamTypes = + transformParametersToExternal(m_returnParameterTypes, isLibraryFunction); + + if (!retParamTypes) + return FunctionTypePointer(); - for (auto type: m_parameterTypes) - { - if (auto ext = type->interfaceType(isLibraryFunction)) - paramTypes.push_back(ext); - else - return FunctionTypePointer(); - } - for (auto type: m_returnParameterTypes) - { - if (auto ext = type->interfaceType(isLibraryFunction)) - retParamTypes.push_back(ext); - else - return FunctionTypePointer(); - } auto variable = dynamic_cast(m_declaration); - if (variable && retParamTypes.empty()) + if (variable && retParamTypes.get().empty()) return FunctionTypePointer(); return make_shared( - paramTypes, - retParamTypes, + *paramTypes, + *retParamTypes, m_parameterNames, m_returnParameterNames, m_kind, @@ -2834,14 +2844,16 @@ string FunctionType::externalSignature() const solAssert(m_declaration != nullptr, "External signature of function needs declaration"); solAssert(!m_declaration->name().empty(), "Fallback function has no signature."); - bool const inLibrary = dynamic_cast(*m_declaration->scope()).isLibrary(); - FunctionTypePointer external = interfaceFunctionType(); - solAssert(!!external, "External function type requested."); - auto parameterTypes = external->parameterTypes(); - auto typeStrings = parameterTypes | boost::adaptors::transformed([&](TypePointer _t) -> string + bool const inLibrary = kind() != Kind::Event && dynamic_cast(*m_declaration->scope()).isLibrary(); + + boost::optional extParams = transformParametersToExternal(m_parameterTypes, inLibrary); + + solAssert(extParams, ""); + + auto typeStrings = *extParams | boost::adaptors::transformed([&](TypePointer _t) -> string { - solAssert(_t, "Parameter should have external type."); string typeName = _t->signatureInExternalFunction(inLibrary); + if (inLibrary && _t->dataStoredIn(DataLocation::Storage)) typeName += " storage"; return typeName; diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index f2cc78bfa..a872f7ff0 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -12413,6 +12413,34 @@ BOOST_AUTO_TEST_CASE(senders_balance) BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(27))); } +BOOST_AUTO_TEST_CASE(event_wrong_abi_name) +{ + char const* sourceCode = R"( + library ClientReceipt { + event Deposit(Test indexed _from, bytes32 indexed _id, uint _value); + function deposit(bytes32 _id) public { + Test a; + emit Deposit(a, _id, msg.value); + } + } + contract Test { + function f() public { + ClientReceipt.deposit("123"); + } + } + )"; + compileAndRun(sourceCode, 0, "ClientReceipt", bytes()); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"ClientReceipt", m_contractAddress}}); + u256 value(18); + u256 id(0x1234); + + callContractFunction("f()"); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 3); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address,bytes32,uint256)"))); +} + BOOST_AUTO_TEST_SUITE_END() }