Fix external ABI type name for contracts

This commit is contained in:
Mathias Baumann 2019-04-04 18:28:53 +02:00 committed by chriseth
parent 9861145ca8
commit 5251099b14
3 changed files with 67 additions and 26 deletions

View File

@ -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.

View File

@ -121,6 +121,21 @@ bool fitsPrecisionBase2(bigint const& _mantissa, uint32_t _expBase2)
return fitsPrecisionBaseX(_mantissa, 1.0, _expBase2);
}
boost::optional<TypePointers> 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<ContractDefinition const&>(*m_declaration->scope()).isLibrary();
bool isLibraryFunction = kind() != Kind::Event && dynamic_cast<ContractDefinition const&>(*m_declaration->scope()).isLibrary();
TypePointers paramTypes;
TypePointers retParamTypes;
boost::optional<TypePointers> paramTypes =
transformParametersToExternal(m_parameterTypes, isLibraryFunction);
if (!paramTypes)
return FunctionTypePointer();
boost::optional<TypePointers> 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<VariableDeclaration const*>(m_declaration);
if (variable && retParamTypes.empty())
if (variable && retParamTypes.get().empty())
return FunctionTypePointer();
return make_shared<FunctionType>(
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<ContractDefinition const&>(*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<ContractDefinition const&>(*m_declaration->scope()).isLibrary();
boost::optional<TypePointers> 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;

View File

@ -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<string, Address>{{"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()
}