Improve typehash() computation for nested structs

This commit is contained in:
Anton Bukov 2023-05-04 17:35:59 +02:00
parent f9a48b94d4
commit 9b4da6bdea
3 changed files with 37 additions and 12 deletions

View File

@ -389,22 +389,39 @@ std::vector<std::pair<ASTPointer<IdentifierPath>, std::optional<Token>>> UsingFo
return ranges::zip_view(m_functionsOrLibrary, m_operators) | ranges::to<vector>; return ranges::zip_view(m_functionsOrLibrary, m_operators) | ranges::to<vector>;
} }
std::string StructDefinition::encodeType() const void StructDefinition::insertEncodedSubtypes(std::set<std::string>& subtypes) const
{
for (size_t i = 0; i < m_members.size(); i++)
{
if (m_members[i]->type()->category() == Type::Category::Struct)
{
Declaration const* declaration = m_members[i]->type()->typeDefinition();
StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration);
solAssert(structDef != nullptr);
subtypes.insert(structDef->encodeTypeWithoutSubtypes());
structDef->insertEncodedSubtypes(subtypes);
}
}
}
std::string StructDefinition::encodeTypeWithoutSubtypes() const
{ {
std::string str = name() + "("; std::string str = name() + "(";
std::set<std::string> nested; // std::set enables duplicates elimination and ordered enumeration
for (size_t i = 0; i < m_members.size(); i++) for (size_t i = 0; i < m_members.size(); i++)
{ {
str += i == 0 ? "" : ","; str += i == 0 ? "" : ",";
str += m_members[i]->type()->canonicalName() + " " + m_members[i]->name(); str += m_members[i]->type()->canonicalName() + " " + m_members[i]->name();
if (m_members[i]->type()->category() == Type::Category::Struct) {
Declaration const* declaration = m_members[i]->type()->typeDefinition();
if (StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration)) {
nested.insert(structDef->encodeType());
} }
return str + ")";
} }
}
return std::accumulate(nested.begin(), nested.end(), str + ")"); std::string StructDefinition::encodeType() const
{
// std::set enables duplicates elimination and ordered enumeration
std::set<std::string> subtypes;
insertEncodedSubtypes(subtypes);
return std::accumulate(subtypes.begin(), subtypes.end(), encodeTypeWithoutSubtypes());
} }
util::h256 StructDefinition::typehash() const util::h256 StructDefinition::typehash() const

View File

@ -741,7 +741,13 @@ public:
std::vector<ASTPointer<VariableDeclaration>> const& members() const { return m_members; } std::vector<ASTPointer<VariableDeclaration>> const& members() const { return m_members; }
/// @returns the EIP-712 compatible struct encoding. /// Fills set with the EIP-712 compatible struct encodings without subtypes concatenated.
void insertEncodedSubtypes(std::set<std::string>& subtypes) const;
/// @returns the EIP-712 compatible struct encoding but without subtypes concatenated.
std::string encodeTypeWithoutSubtypes() const;
/// @returns the EIP-712 compatible struct encoding with subtypes sorted and concatenated.
std::string encodeType() const; std::string encodeType() const;
/// @returns the EIP-712 compatible typehash of this struct. /// @returns the EIP-712 compatible typehash of this struct.

View File

@ -1944,8 +1944,10 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
else if (member == "typehash") else if (member == "typehash")
{ {
Type const* arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument(); Type const* arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
auto const& structType = dynamic_cast<StructType const&>(*arg); solAssert(arg != nullptr);
StructDefinition const& struct_ = structType.structDefinition(); StructType const* structType = dynamic_cast<StructType const*>(arg);
solAssert(structType != nullptr);
StructDefinition const& struct_ = structType->structDefinition();
define(_memberAccess) << formatNumber(struct_.typehash()) << "\n"; define(_memberAccess) << formatNumber(struct_.typehash()) << "\n";
} }
else if (member == "min" || member == "max") else if (member == "min" || member == "max")