Add support for interfaceID.

This commit is contained in:
Alexander Arlt
2020-04-16 12:17:40 -05:00
parent 7a9e024e90
commit 3754a86ab2
15 changed files with 304 additions and 12 deletions
+2
View File
@@ -2617,6 +2617,8 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
}
else if (magicType->kind() == MagicType::Kind::MetaType && memberName == "name")
annotation.isPure = true;
else if (magicType->kind() == MagicType::Kind::MetaType && memberName == "interfaceId")
annotation.isPure = true;
}
return false;
+1
View File
@@ -355,6 +355,7 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
{MagicType::Kind::MetaType, "creationCode"},
{MagicType::Kind::MetaType, "runtimeCode"},
{MagicType::Kind::MetaType, "name"},
{MagicType::Kind::MetaType, "interfaceId"},
};
set<MagicMember> static const payableMembers{
{MagicType::Kind::Message, "value"}
+9 -7
View File
@@ -96,9 +96,9 @@ bool ContractDefinition::derivesFrom(ContractDefinition const& _base) const
return util::contains(annotation().linearizedBaseContracts, &_base);
}
map<util::FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
map<util::FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions(bool _includeInheritedFunctions) const
{
auto exportedFunctionList = interfaceFunctionList();
auto exportedFunctionList = interfaceFunctionList(_includeInheritedFunctions);
map<util::FixedHash<4>, FunctionTypePointer> exportedFunctions;
for (auto const& it: exportedFunctionList)
@@ -174,14 +174,16 @@ vector<EventDefinition const*> const& ContractDefinition::interfaceEvents() cons
return *m_interfaceEvents;
}
vector<pair<util::FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::interfaceFunctionList() const
vector<pair<util::FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::interfaceFunctionList(bool _includeInheritedFunctions) const
{
if (!m_interfaceFunctionList)
if (!m_interfaceFunctionList[_includeInheritedFunctions])
{
set<string> signaturesSeen;
m_interfaceFunctionList = make_unique<vector<pair<util::FixedHash<4>, FunctionTypePointer>>>();
m_interfaceFunctionList[_includeInheritedFunctions] = make_unique<vector<pair<util::FixedHash<4>, FunctionTypePointer>>>();
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
{
if (_includeInheritedFunctions == false && contract != this)
continue;
vector<FunctionTypePointer> functions;
for (FunctionDefinition const* f: contract->definedFunctions())
if (f->isPartOfExternalInterface())
@@ -199,12 +201,12 @@ vector<pair<util::FixedHash<4>, FunctionTypePointer>> const& ContractDefinition:
{
signaturesSeen.insert(functionSignature);
util::FixedHash<4> hash(util::keccak256(functionSignature));
m_interfaceFunctionList->emplace_back(hash, fun);
m_interfaceFunctionList[_includeInheritedFunctions]->emplace_back(hash, fun);
}
}
}
}
return *m_interfaceFunctionList;
return *m_interfaceFunctionList[_includeInheritedFunctions];
}
TypePointer ContractDefinition::type() const
+3 -3
View File
@@ -488,8 +488,8 @@ public:
/// @returns a map of canonical function signatures to FunctionDefinitions
/// as intended for use by the ABI.
std::map<util::FixedHash<4>, FunctionTypePointer> interfaceFunctions() const;
std::vector<std::pair<util::FixedHash<4>, FunctionTypePointer>> const& interfaceFunctionList() const;
std::map<util::FixedHash<4>, FunctionTypePointer> interfaceFunctions(bool _includeInheritedFunctions = true) const;
std::vector<std::pair<util::FixedHash<4>, FunctionTypePointer>> const& interfaceFunctionList(bool _includeInheritedFunctions = true) const;
/// @returns a list of all declarations in this contract
std::vector<Declaration const*> declarations() const { return filteredNodes<Declaration>(m_subNodes); }
@@ -528,7 +528,7 @@ private:
ContractKind m_contractKind;
bool m_abstract{false};
mutable std::unique_ptr<std::vector<std::pair<util::FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList;
mutable std::unique_ptr<std::vector<std::pair<util::FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList[2];
mutable std::unique_ptr<std::vector<EventDefinition const*>> m_interfaceEvents;
};
+3 -1
View File
@@ -3719,7 +3719,9 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
{"name", TypeProvider::stringMemory()},
});
else
return {};
return MemberList::MemberMap({
{"interfaceId", TypeProvider::fixedBytes(4)},
});
}
}
solAssert(false, "Unknown kind of magic.");
@@ -1580,6 +1580,15 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
utils().storeStringData(contract.name());
}
else if (member == "interfaceId")
{
TypePointer arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*arg).contractDefinition();
uint64_t result{0};
for (auto const& function: contract.interfaceFunctionList(false))
result ^= fromBigEndian<uint64_t>(function.first.ref());
m_context << (u256{result} << (256 - 32));
}
else if ((set<string>{"encode", "encodePacked", "encodeWithSelector", "encodeWithSignature", "decode"}).count(member))
{
// no-op
@@ -754,6 +754,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
}
break;
}
case FunctionType::Kind::MetaType:
{
break;
}
default:
solUnimplemented("FunctionKind " + toString(static_cast<int>(functionType->kind())) + " not yet implemented");
}
@@ -904,6 +908,15 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
{
solUnimplementedAssert(false, "");
}
else if (member == "interfaceId")
{
TypePointer arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*arg).contractDefinition();
uint64_t result{0};
for (auto const& function: contract.interfaceFunctionList(false))
result ^= fromBigEndian<uint64_t>(function.first.ref());
define(_memberAccess) << formatNumber(u256{result} << (256 - 32)) << "\n";
}
else if (set<string>{"encode", "encodePacked", "encodeWithSelector", "encodeWithSignature", "decode"}.count(member))
{
// no-op