From 54b46ce39e6ec0cd101ae93a10d3671b9f36afc2 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Fri, 28 Apr 2023 10:54:52 +0200 Subject: [PATCH 01/34] Add native support of EIP-712 struct typehash --- docs/cheatsheet.rst | 1 + docs/units-and-global-variables.rst | 7 +++++++ libsolidity/analysis/TypeChecker.cpp | 2 ++ libsolidity/analysis/ViewPureChecker.cpp | 1 + libsolidity/ast/AST.cpp | 11 +++++++++++ libsolidity/ast/AST.h | 3 +++ libsolidity/ast/Types.cpp | 7 +++++++ libsolidity/codegen/ExpressionCompiler.cpp | 6 ++++++ libsolidity/codegen/ir/IRGeneratorForStatements.cpp | 7 +++++++ libsolidity/formal/SMTEncoder.cpp | 5 +++++ test/libsolidity/analysis/FunctionCallGraph.cpp | 4 ++++ 11 files changed, 54 insertions(+) diff --git a/docs/cheatsheet.rst b/docs/cheatsheet.rst index 34ad46df6..cba123c77 100644 --- a/docs/cheatsheet.rst +++ b/docs/cheatsheet.rst @@ -119,6 +119,7 @@ Type Information - ``type(C).creationCode`` (``bytes memory``): creation bytecode of the given contract, see :ref:`Type Information`. - ``type(C).runtimeCode`` (``bytes memory``): runtime bytecode of the given contract, see :ref:`Type Information`. - ``type(I).interfaceId`` (``bytes4``): value containing the EIP-165 interface identifier of the given interface, see :ref:`Type Information`. +- ``type(S).typehash`` (``bytes32``): the typehash of the given struct type ``S``, see :ref:`Type Information`. - ``type(T).min`` (``T``): the minimum value representable by the integer type ``T``, see :ref:`Type Information`. - ``type(T).max`` (``T``): the maximum value representable by the integer type ``T``, see :ref:`Type Information`. diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index e70299679..d11458dff 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -385,6 +385,13 @@ for an interface type ``I``: interface identifier of the given interface ``I``. This identifier is defined as the ``XOR`` of all function selectors defined within the interface itself - excluding all inherited functions. +The following properties are available for an struct type ``S``: + +``type(S).typehash``: + A ``bytes32`` value containing the `EIP-712 `_ + typehash of the given structure ``S``. This identifier is defined as ``keccak256`` of + structure name and all the fields with their types, wrapped in braces and separated by commas. + The following properties are available for an integer type ``T``: ``type(T).min`` diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index e7721fd9e..a239df58c 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -3391,6 +3391,8 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) annotation.isPure = true; else if (magicType->kind() == MagicType::Kind::MetaType && memberName == "interfaceId") annotation.isPure = true; + else if (magicType->kind() == MagicType::Kind::MetaType && memberName == "typehash") + annotation.isPure = true; else if ( magicType->kind() == MagicType::Kind::MetaType && (memberName == "min" || memberName == "max") diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index c370f8f9f..608ef3c9f 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -398,6 +398,7 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess) {MagicType::Kind::MetaType, "runtimeCode"}, {MagicType::Kind::MetaType, "name"}, {MagicType::Kind::MetaType, "interfaceId"}, + {MagicType::Kind::MetaType, "typehash"}, {MagicType::Kind::MetaType, "min"}, {MagicType::Kind::MetaType, "max"}, }; diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 833ba739e..d75c0d63d 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -389,6 +389,17 @@ std::vector, std::optional>> UsingFo return ranges::zip_view(m_functionsOrLibrary, m_operators) | ranges::to; } +util::h256 StructDefinition::typehash() const +{ + std::string str = name() + "("; + for (size_t i = 0; i < m_members.size(); i++) + { + str += i == 0 ? "" : ","; + str += m_members[i]->type()->canonicalName() + " " + m_members[i]->name(); + } + return util::keccak256(str + ")"); +} + Type const* StructDefinition::type() const { solAssert(annotation().recursive.has_value(), "Requested struct type before DeclarationTypeChecker."); diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 9d754202d..88171361d 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -741,6 +741,9 @@ public: std::vector> const& members() const { return m_members; } + /// @returns the EIP-712 compatible typehash of this struct. + util::h256 typehash() const; + Type const* type() const override; bool isVisibleInDerivedContracts() const override { return true; } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 6308dbe3d..facbb35d3 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -4213,6 +4213,13 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const {"name", TypeProvider::stringMemory()}, }); } + else if (m_typeArgument->category() == Type::Category::Struct) + { + StructType const* structTypePointer = dynamic_cast(m_typeArgument); + return MemberList::MemberMap({ + {"typehash", structTypePointer}, + }); + } else if (m_typeArgument->category() == Type::Category::Integer) { IntegerType const* integerTypePointer = dynamic_cast(m_typeArgument); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 25bd15d5a..10311933f 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1931,6 +1931,12 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) ContractDefinition const& contract = dynamic_cast(*arg).contractDefinition(); m_context << (u256{contract.interfaceId()} << (256 - 32)); } + else if (member == "typehash") + { + Type const* arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); + StructDefinition const& struct_ = dynamic_cast(*arg).structDefinition(); + m_context << struct_.typehash(); + } else if (member == "min" || member == "max") { MagicType const* arg = dynamic_cast(_memberAccess.expression().annotation().type); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 509cc28c7..2cbecadd3 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1941,6 +1941,13 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) ContractDefinition const& contract = contractType.contractDefinition(); define(_memberAccess) << formatNumber(u256{contract.interfaceId()} << (256 - 32)) << "\n"; } + else if (member == "typehash") + { + Type const* arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); + auto const& structType = dynamic_cast(*arg); + StructDefinition const& struct_ = structType.structDefinition(); + define(_memberAccess) << formatNumber(struct_.typehash()) << "\n"; + } else if (member == "min" || member == "max") { MagicType const* arg = dynamic_cast(_memberAccess.expression().annotation().type); diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index a328a7781..c0b73c34c 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -1409,6 +1409,11 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess) ContractDefinition const& contract = dynamic_cast(*magicType->typeArgument()).contractDefinition(); defineExpr(_memberAccess, contract.interfaceId()); } + else if (memberName == "typehash") + { + StructDefinition const& structDef = dynamic_cast(*magicType->typeArgument()).structDefinition(); + defineExpr(_memberAccess, u256(structDef.typehash())); + } else // NOTE: supporting name, creationCode, runtimeCode would be easy enough, but the bytes/string they return are not // at all usable in the SMT checker currently diff --git a/test/libsolidity/analysis/FunctionCallGraph.cpp b/test/libsolidity/analysis/FunctionCallGraph.cpp index da17fc433..96e92d7a9 100644 --- a/test/libsolidity/analysis/FunctionCallGraph.cpp +++ b/test/libsolidity/analysis/FunctionCallGraph.cpp @@ -1916,6 +1916,9 @@ BOOST_AUTO_TEST_CASE(builtins) interface I {} contract C { + struct S { + uint x; + } function accessBuiltin() public payable { abi.decode; abi.encode; @@ -1956,6 +1959,7 @@ BOOST_AUTO_TEST_CASE(builtins) address(0).staticcall; type(C).name; type(I).interfaceId; + type(S).typehash; type(uint).min; type(uint).max; assert; From f9a48b94d41d4838cefbc5daa5dcc1748810ea56 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Thu, 4 May 2023 13:36:06 +0200 Subject: [PATCH 02/34] Handle nested structs encoding for EIP-712 --- libsolidity/ast/AST.cpp | 16 ++++++++++++++-- libsolidity/ast/AST.h | 3 +++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index d75c0d63d..1166d8ffd 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -389,15 +389,27 @@ std::vector, std::optional>> UsingFo return ranges::zip_view(m_functionsOrLibrary, m_operators) | ranges::to; } -util::h256 StructDefinition::typehash() const +std::string StructDefinition::encodeType() const { std::string str = name() + "("; + std::set nested; // std::set enables duplicates elimination and ordered enumeration for (size_t i = 0; i < m_members.size(); i++) { str += i == 0 ? "" : ","; 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(declaration)) { + nested.insert(structDef->encodeType()); + } + } } - return util::keccak256(str + ")"); + return std::accumulate(nested.begin(), nested.end(), str + ")"); +} + +util::h256 StructDefinition::typehash() const +{ + return util::keccak256(encodeType()); } Type const* StructDefinition::type() const diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 88171361d..2d5cce81c 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -741,6 +741,9 @@ public: std::vector> const& members() const { return m_members; } + /// @returns the EIP-712 compatible struct encoding. + std::string encodeType() const; + /// @returns the EIP-712 compatible typehash of this struct. util::h256 typehash() const; From 9b4da6bdea3910359e935d58269ed11cb60f8024 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Thu, 4 May 2023 17:35:59 +0200 Subject: [PATCH 03/34] Improve typehash() computation for nested structs --- libsolidity/ast/AST.cpp | 35 ++++++++++++++----- libsolidity/ast/AST.h | 8 ++++- .../codegen/ir/IRGeneratorForStatements.cpp | 6 ++-- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 1166d8ffd..566187191 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -389,22 +389,39 @@ std::vector, std::optional>> UsingFo return ranges::zip_view(m_functionsOrLibrary, m_operators) | ranges::to; } -std::string StructDefinition::encodeType() const +void StructDefinition::insertEncodedSubtypes(std::set& 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(declaration); + solAssert(structDef != nullptr); + + subtypes.insert(structDef->encodeTypeWithoutSubtypes()); + structDef->insertEncodedSubtypes(subtypes); + } + } +} + +std::string StructDefinition::encodeTypeWithoutSubtypes() const { std::string str = name() + "("; - std::set nested; // std::set enables duplicates elimination and ordered enumeration for (size_t i = 0; i < m_members.size(); i++) { str += i == 0 ? "" : ","; 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(declaration)) { - nested.insert(structDef->encodeType()); - } - } } - return std::accumulate(nested.begin(), nested.end(), str + ")"); + return str + ")"; +} + +std::string StructDefinition::encodeType() const +{ + // std::set enables duplicates elimination and ordered enumeration + std::set subtypes; + insertEncodedSubtypes(subtypes); + return std::accumulate(subtypes.begin(), subtypes.end(), encodeTypeWithoutSubtypes()); } util::h256 StructDefinition::typehash() const diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 2d5cce81c..e11cda10e 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -741,7 +741,13 @@ public: std::vector> 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& 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; /// @returns the EIP-712 compatible typehash of this struct. diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 2cbecadd3..277b81fec 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1944,8 +1944,10 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) else if (member == "typehash") { Type const* arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); - auto const& structType = dynamic_cast(*arg); - StructDefinition const& struct_ = structType.structDefinition(); + solAssert(arg != nullptr); + StructType const* structType = dynamic_cast(arg); + solAssert(structType != nullptr); + StructDefinition const& struct_ = structType->structDefinition(); define(_memberAccess) << formatNumber(struct_.typehash()) << "\n"; } else if (member == "min" || member == "max") From b267b0e8cddba761308e6085e138100f0a4b8ee6 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Thu, 4 May 2023 18:04:38 +0200 Subject: [PATCH 04/34] Add missing includes --- libsolidity/ast/AST.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 566187191..f6b82f00c 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -38,6 +38,8 @@ #include #include +#include +#include using namespace std; using namespace solidity; From 09e85879d76cbb5c2a440a5781aa0955a06a32b6 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Sat, 6 May 2023 22:53:52 +0300 Subject: [PATCH 05/34] Some fixes --- libsolidity/ast/Types.cpp | 3 +-- libsolidity/codegen/ir/IRGeneratorForStatements.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index facbb35d3..764d98816 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -4215,9 +4215,8 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const } else if (m_typeArgument->category() == Type::Category::Struct) { - StructType const* structTypePointer = dynamic_cast(m_typeArgument); return MemberList::MemberMap({ - {"typehash", structTypePointer}, + {"typehash", TypeProvider::fixedBytes(32)}, }); } else if (m_typeArgument->category() == Type::Category::Integer) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 277b81fec..4a2019f4c 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1948,7 +1948,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) StructType const* structType = dynamic_cast(arg); solAssert(structType != nullptr); StructDefinition const& struct_ = structType->structDefinition(); - define(_memberAccess) << formatNumber(struct_.typehash()) << "\n"; + define(_memberAccess) << "0x" << toHex(struct_.typehash()) << "\n"; } else if (member == "min" || member == "max") { From 66c54ef128af8b14ca32a6e48aebe01aa3ccf383 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Sat, 6 May 2023 23:10:32 +0300 Subject: [PATCH 06/34] Fix wrong failure --- libsolidity/ast/Types.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 764d98816..b132e4ff8 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -4189,15 +4189,7 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const }); case Kind::MetaType: { - solAssert( - m_typeArgument && ( - m_typeArgument->category() == Type::Category::Contract || - m_typeArgument->category() == Type::Category::Integer || - m_typeArgument->category() == Type::Category::Enum - ), - "Only enums, contracts or integer types supported for now" - ); - + solAssert(m_typeArgument != nullptr, ""); if (m_typeArgument->category() == Type::Category::Contract) { ContractDefinition const& contract = dynamic_cast(*m_typeArgument).contractDefinition(); @@ -4235,6 +4227,10 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const {"max", enumTypePointer}, }); } + else + { + solAssert(false, "Only enums, contracts, structs or integer types supported for now"); + } } } solAssert(false, "Unknown kind of magic."); From e8a311268d6a9dccb0b5bad0b3c88b6fd8eeddb8 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Sat, 6 May 2023 23:53:57 +0300 Subject: [PATCH 07/34] Extend type(X) validation to support structs --- libsolidity/analysis/TypeChecker.cpp | 1 + libsolidity/ast/TypeProvider.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index a239df58c..1aece87c7 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -316,6 +316,7 @@ TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(Functio wrongType = contractType->isSuper(); else if ( typeCategory != Type::Category::Integer && + typeCategory != Type::Category::Struct && typeCategory != Type::Category::Enum ) wrongType = true; diff --git a/libsolidity/ast/TypeProvider.cpp b/libsolidity/ast/TypeProvider.cpp index 6cf8b5c03..0eb5693dd 100644 --- a/libsolidity/ast/TypeProvider.cpp +++ b/libsolidity/ast/TypeProvider.cpp @@ -563,10 +563,11 @@ MagicType const* TypeProvider::meta(Type const* _type) solAssert( _type && ( _type->category() == Type::Category::Contract || + _type->category() == Type::Category::Struct || _type->category() == Type::Category::Integer || _type->category() == Type::Category::Enum ), - "Only enum, contracts or integer types supported for now." + "Only enum, contract, struct or integer types supported for now." ); return createAndGet(_type); } From 8c1a9af76ace5c705cfbc622f1e029c3d0776882 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Sun, 7 May 2023 00:06:27 +0300 Subject: [PATCH 08/34] Fix false positive test for type(S).typehash and update error messages --- libsolidity/analysis/TypeChecker.cpp | 2 +- .../syntaxTests/array/concat/bytes_concat_on_type_info.sol | 2 +- .../syntaxTests/errors/bytes_concat_on_error_type_info.sol | 2 +- .../syntaxTests/events/bytes_concat_on_event_type_info.sol | 2 +- test/libsolidity/syntaxTests/metaTypes/codeAccess_super.sol | 2 +- test/libsolidity/syntaxTests/metaTypes/interfaceid_super.sol | 2 +- test/libsolidity/syntaxTests/metaTypes/super_name.sol | 2 +- test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol | 2 +- .../syntaxTests/metaTypes/unsupported_arg_for_type.sol | 5 ++--- test/libsolidity/syntaxTests/tryCatch/no_special.sol | 2 +- 10 files changed, 11 insertions(+), 12 deletions(-) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 1aece87c7..0b66f7ef3 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -329,7 +329,7 @@ TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(Functio 4259_error, arguments.front()->location(), "Invalid type for argument in the function call. " - "An enum type, contract type or an integer type is required, but " + + "An enum type, contract type, struct type or an integer type is required, but " + type(*arguments.front())->humanReadableName() + " provided." ); diff --git a/test/libsolidity/syntaxTests/array/concat/bytes_concat_on_type_info.sol b/test/libsolidity/syntaxTests/array/concat/bytes_concat_on_type_info.sol index 895021733..87208373b 100644 --- a/test/libsolidity/syntaxTests/array/concat/bytes_concat_on_type_info.sol +++ b/test/libsolidity/syntaxTests/array/concat/bytes_concat_on_type_info.sol @@ -5,4 +5,4 @@ contract C { } } // ---- -// TypeError 4259: (93-98): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(bytes storage pointer) provided. +// TypeError 4259: (93-98): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but type(bytes storage pointer) provided. diff --git a/test/libsolidity/syntaxTests/errors/bytes_concat_on_error_type_info.sol b/test/libsolidity/syntaxTests/errors/bytes_concat_on_error_type_info.sol index 4b8bbd459..f1823cd86 100644 --- a/test/libsolidity/syntaxTests/errors/bytes_concat_on_error_type_info.sol +++ b/test/libsolidity/syntaxTests/errors/bytes_concat_on_error_type_info.sol @@ -6,4 +6,4 @@ contract C { } } // ---- -// TypeError 4259: (126-139): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but error MyCustomError(uint256,bool) provided. +// TypeError 4259: (126-139): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but error MyCustomError(uint256,bool) provided. diff --git a/test/libsolidity/syntaxTests/events/bytes_concat_on_event_type_info.sol b/test/libsolidity/syntaxTests/events/bytes_concat_on_event_type_info.sol index 40323830e..7f0fcda8a 100644 --- a/test/libsolidity/syntaxTests/events/bytes_concat_on_event_type_info.sol +++ b/test/libsolidity/syntaxTests/events/bytes_concat_on_event_type_info.sol @@ -6,4 +6,4 @@ contract C { } } // ---- -// TypeError 4259: (124-137): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but event MyCustomEvent(uint256) provided. +// TypeError 4259: (124-137): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but event MyCustomEvent(uint256) provided. diff --git a/test/libsolidity/syntaxTests/metaTypes/codeAccess_super.sol b/test/libsolidity/syntaxTests/metaTypes/codeAccess_super.sol index 7d057e132..788f081ea 100644 --- a/test/libsolidity/syntaxTests/metaTypes/codeAccess_super.sol +++ b/test/libsolidity/syntaxTests/metaTypes/codeAccess_super.sol @@ -10,4 +10,4 @@ contract SuperTest is Other { } } // ---- -// TypeError 4259: (177-182): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(contract super SuperTest) provided. +// TypeError 4259: (177-182): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but type(contract super SuperTest) provided. diff --git a/test/libsolidity/syntaxTests/metaTypes/interfaceid_super.sol b/test/libsolidity/syntaxTests/metaTypes/interfaceid_super.sol index 0740b31cf..6635b10f9 100644 --- a/test/libsolidity/syntaxTests/metaTypes/interfaceid_super.sol +++ b/test/libsolidity/syntaxTests/metaTypes/interfaceid_super.sol @@ -14,4 +14,4 @@ abstract contract Test is ERC165 { } } // ---- -// TypeError 4259: (592-597): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(contract super Test) provided. +// TypeError 4259: (592-597): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but type(contract super Test) provided. diff --git a/test/libsolidity/syntaxTests/metaTypes/super_name.sol b/test/libsolidity/syntaxTests/metaTypes/super_name.sol index 5795b8190..6a2f98e99 100644 --- a/test/libsolidity/syntaxTests/metaTypes/super_name.sol +++ b/test/libsolidity/syntaxTests/metaTypes/super_name.sol @@ -50,4 +50,4 @@ contract D is B, C { } } // ---- -// TypeError 4259: (426-431): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(contract super B) provided. +// TypeError 4259: (426-431): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but type(contract super B) provided. diff --git a/test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol b/test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol index 427caf4d0..c9ab5e6a1 100644 --- a/test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol +++ b/test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol @@ -4,4 +4,4 @@ contract Test { } } // ---- -// TypeError 4259: (65-75): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(contract Test) provided. +// TypeError 4259: (65-75): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but type(contract Test) provided. diff --git a/test/libsolidity/syntaxTests/metaTypes/unsupported_arg_for_type.sol b/test/libsolidity/syntaxTests/metaTypes/unsupported_arg_for_type.sol index aa7686ed8..a2b66a5b3 100644 --- a/test/libsolidity/syntaxTests/metaTypes/unsupported_arg_for_type.sol +++ b/test/libsolidity/syntaxTests/metaTypes/unsupported_arg_for_type.sol @@ -1,9 +1,8 @@ contract Test { - struct S { uint x; } function f() public pure { // Unsupported for now, but might be supported in the future - type(S); + type(bytes32); } } // ---- -// TypeError 4259: (154-155): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(struct Test.S storage pointer) provided. +// TypeError 4259: (154-155): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but type(struct Test.S storage pointer) provided. diff --git a/test/libsolidity/syntaxTests/tryCatch/no_special.sol b/test/libsolidity/syntaxTests/tryCatch/no_special.sol index d760e6ee3..2e572ea45 100644 --- a/test/libsolidity/syntaxTests/tryCatch/no_special.sol +++ b/test/libsolidity/syntaxTests/tryCatch/no_special.sol @@ -14,4 +14,4 @@ contract C { // ---- // TypeError 5347: (72-76): Try can only be used with external function calls and contract creation calls. // TypeError 2536: (119-128): Try can only be used with external function calls and contract creation calls. -// TypeError 4259: (176-183): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(address) provided. +// TypeError 4259: (176-183): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but type(address) provided. From cebf2d2ca7f087f22500a6c4aa247b9f2dcce1af Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Sun, 7 May 2023 00:12:25 +0300 Subject: [PATCH 09/34] Add tests for type(S).typehash --- .../smtCheckerTests/types/type_typehash.sol | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 test/libsolidity/smtCheckerTests/types/type_typehash.sol diff --git a/test/libsolidity/smtCheckerTests/types/type_typehash.sol b/test/libsolidity/smtCheckerTests/types/type_typehash.sol new file mode 100644 index 000000000..757f795bc --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/type_typehash.sol @@ -0,0 +1,45 @@ +interface I1 { +} + +contract C { + struct S1 { + uint256 x; + } + + struct S2 { + uint256 x; + address y; + } + + struct S3 { + uint256 x; + I1 y; + S2 third; + } + + struct S4 { + S3 one; + S2 two; + } + + struct S5 { + S2 two; + S1 one; + S3 three; + S4[5] four; + } + + function f() public pure { + assert(type(S1).typehash == keccak256(bytes("S1(uint256 x)"))); + assert(type(S2).typehash == keccak256(bytes("S2(uint256 x,address y)"))); + assert(type(S3).typehash == keccak256(bytes("S3(uint256 x,address y,S2 third)S2(uint256 x,address y)"))); + assert(type(S4).typehash == keccak256(bytes("S4(S3 one,S2 two)S2(uint256 x,address y)S3(uint256 x,address y,S2 third)"))); + assert(type(S5).typehash == keccak256(bytes("S5(S2 two,S1 one,S3 three,S4[5] four)S1(uint256 x)S2(uint256 x,address y)S3(uint256 x,address y,S2 third)S4(S3 one,S2 two)"))); + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (416-468): CHC: Assertion violation happens here. +// Warning 6328: (503-555): CHC: Assertion violation happens here. +// Info 1391: CHC: 5 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them. From 9e397f90ade34d1054cfcacec32d95abe4473830 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Sun, 7 May 2023 00:23:22 +0300 Subject: [PATCH 10/34] Fix test expected error --- test/libsolidity/smtCheckerTests/types/type_typehash.sol | 8 +++++--- .../syntaxTests/metaTypes/unsupported_arg_for_type.sol | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/test/libsolidity/smtCheckerTests/types/type_typehash.sol b/test/libsolidity/smtCheckerTests/types/type_typehash.sol index 757f795bc..5d07027ba 100644 --- a/test/libsolidity/smtCheckerTests/types/type_typehash.sol +++ b/test/libsolidity/smtCheckerTests/types/type_typehash.sol @@ -40,6 +40,8 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (416-468): CHC: Assertion violation happens here. -// Warning 6328: (503-555): CHC: Assertion violation happens here. -// Info 1391: CHC: 5 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them. +// Warning 6328: (386-448): CHC: Assertion violation happens here. +// Warning 6328: (452-524): CHC: Assertion violation happens here. +// Warning 6328: (528-632): CHC: Assertion violation happens here. +// Warning 6328: (642-763): CHC: Assertion violation happens here. +// Warning 6328: (773-944): CHC: Assertion violation happens here. diff --git a/test/libsolidity/syntaxTests/metaTypes/unsupported_arg_for_type.sol b/test/libsolidity/syntaxTests/metaTypes/unsupported_arg_for_type.sol index a2b66a5b3..b4bcf4ab6 100644 --- a/test/libsolidity/syntaxTests/metaTypes/unsupported_arg_for_type.sol +++ b/test/libsolidity/syntaxTests/metaTypes/unsupported_arg_for_type.sol @@ -5,4 +5,4 @@ contract Test { } } // ---- -// TypeError 4259: (154-155): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but type(struct Test.S storage pointer) provided. +// TypeError 4259: (129-136): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but type(bytes32) provided. From 4382dc3d2e5b32342495629e5ed8b1c328670c99 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Sun, 7 May 2023 01:16:46 +0300 Subject: [PATCH 11/34] Simplify type(S).typehash tests --- .../smtCheckerTests/types/type_typehash.sol | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/libsolidity/smtCheckerTests/types/type_typehash.sol b/test/libsolidity/smtCheckerTests/types/type_typehash.sol index 5d07027ba..50ac3ccfe 100644 --- a/test/libsolidity/smtCheckerTests/types/type_typehash.sol +++ b/test/libsolidity/smtCheckerTests/types/type_typehash.sol @@ -30,18 +30,18 @@ contract C { } function f() public pure { - assert(type(S1).typehash == keccak256(bytes("S1(uint256 x)"))); - assert(type(S2).typehash == keccak256(bytes("S2(uint256 x,address y)"))); - assert(type(S3).typehash == keccak256(bytes("S3(uint256 x,address y,S2 third)S2(uint256 x,address y)"))); - assert(type(S4).typehash == keccak256(bytes("S4(S3 one,S2 two)S2(uint256 x,address y)S3(uint256 x,address y,S2 third)"))); - assert(type(S5).typehash == keccak256(bytes("S5(S2 two,S1 one,S3 three,S4[5] four)S1(uint256 x)S2(uint256 x,address y)S3(uint256 x,address y,S2 third)S4(S3 one,S2 two)"))); + assert(type(S1).typehash == keccak256("S1(uint256 x)")); + assert(type(S2).typehash == keccak256("S2(uint256 x,address y)")); + assert(type(S3).typehash == keccak256("S3(uint256 x,address y,S2 third)S2(uint256 x,address y)")); + assert(type(S4).typehash == keccak256("S4(S3 one,S2 two)S2(uint256 x,address y)S3(uint256 x,address y,S2 third)")); + assert(type(S5).typehash == keccak256("S5(S2 two,S1 one,S3 three,S4[5] four)S1(uint256 x)S2(uint256 x,address y)S3(uint256 x,address y,S2 third)S4(S3 one,S2 two)")); } } // ==== // SMTEngine: all // ---- -// Warning 6328: (386-448): CHC: Assertion violation happens here. -// Warning 6328: (452-524): CHC: Assertion violation happens here. -// Warning 6328: (528-632): CHC: Assertion violation happens here. -// Warning 6328: (642-763): CHC: Assertion violation happens here. -// Warning 6328: (773-944): CHC: Assertion violation happens here. +// Warning 6328: (386-441): CHC: Assertion violation happens here. +// Warning 6328: (445-510): CHC: Assertion violation happens here. +// Warning 6328: (514-611): CHC: Assertion violation happens here. +// Warning 6328: (621-735): CHC: Assertion violation happens here. +// Warning 6328: (745-909): CHC: Assertion violation happens here. From e7bb0b38e196710e9ec0c593863a71d3e020fb31 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Tue, 9 May 2023 12:16:06 +0200 Subject: [PATCH 12/34] Rename methods encode* to eip712Encode* --- libsolidity/ast/AST.cpp | 16 ++++++++-------- libsolidity/ast/AST.h | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index f6b82f00c..d24184af8 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -391,7 +391,7 @@ std::vector, std::optional>> UsingFo return ranges::zip_view(m_functionsOrLibrary, m_operators) | ranges::to; } -void StructDefinition::insertEncodedSubtypes(std::set& subtypes) const +void StructDefinition::insertEip712EncodedSubtypes(std::set& subtypes) const { for (size_t i = 0; i < m_members.size(); i++) { @@ -401,13 +401,13 @@ void StructDefinition::insertEncodedSubtypes(std::set& subtypes) co StructDefinition const* structDef = dynamic_cast(declaration); solAssert(structDef != nullptr); - subtypes.insert(structDef->encodeTypeWithoutSubtypes()); - structDef->insertEncodedSubtypes(subtypes); + subtypes.insert(structDef->eip712EncodeTypeWithoutSubtypes()); + structDef->insertEip712EncodedSubtypes(subtypes); } } } -std::string StructDefinition::encodeTypeWithoutSubtypes() const +std::string StructDefinition::eip712EncodeTypeWithoutSubtypes() const { std::string str = name() + "("; for (size_t i = 0; i < m_members.size(); i++) @@ -418,17 +418,17 @@ std::string StructDefinition::encodeTypeWithoutSubtypes() const return str + ")"; } -std::string StructDefinition::encodeType() const +std::string StructDefinition::eip712EncodeType() const { // std::set enables duplicates elimination and ordered enumeration std::set subtypes; - insertEncodedSubtypes(subtypes); - return std::accumulate(subtypes.begin(), subtypes.end(), encodeTypeWithoutSubtypes()); + insertEip712EncodedSubtypes(subtypes); + return std::accumulate(subtypes.begin(), subtypes.end(), eip712EncodeTypeWithoutSubtypes()); } util::h256 StructDefinition::typehash() const { - return util::keccak256(encodeType()); + return util::keccak256(eip712EncodeType()); } Type const* StructDefinition::type() const diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index e11cda10e..eb39c7b35 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -742,13 +742,13 @@ public: std::vector> const& members() const { return m_members; } /// Fills set with the EIP-712 compatible struct encodings without subtypes concatenated. - void insertEncodedSubtypes(std::set& subtypes) const; + void insertEip712EncodedSubtypes(std::set& subtypes) const; /// @returns the EIP-712 compatible struct encoding but without subtypes concatenated. - std::string encodeTypeWithoutSubtypes() const; + std::string eip712EncodeTypeWithoutSubtypes() const; /// @returns the EIP-712 compatible struct encoding with subtypes sorted and concatenated. - std::string encodeType() const; + std::string eip712EncodeType() const; /// @returns the EIP-712 compatible typehash of this struct. util::h256 typehash() const; From 422676aef2df241f1efbf553842227419766bed9 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Tue, 9 May 2023 12:17:08 +0200 Subject: [PATCH 13/34] Update libsolidity/ast/Types.cpp Co-authored-by: Hari --- libsolidity/ast/Types.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index b132e4ff8..743e381f7 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -4189,7 +4189,7 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const }); case Kind::MetaType: { - solAssert(m_typeArgument != nullptr, ""); + solAssert(!m_typeArgument, ""); if (m_typeArgument->category() == Type::Category::Contract) { ContractDefinition const& contract = dynamic_cast(*m_typeArgument).contractDefinition(); From f9b9905c9505a38e37ceb99ec50e3421948ec834 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Tue, 9 May 2023 12:19:18 +0200 Subject: [PATCH 14/34] Update libsolidity/codegen/ExpressionCompiler.cpp Co-authored-by: Hari --- libsolidity/codegen/ExpressionCompiler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 10311933f..5ca059ab7 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1934,6 +1934,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) else if (member == "typehash") { Type const* arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); + solAssert(dynamic_cast(arg), "typehash called on a non-struct type") StructDefinition const& struct_ = dynamic_cast(*arg).structDefinition(); m_context << struct_.typehash(); } From 3efe10017948f7ce26ce5ea3c8b212c5d049d736 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Tue, 9 May 2023 12:19:50 +0200 Subject: [PATCH 15/34] Update libsolidity/codegen/ir/IRGeneratorForStatements.cpp Co-authored-by: Hari --- libsolidity/codegen/ir/IRGeneratorForStatements.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 4a2019f4c..9fdc1556e 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1944,9 +1944,9 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) else if (member == "typehash") { Type const* arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); - solAssert(arg != nullptr); + solAssert(!arg); StructType const* structType = dynamic_cast(arg); - solAssert(structType != nullptr); + solAssert(!structType); StructDefinition const& struct_ = structType->structDefinition(); define(_memberAccess) << "0x" << toHex(struct_.typehash()) << "\n"; } From 63210e5a6811b4e09ca4b0482d7752f9b959f7a7 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Tue, 9 May 2023 12:21:01 +0200 Subject: [PATCH 16/34] Update libsolidity/codegen/ir/IRGeneratorForStatements.cpp Co-authored-by: Hari --- libsolidity/codegen/ir/IRGeneratorForStatements.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 9fdc1556e..6240d5a22 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1948,7 +1948,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) StructType const* structType = dynamic_cast(arg); solAssert(!structType); StructDefinition const& struct_ = structType->structDefinition(); - define(_memberAccess) << "0x" << toHex(struct_.typehash()) << "\n"; + define(_memberAccess) << "0x" << struct_.typehash() << "\n"; } else if (member == "min" || member == "max") { From c4e8d3754d143020faf4a3cd36f80682f4b0d5f4 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Tue, 9 May 2023 12:34:38 +0200 Subject: [PATCH 17/34] Fix compilation error --- libsolidity/codegen/ExpressionCompiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 5ca059ab7..a53fa4627 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1934,7 +1934,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) else if (member == "typehash") { Type const* arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); - solAssert(dynamic_cast(arg), "typehash called on a non-struct type") + solAssert(dynamic_cast(arg), "typehash called on a non-struct type"); StructDefinition const& struct_ = dynamic_cast(*arg).structDefinition(); m_context << struct_.typehash(); } From 1d40bb4940c92a369105e98b3bfe536e024e8682 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Tue, 9 May 2023 12:38:12 +0200 Subject: [PATCH 18/34] Disallow to use typehash() for structs with nested mappings --- libsolidity/ast/AST.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index d24184af8..25d1c1eeb 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -420,6 +420,9 @@ std::string StructDefinition::eip712EncodeTypeWithoutSubtypes() const std::string StructDefinition::eip712EncodeType() const { + // EIP-712 supports recurvie structs, but not containing nested mappings + solAssert(!annotation().containsNestedMapping.has_value() || !annotation().containsNestedMapping.value(), "Struct containing mapping cannot be used in EIP-712."); + // std::set enables duplicates elimination and ordered enumeration std::set subtypes; insertEip712EncodedSubtypes(subtypes); From 7ffbfe67817ac0c29fe490f4a3dd003dca264b22 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Tue, 9 May 2023 13:54:41 +0200 Subject: [PATCH 19/34] Fix assert --- libsolidity/ast/Types.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 743e381f7..70239bf56 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -4189,7 +4189,7 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const }); case Kind::MetaType: { - solAssert(!m_typeArgument, ""); + solAssert(m_typeArgument, ""); if (m_typeArgument->category() == Type::Category::Contract) { ContractDefinition const& contract = dynamic_cast(*m_typeArgument).contractDefinition(); From a8dc240d42bd5e8f5c6c4d431131c2f401ed8c25 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Mon, 15 May 2023 09:26:56 +0200 Subject: [PATCH 20/34] Update libsolidity/codegen/ir/IRGeneratorForStatements.cpp Co-authored-by: Saw-mon & Natalie <3140080+Saw-mon-and-Natalie@users.noreply.github.com> --- libsolidity/codegen/ir/IRGeneratorForStatements.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 6240d5a22..7efaf8bb2 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1944,7 +1944,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) else if (member == "typehash") { Type const* arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); - solAssert(!arg); + solAssert(!!arg); StructType const* structType = dynamic_cast(arg); solAssert(!structType); StructDefinition const& struct_ = structType->structDefinition(); From 78981fac52ad4d4e19897855090cf70de09bfd8c Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Mon, 15 May 2023 09:27:12 +0200 Subject: [PATCH 21/34] Update libsolidity/codegen/ir/IRGeneratorForStatements.cpp Co-authored-by: Saw-mon & Natalie <3140080+Saw-mon-and-Natalie@users.noreply.github.com> --- libsolidity/codegen/ir/IRGeneratorForStatements.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 7efaf8bb2..ae251fb7d 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1946,7 +1946,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) Type const* arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); solAssert(!!arg); StructType const* structType = dynamic_cast(arg); - solAssert(!structType); + solAssert(!!structType); StructDefinition const& struct_ = structType->structDefinition(); define(_memberAccess) << "0x" << struct_.typehash() << "\n"; } From 145dfcf6da43e9ccb7854490fbe6a3d3d71e3255 Mon Sep 17 00:00:00 2001 From: Saw-mon & Natalie <3140080+Saw-mon-and-Natalie@users.noreply.github.com> Date: Tue, 16 May 2023 01:08:11 +0100 Subject: [PATCH 22/34] fixed EIP-712 encoding type. --- libsolidity/ast/AST.cpp | 36 +++++++++++++++++++++++++++--------- libsolidity/ast/Types.cpp | 22 ++++++++++++++++++++++ libsolidity/ast/Types.h | 16 ++++++++++++++++ 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 25d1c1eeb..77aff41bb 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -395,12 +395,33 @@ void StructDefinition::insertEip712EncodedSubtypes(std::set& subtyp { 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(declaration); - solAssert(structDef != nullptr); + Declaration const* declaration = nullptr; + switch (m_members[i]->type()->category()) + { + case Type::Category::Struct: + declaration = m_members[i]->type()->typeDefinition(); + break; + case Type::Category::Array: + { + auto const* arrayType = dynamic_cast(m_members[i]->type()); + solAssert(!!arrayType); + if (auto finalyBaseType = dynamic_cast(arrayType->finalBaseType(false))) + { + declaration = finalyBaseType->typeDefinition(); + } + } + break; + default: + continue; + } + + if(!declaration) { + continue; + } + + if (auto const* structDef = dynamic_cast(declaration)) + { subtypes.insert(structDef->eip712EncodeTypeWithoutSubtypes()); structDef->insertEip712EncodedSubtypes(subtypes); } @@ -413,16 +434,13 @@ std::string StructDefinition::eip712EncodeTypeWithoutSubtypes() const for (size_t i = 0; i < m_members.size(); i++) { str += i == 0 ? "" : ","; - str += m_members[i]->type()->canonicalName() + " " + m_members[i]->name(); + str += m_members[i]->type()->eip712TypeName() + " " + m_members[i]->name(); } return str + ")"; } std::string StructDefinition::eip712EncodeType() const { - // EIP-712 supports recurvie structs, but not containing nested mappings - solAssert(!annotation().containsNestedMapping.has_value() || !annotation().containsNestedMapping.value(), "Struct containing mapping cannot be used in EIP-712."); - // std::set enables duplicates elimination and ordered enumeration std::set subtypes; insertEip712EncodedSubtypes(subtypes); diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 70239bf56..7a916ff30 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1887,6 +1887,23 @@ string ArrayType::canonicalName() const return ret; } +string ArrayType::eip712TypeName() const +{ + string ret; + if (isString()) + ret = "string"; + else if (isByteArrayOrString()) + ret = "bytes"; + else + { + ret = baseType()->eip712TypeName() + "["; + if (!isDynamicallySized()) + ret += length().str(); + ret += "]"; + } + return ret; +} + string ArrayType::signatureInExternalFunction(bool _structsByName) const { if (isByteArrayOrString()) @@ -2511,6 +2528,11 @@ string StructType::canonicalName() const return *m_struct.annotation().canonicalName; } +string StructType::eip712TypeName() const +{ + return this->typeDefinition()->name(); +} + FunctionTypePointer StructType::constructorType() const { TypePointers paramTypes; diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 1fc0a7e17..783b2b259 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -357,6 +357,7 @@ public: /// @returns the canonical name of this type for use in library function signatures. virtual std::string canonicalName() const { return toString(true); } virtual std::string humanReadableName() const { return toString(); } + virtual std::string eip712TypeName() const { return encodingType()->toString(true); } /// @returns the signature of this type in external functions, i.e. `uint256` for integers /// or `(uint256,bytes8)[2]` for an array of structs. If @a _structsByName, /// structs are given by canonical name like `ContractName.StructName[2]`. @@ -551,6 +552,7 @@ public: bool nameable() const override { return true; } std::string toString(bool _withoutDataLocation) const override; + std::string eip712TypeName() const override{ solAssert(false, "EIP-712 is not supported for struct members of fixed point type"); } Type const* encodingType() const override { return this; } TypeResult interfaceType(bool) const override { return this; } @@ -867,6 +869,7 @@ public: std::string toString(bool _withoutDataLocation) const override; std::string humanReadableName() const override; std::string canonicalName() const override; + std::string eip712TypeName() const override; std::string signatureInExternalFunction(bool _structsByName) const override; MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override; Type const* encodingType() const override; @@ -924,6 +927,7 @@ public: BoolResult isImplicitlyConvertibleTo(Type const& _other) const override; BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; std::string richIdentifier() const override; + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of array slice type"); } bool operator==(Type const& _other) const override; unsigned calldataEncodedSize(bool) const override { solAssert(false, ""); } unsigned calldataEncodedTailSize() const override { return 32; } @@ -1052,6 +1056,7 @@ public: std::unique_ptr copyForLocation(DataLocation _location, bool _isPointer) const override; std::string canonicalName() const override; + std::string eip712TypeName() const override; std::string signatureInExternalFunction(bool _structsByName) const override; /// @returns a function that performs the type conversion between a list of struct members @@ -1100,6 +1105,7 @@ public: bool leftAligned() const override { return false; } std::string toString(bool _withoutDataLocation) const override; std::string canonicalName() const override; + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of Enum type"); } bool isValueType() const override { return true; } bool nameable() const override { return true; } @@ -1187,6 +1193,7 @@ public: std::string toString(bool _withoutDataLocation) const override; std::string canonicalName() const override; + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of user defined value type"); } std::string signatureInExternalFunction(bool) const override { solAssert(false, ""); } protected: @@ -1218,6 +1225,8 @@ public: bool hasSimpleZeroValueInMemory() const override { return false; } Type const* mobileType() const override; + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of tuple type"); } + std::vector const& components() const { return m_components; } protected: @@ -1415,6 +1424,7 @@ public: TypeResult binaryOperatorResult(Token, Type const*) const override; std::string canonicalName() const override; std::string humanReadableName() const override; + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of function type"); } std::string toString(bool _withoutDataLocation) const override; unsigned calldataEncodedSize(bool _padded) const override; bool canBeStored() const override { return m_kind == Kind::Internal || m_kind == Kind::External; } @@ -1551,6 +1561,7 @@ public: bool operator==(Type const& _other) const override; std::string toString(bool _withoutDataLocation) const override; std::string canonicalName() const override; + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of mapping type"); } bool containsNestedMapping() const override { return true; } TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; } Type const* encodingType() const override; @@ -1595,6 +1606,7 @@ public: bool operator==(Type const& _other) const override; bool canBeStored() const override { return false; } u256 storageSize() const override; + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of type type"); } bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); } std::string toString(bool _withoutDataLocation) const override { return "type(" + m_actualType->toString(_withoutDataLocation) + ")"; } MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override; @@ -1622,6 +1634,7 @@ public: u256 storageSize() const override; bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); } std::string richIdentifier() const override; + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of modfier type"); } bool operator==(Type const& _other) const override; std::string toString(bool _withoutDataLocation) const override; protected: @@ -1646,6 +1659,7 @@ public: std::string richIdentifier() const override; bool operator==(Type const& _other) const override; bool canBeStored() const override { return false; } + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of module type"); } bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); } MemberList::MemberMap nativeMembers(ASTNode const*) const override; @@ -1685,6 +1699,7 @@ public: std::string richIdentifier() const override; bool operator==(Type const& _other) const override; bool canBeStored() const override { return false; } + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of magic type"); } bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); } MemberList::MemberMap nativeMembers(ASTNode const*) const override; @@ -1718,6 +1733,7 @@ public: unsigned calldataEncodedSize(bool) const override { return 32; } bool canBeStored() const override { return false; } bool isValueType() const override { return true; } + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of inaccessible dynamic type"); } bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); } std::string toString(bool) const override { return "inaccessible dynamic type"; } Type const* decodingType() const override; From 89424875de30a3c097731f52b97c218a0553fc4c Mon Sep 17 00:00:00 2001 From: Saw-mon & Natalie <3140080+Saw-mon-and-Natalie@users.noreply.github.com> Date: Tue, 16 May 2023 01:11:07 +0100 Subject: [PATCH 23/34] fix coding style --- libsolidity/ast/AST.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 77aff41bb..3c9c64196 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -416,7 +416,8 @@ void StructDefinition::insertEip712EncodedSubtypes(std::set& subtyp continue; } - if(!declaration) { + if (!declaration) + { continue; } From 7de314bd0d81b17f326e9a3fc0d948a383b5b5ad Mon Sep 17 00:00:00 2001 From: Saw-mon & Natalie <3140080+Saw-mon-and-Natalie@users.noreply.github.com> Date: Tue, 16 May 2023 04:41:22 +0100 Subject: [PATCH 24/34] fixed typo --- libsolidity/ast/Types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 783b2b259..bca79f555 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -1634,7 +1634,7 @@ public: u256 storageSize() const override; bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); } std::string richIdentifier() const override; - std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of modfier type"); } + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of modifier type"); } bool operator==(Type const& _other) const override; std::string toString(bool _withoutDataLocation) const override; protected: From 8023619d5c1cb676d09775f1a8a0191ad8499d83 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Thu, 18 May 2023 18:56:57 +0200 Subject: [PATCH 25/34] Fix tests for compile-time checks --- .../smtCheckerTests/types/type_typehash.sol | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/test/libsolidity/smtCheckerTests/types/type_typehash.sol b/test/libsolidity/smtCheckerTests/types/type_typehash.sol index 50ac3ccfe..46673c3e6 100644 --- a/test/libsolidity/smtCheckerTests/types/type_typehash.sol +++ b/test/libsolidity/smtCheckerTests/types/type_typehash.sol @@ -30,18 +30,14 @@ contract C { } function f() public pure { - assert(type(S1).typehash == keccak256("S1(uint256 x)")); - assert(type(S2).typehash == keccak256("S2(uint256 x,address y)")); - assert(type(S3).typehash == keccak256("S3(uint256 x,address y,S2 third)S2(uint256 x,address y)")); - assert(type(S4).typehash == keccak256("S4(S3 one,S2 two)S2(uint256 x,address y)S3(uint256 x,address y,S2 third)")); - assert(type(S5).typehash == keccak256("S5(S2 two,S1 one,S3 three,S4[5] four)S1(uint256 x)S2(uint256 x,address y)S3(uint256 x,address y,S2 third)S4(S3 one,S2 two)")); + assert(type(S1).typehash == 0x78a822935e38445215ba7404686b919cbbef5725cbf9231d92802f542d7456e0); // keccak256("S1(uint256 x)") + assert(type(S2).typehash == 0x6c397ebd50462a81423e44830702ee1214cb9ab734bf173eb55f04238c9d398f); // keccak256("S2(uint256 x,address y)") + assert(type(S3).typehash == 0xfa5685568fb2f15c09479ecbcfe9d0494743d804587d1966db67d5e62ea4344a); // keccak256("S3(uint256 x,address y,S2 third)S2(uint256 x,address y)") + assert(type(S4).typehash == 0x17ed8da37c0446eeffef8cd38d116505b399b5644fdc3a59f8a68a68dd5d4178); // keccak256("S4(S3 one,S2 two)S2(uint256 x,address y)S3(uint256 x,address y,S2 third)") + assert(type(S5).typehash == 0x5e52252fbbc0eda2d75f57c57d47fbec3bc6b215a9a3790c7f7ca44a36eb5185); // keccak256("S5(S2 two,S1 one,S3 three,S4[5] four)S1(uint256 x)S2(uint256 x,address y)S3(uint256 x,address y,S2 third)S4(S3 one,S2 two)") } } // ==== // SMTEngine: all // ---- -// Warning 6328: (386-441): CHC: Assertion violation happens here. -// Warning 6328: (445-510): CHC: Assertion violation happens here. -// Warning 6328: (514-611): CHC: Assertion violation happens here. -// Warning 6328: (621-735): CHC: Assertion violation happens here. -// Warning 6328: (745-909): CHC: Assertion violation happens here. +// Info 1391: CHC: 5 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them. From 84918fb01ef2b675ce88bc40d816fa6c172ca4d0 Mon Sep 17 00:00:00 2001 From: Saw-mon & Natalie <3140080+Saw-mon-and-Natalie@users.noreply.github.com> Date: Sun, 21 May 2023 16:41:06 +0100 Subject: [PATCH 26/34] added syntaxt tests and updated the TypeChecker logic. --- libsolidity/analysis/TypeChecker.cpp | 24 +++++++++++++++++++ libsolidity/ast/Types.h | 10 ++++++++ .../types/struct/typehash_const.sol | 7 ++++++ .../types/struct/typehash_contract.sol | 5 ++++ .../types/struct/typehash_enum.sol | 9 +++++++ .../types/struct/typehash_member_enum.sol | 14 +++++++++++ .../struct/typehash_member_fixed128x18.sol | 9 +++++++ .../types/struct/typehash_member_function.sol | 9 +++++++ .../types/struct/typehash_member_mapping.sol | 9 +++++++ .../struct/typehash_member_ufixed128x18.sol | 9 +++++++ .../struct/typehash_member_userdefined.sol | 10 ++++++++ .../types/struct/typehash_pure.sol | 9 +++++++ .../struct/typehash_recursive_struct.sol | 9 +++++++ .../struct/typehash_recursive_struct_2.sol | 14 +++++++++++ .../types/struct/typehash_struct_variable.sol | 15 ++++++++++++ .../struct/typehash_struct_variable_2.sol | 15 ++++++++++++ .../types/struct/typehash_uint256.sol | 5 ++++ .../types/struct/typehash_viewpure.sol | 11 +++++++++ 18 files changed, 193 insertions(+) create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_const.sol create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_contract.sol create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_enum.sol create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_member_enum.sol create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_member_fixed128x18.sol create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_member_function.sol create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_member_mapping.sol create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_member_ufixed128x18.sol create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_member_userdefined.sol create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_pure.sol create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct.sol create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct_2.sol create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_struct_variable.sol create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_struct_variable_2.sol create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_uint256.sol create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_viewpure.sol diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 0b66f7ef3..5ff6f18f1 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -3393,7 +3393,31 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) else if (magicType->kind() == MagicType::Kind::MetaType && memberName == "interfaceId") annotation.isPure = true; else if (magicType->kind() == MagicType::Kind::MetaType && memberName == "typehash") + { annotation.isPure = true; + auto accessedStructType = dynamic_cast(magicType->typeArgument()); + solAssert(accessedStructType, "typehash requested on a non struct type."); + + if (accessedStructType->recursive()) { + m_errorReporter.typeError( + 9298_error, + _memberAccess.location(), + "\"typehash\" cannot be used for recursive structs." + ); + } + + for (auto const& member: accessedStructType->members(currentDefinitionScope())) + { + if (!member.type->isEIP712AllowedStructMemberType()) + { + m_errorReporter.typeError( + 9518_error, + _memberAccess.location(), + "\"typehash\" cannot be used for structs with members of \"" + member.type->humanReadableName() + "\" type." + ); + } + } + } else if ( magicType->kind() == MagicType::Kind::MetaType && (memberName == "min" || memberName == "max") diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index bca79f555..37cb843e8 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -358,6 +358,7 @@ public: virtual std::string canonicalName() const { return toString(true); } virtual std::string humanReadableName() const { return toString(); } virtual std::string eip712TypeName() const { return encodingType()->toString(true); } + virtual bool isEIP712AllowedStructMemberType() const { return false; } /// @returns the signature of this type in external functions, i.e. `uint256` for integers /// or `(uint256,bytes8)[2]` for an array of structs. If @a _structsByName, /// structs are given by canonical name like `ContractName.StructName[2]`. @@ -458,6 +459,7 @@ public: bool leftAligned() const override { return false; } bool isValueType() const override { return true; } bool nameable() const override { return true; } + bool isEIP712AllowedStructMemberType() const override { return true; } MemberList::MemberMap nativeMembers(ASTNode const*) const override; @@ -503,6 +505,7 @@ public: bool leftAligned() const override { return false; } bool isValueType() const override { return true; } bool nameable() const override { return true; } + bool isEIP712AllowedStructMemberType() const override { return true; } std::string toString(bool _withoutDataLocation) const override; @@ -662,6 +665,8 @@ public: return nullptr; } + bool isEIP712AllowedStructMemberType() const override { return true; } + std::string richIdentifier() const override; bool operator==(Type const& _other) const override; @@ -700,6 +705,7 @@ public: bool leftAligned() const override { return true; } bool isValueType() const override { return true; } bool nameable() const override { return true; } + bool isEIP712AllowedStructMemberType() const override { return true; } std::string toString(bool) const override { return "bytes" + util::toString(m_bytes); } MemberList::MemberMap nativeMembers(ASTNode const*) const override; @@ -728,6 +734,7 @@ public: bool leftAligned() const override { return false; } bool isValueType() const override { return true; } bool nameable() const override { return true; } + bool isEIP712AllowedStructMemberType() const override { return true; } std::string toString(bool) const override { return "bool"; } u256 literalValue(Literal const* _literal) const override; @@ -865,6 +872,7 @@ public: u256 storageSize() const override; bool containsNestedMapping() const override { return m_baseType->containsNestedMapping(); } bool nameable() const override { return true; } + bool isEIP712AllowedStructMemberType() const override { return true; } std::string toString(bool _withoutDataLocation) const override; std::string humanReadableName() const override; @@ -978,6 +986,7 @@ public: bool leftAligned() const override { solAssert(!isSuper(), ""); return false; } bool isValueType() const override { return !isSuper(); } bool nameable() const override { return !isSuper(); } + bool isEIP712AllowedStructMemberType() const override { return true; } std::string toString(bool _withoutDataLocation) const override; std::string canonicalName() const override; @@ -1040,6 +1049,7 @@ public: u256 storageSize() const override; bool containsNestedMapping() const override; bool nameable() const override { return true; } + bool isEIP712AllowedStructMemberType() const override { return true; } std::string toString(bool _withoutDataLocation) const override; MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override; diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_const.sol b/test/libsolidity/syntaxTests/types/struct/typehash_const.sol new file mode 100644 index 000000000..e9f33f1d1 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_const.sol @@ -0,0 +1,7 @@ +contract C { + struct S { + uint256[][10][] x; + } + + bytes32 constant h = type(S).typehash; +} \ No newline at end of file diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_contract.sol b/test/libsolidity/syntaxTests/types/struct/typehash_contract.sol new file mode 100644 index 000000000..22bad80aa --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_contract.sol @@ -0,0 +1,5 @@ +contract C { + bytes32 x = type(C).typehash; +} +// ---- +// TypeError 9582: (29-45): Member "typehash" not found or not visible after argument-dependent lookup in type(contract C). diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_enum.sol b/test/libsolidity/syntaxTests/types/struct/typehash_enum.sol new file mode 100644 index 000000000..670ef1ccf --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_enum.sol @@ -0,0 +1,9 @@ +contract C { + enum E { + VALUE + } + + bytes32 h = type(E).typehash; +} +// ---- +// TypeError 9582: (63-79): Member "typehash" not found or not visible after argument-dependent lookup in type(enum C.E). diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_member_enum.sol b/test/libsolidity/syntaxTests/types/struct/typehash_member_enum.sol new file mode 100644 index 000000000..695ef07ac --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_member_enum.sol @@ -0,0 +1,14 @@ +contract C { + enum E { + VALUE + } + + struct S { + E e; + } + + bytes32 h = type(S).typehash; +} + +// ---- +// TypeError 9518: (98-114): "typehash" cannot be used for structs with members of "enum C.E" type. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_member_fixed128x18.sol b/test/libsolidity/syntaxTests/types/struct/typehash_member_fixed128x18.sol new file mode 100644 index 000000000..0b3c5b57b --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_member_fixed128x18.sol @@ -0,0 +1,9 @@ +contract C { + struct S { + fixed128x18 x; + } + + bytes32 h = type(S).typehash; +} +// ---- +// TypeError 9518: (74-90): "typehash" cannot be used for structs with members of "fixed128x18" type. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_member_function.sol b/test/libsolidity/syntaxTests/types/struct/typehash_member_function.sol new file mode 100644 index 000000000..7e2e5895c --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_member_function.sol @@ -0,0 +1,9 @@ +contract C { + struct S { + function(uint256) internal returns(uint256) f; + } + + bytes32 h = type(S).typehash; +} +// ---- +// TypeError 9518: (106-122): "typehash" cannot be used for structs with members of "function (uint256) returns (uint256)" type. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_member_mapping.sol b/test/libsolidity/syntaxTests/types/struct/typehash_member_mapping.sol new file mode 100644 index 000000000..27dd775e6 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_member_mapping.sol @@ -0,0 +1,9 @@ +contract C { + struct S { + mapping (uint256 => uint256) x; + } + + bytes32 h = type(S).typehash; +} +// ---- +// TypeError 9518: (92-108): "typehash" cannot be used for structs with members of "mapping(uint256 => uint256)" type. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_member_ufixed128x18.sol b/test/libsolidity/syntaxTests/types/struct/typehash_member_ufixed128x18.sol new file mode 100644 index 000000000..5393a30e8 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_member_ufixed128x18.sol @@ -0,0 +1,9 @@ +contract C { + struct S { + ufixed128x18 x; + } + + bytes32 h = type(S).typehash; +} +// ---- +// TypeError 9518: (75-91): "typehash" cannot be used for structs with members of "ufixed128x18" type. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_member_userdefined.sol b/test/libsolidity/syntaxTests/types/struct/typehash_member_userdefined.sol new file mode 100644 index 000000000..5f46378c2 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_member_userdefined.sol @@ -0,0 +1,10 @@ +type T is uint256; +contract C { + struct S { + T t; + } + + bytes32 h = type(S).typehash; +} +// ---- +// TypeError 9518: (83-99): "typehash" cannot be used for structs with members of "T" type. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_pure.sol b/test/libsolidity/syntaxTests/types/struct/typehash_pure.sol new file mode 100644 index 000000000..fdca58e27 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_pure.sol @@ -0,0 +1,9 @@ +contract C { + struct S { + uint256 x; + } + + function f() public pure returns(bytes32) { + return type(S).typehash; + } +} \ No newline at end of file diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct.sol b/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct.sol new file mode 100644 index 000000000..018411d8b --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct.sol @@ -0,0 +1,9 @@ +contract C { + struct S { + S[] s; + } + + bytes32 h = type(S).typehash; +} +// ---- +// TypeError 9298: (68-84): "typehash" cannot be used for recursive structs. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct_2.sol b/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct_2.sol new file mode 100644 index 000000000..9f46255ed --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct_2.sol @@ -0,0 +1,14 @@ +contract A { + struct S { + C.S[] s; + } +} +contract C { + struct S { + A.S s; + } + + bytes32 h = type(S).typehash; +} +// ---- +// TypeError 9298: (121-137): "typehash" cannot be used for recursive structs. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_struct_variable.sol b/test/libsolidity/syntaxTests/types/struct/typehash_struct_variable.sol new file mode 100644 index 000000000..049bc46d5 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_struct_variable.sol @@ -0,0 +1,15 @@ +contract C { + struct S { + uint256 x; + } + + function f1(S calldata s) public pure returns(bytes32 h) { + h = type(s).typehash; // should fail + } + + function f3(S calldata s) public pure returns(bytes32 h) { + h = type(S).typehash; + } +} +// ---- +// TypeError 4259: (134-135): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but struct C.S calldata provided. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_struct_variable_2.sol b/test/libsolidity/syntaxTests/types/struct/typehash_struct_variable_2.sol new file mode 100644 index 000000000..9ba0bc761 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_struct_variable_2.sol @@ -0,0 +1,15 @@ +contract C { + struct S { + uint256 x; + } + + function f1(S memory s) public pure returns(bytes32 h) { + h = type(s).typehash; // should fail + } + + function f3(S calldata s) public pure returns(bytes32 h) { + h = type(S).typehash; + } +} +// ---- +// TypeError 4259: (132-133): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but struct C.S memory provided. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_uint256.sol b/test/libsolidity/syntaxTests/types/struct/typehash_uint256.sol new file mode 100644 index 000000000..d6ff2d73d --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_uint256.sol @@ -0,0 +1,5 @@ +contract C { + bytes32 h = type(uint256).typehash; +} +// ---- +// TypeError 9582: (29-51): Member "typehash" not found or not visible after argument-dependent lookup in type(uint256). diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_viewpure.sol b/test/libsolidity/syntaxTests/types/struct/typehash_viewpure.sol new file mode 100644 index 000000000..85bad50b2 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_viewpure.sol @@ -0,0 +1,11 @@ +contract C { + struct S { + uint256 x; + } + + function f() public view returns(bytes32) { // can be pure + return type(S).typehash; + } +} +// ---- +// Warning 2018: (58-155): Function state mutability can be restricted to pure From c6e73707c74f6067083fa5a4d7e9d8e758d0ba95 Mon Sep 17 00:00:00 2001 From: Saw-mon & Natalie <3140080+Saw-mon-and-Natalie@users.noreply.github.com> Date: Sun, 21 May 2023 16:59:40 +0100 Subject: [PATCH 27/34] fixed codestyle. --- libsolidity/analysis/TypeChecker.cpp | 3 ++- .../syntaxTests/types/struct/typehash_member_mapping.sol | 2 +- .../syntaxTests/types/struct/typehash_recursive_struct.sol | 4 ++-- .../syntaxTests/types/struct/typehash_recursive_struct_2.sol | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 5ff6f18f1..760041d15 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -3398,7 +3398,8 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) auto accessedStructType = dynamic_cast(magicType->typeArgument()); solAssert(accessedStructType, "typehash requested on a non struct type."); - if (accessedStructType->recursive()) { + if (accessedStructType->recursive()) + { m_errorReporter.typeError( 9298_error, _memberAccess.location(), diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_member_mapping.sol b/test/libsolidity/syntaxTests/types/struct/typehash_member_mapping.sol index 27dd775e6..8a876dec9 100644 --- a/test/libsolidity/syntaxTests/types/struct/typehash_member_mapping.sol +++ b/test/libsolidity/syntaxTests/types/struct/typehash_member_mapping.sol @@ -1,6 +1,6 @@ contract C { struct S { - mapping (uint256 => uint256) x; + mapping (uint256 => uint256) x; } bytes32 h = type(S).typehash; diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct.sol b/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct.sol index 018411d8b..eddfc17df 100644 --- a/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct.sol +++ b/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct.sol @@ -1,6 +1,6 @@ contract C { - struct S { - S[] s; + struct S { + S[] s; } bytes32 h = type(S).typehash; diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct_2.sol b/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct_2.sol index 9f46255ed..3ff539237 100644 --- a/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct_2.sol +++ b/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct_2.sol @@ -4,8 +4,8 @@ contract A { } } contract C { - struct S { - A.S s; + struct S { + A.S s; } bytes32 h = type(S).typehash; From 57d7226d1a321b3415f4172e177043fcb17178ca Mon Sep 17 00:00:00 2001 From: Saw-mon & Natalie <3140080+Saw-mon-and-Natalie@users.noreply.github.com> Date: Sun, 21 May 2023 17:15:20 +0100 Subject: [PATCH 28/34] fixed syntax test error messages. --- .../syntaxTests/types/struct/typehash_member_mapping.sol | 2 +- .../syntaxTests/types/struct/typehash_recursive_struct.sol | 2 +- .../syntaxTests/types/struct/typehash_recursive_struct_2.sol | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_member_mapping.sol b/test/libsolidity/syntaxTests/types/struct/typehash_member_mapping.sol index 8a876dec9..b5edc62ab 100644 --- a/test/libsolidity/syntaxTests/types/struct/typehash_member_mapping.sol +++ b/test/libsolidity/syntaxTests/types/struct/typehash_member_mapping.sol @@ -6,4 +6,4 @@ contract C { bytes32 h = type(S).typehash; } // ---- -// TypeError 9518: (92-108): "typehash" cannot be used for structs with members of "mapping(uint256 => uint256)" type. +// TypeError 9518: (91-107): "typehash" cannot be used for structs with members of "mapping(uint256 => uint256)" type. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct.sol b/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct.sol index eddfc17df..64d34716c 100644 --- a/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct.sol +++ b/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct.sol @@ -6,4 +6,4 @@ contract C { bytes32 h = type(S).typehash; } // ---- -// TypeError 9298: (68-84): "typehash" cannot be used for recursive structs. +// TypeError 9298: (66-82): "typehash" cannot be used for recursive structs. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct_2.sol b/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct_2.sol index 3ff539237..11897755a 100644 --- a/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct_2.sol +++ b/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct_2.sol @@ -11,4 +11,4 @@ contract C { bytes32 h = type(S).typehash; } // ---- -// TypeError 9298: (121-137): "typehash" cannot be used for recursive structs. +// TypeError 9298: (119-135): "typehash" cannot be used for recursive structs. From 283f85b091b6bf8b61dcd8bd3d44d1028a485b50 Mon Sep 17 00:00:00 2001 From: Saw-mon & Natalie <3140080+Saw-mon-and-Natalie@users.noreply.github.com> Date: Sun, 21 May 2023 17:48:58 +0100 Subject: [PATCH 29/34] more semantic and syntax tests --- .../types/type_typehash_different_scopes.sol | 25 +++++++++++++++++ .../types/type_typehash_inheritence.sol | 19 +++++++++++++ .../types/type_typehash_shadow.sol | 27 +++++++++++++++++++ .../types/type_typehash_super.sol | 15 +++++++++++ .../types/struct/typehash_immutable.sol | 11 ++++++++ 5 files changed, 97 insertions(+) create mode 100644 test/libsolidity/smtCheckerTests/types/type_typehash_different_scopes.sol create mode 100644 test/libsolidity/smtCheckerTests/types/type_typehash_inheritence.sol create mode 100644 test/libsolidity/smtCheckerTests/types/type_typehash_shadow.sol create mode 100644 test/libsolidity/smtCheckerTests/types/type_typehash_super.sol create mode 100644 test/libsolidity/syntaxTests/types/struct/typehash_immutable.sol diff --git a/test/libsolidity/smtCheckerTests/types/type_typehash_different_scopes.sol b/test/libsolidity/smtCheckerTests/types/type_typehash_different_scopes.sol new file mode 100644 index 000000000..b9d7685c8 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/type_typehash_different_scopes.sol @@ -0,0 +1,25 @@ +library A { + struct S1 { + uint256 x; + } + + bytes32 internal constant a = type(S1).typehash; +} + +library B { + struct S1 { + uint256 x; + } + + bytes32 internal constant b = type(S1).typehash; +} + +contract C { + function f() public pure { + assert(A.a == B.b); + } +} +// ==== +// SMTEngine: all +// ---- +// Info 1391: CHC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them. diff --git a/test/libsolidity/smtCheckerTests/types/type_typehash_inheritence.sol b/test/libsolidity/smtCheckerTests/types/type_typehash_inheritence.sol new file mode 100644 index 000000000..cb95d25b9 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/type_typehash_inheritence.sol @@ -0,0 +1,19 @@ +contract A { + struct S { + string x; + } +} + +contract B { + struct S { + bool y; + } +} + +contract C is A, B { + function f() public pure { + assert(type(A.S).typehash != type(B.S).typehash); + } +} +// ---- +// DeclarationError 9097: (72-104): Identifier already declared. diff --git a/test/libsolidity/smtCheckerTests/types/type_typehash_shadow.sol b/test/libsolidity/smtCheckerTests/types/type_typehash_shadow.sol new file mode 100644 index 000000000..13addbec1 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/type_typehash_shadow.sol @@ -0,0 +1,27 @@ +struct S { + uint256 x; +} + +bytes32 constant TYPE_HASH_FILE_LEVEL = type(S).typehash; + +contract A { + function f() public pure { + // TYPE_HASH_FILE_LEVEL == keccak256("S(uint256 x)") + assert(TYPE_HASH_FILE_LEVEL == 0x2a7af8c10b1d48ad8e0a6aad976d8385e84377b5bd03b59e2c445dc430ac2ca2); + } +} + +contract C { + struct S { + uint256 y; + } + + function f() public pure { + // type(S).typehash == keccak256("S(uint256 y)") and not the shadowed file-level struct S + assert(type(S).typehash == 0xea24952476a382c98f2d2e42112ff8a673d8ed19d22ffc89ee9fe2f415bf6c35); + assert(type(S).typehash != TYPE_HASH_FILE_LEVEL); + } +} +// ---- +// Warning 2519: (327-362): This declaration shadows an existing declaration. +// Info 1391: CHC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them. diff --git a/test/libsolidity/smtCheckerTests/types/type_typehash_super.sol b/test/libsolidity/smtCheckerTests/types/type_typehash_super.sol new file mode 100644 index 000000000..6c7e6d29b --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/type_typehash_super.sol @@ -0,0 +1,15 @@ +contract A { + struct S { + string x; + bool[10][] y; + } +} + +contract C is A { + function f() public pure { + // keccak256("S(string x,bool[10][] y)") + assert(type(S).typehash == 0xb4abec9b1d4b9d4724891b27b275d7d5e1692fe69fe6ff78379f613500046c11); + } +} +// ---- +// Info 1391: CHC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_immutable.sol b/test/libsolidity/syntaxTests/types/struct/typehash_immutable.sol new file mode 100644 index 000000000..a2adbf737 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_immutable.sol @@ -0,0 +1,11 @@ +contract C { + struct S { + uint256[][10][] x; + } + + bytes32 immutable h; + + constructor() { + h = type(S).typehash; + } +} \ No newline at end of file From f299f0cb33ba8a8dffe9bc672240430418ed505f Mon Sep 17 00:00:00 2001 From: Saw-mon & Natalie <3140080+Saw-mon-and-Natalie@users.noreply.github.com> Date: Mon, 22 May 2023 01:52:44 +0100 Subject: [PATCH 30/34] moved and created new semantic tests. --- .../struct/type_typehash_EIP712_example.sol | 15 +++++++++++ .../type_typehash_different_scopes.sol | 8 +++--- .../types/struct/type_typehash_shadow.sol | 23 ++++++++++++++++ .../types/struct/type_typehash_super.sol | 16 +++++++++++ .../types/type_typehash_inheritence.sol | 19 ------------- .../types/type_typehash_shadow.sol | 27 ------------------- .../types/type_typehash_super.sol | 15 ----------- 7 files changed, 58 insertions(+), 65 deletions(-) create mode 100644 test/libsolidity/semanticTests/types/struct/type_typehash_EIP712_example.sol rename test/libsolidity/{smtCheckerTests/types => semanticTests/types/struct}/type_typehash_different_scopes.sol (55%) create mode 100644 test/libsolidity/semanticTests/types/struct/type_typehash_shadow.sol create mode 100644 test/libsolidity/semanticTests/types/struct/type_typehash_super.sol delete mode 100644 test/libsolidity/smtCheckerTests/types/type_typehash_inheritence.sol delete mode 100644 test/libsolidity/smtCheckerTests/types/type_typehash_shadow.sol delete mode 100644 test/libsolidity/smtCheckerTests/types/type_typehash_super.sol diff --git a/test/libsolidity/semanticTests/types/struct/type_typehash_EIP712_example.sol b/test/libsolidity/semanticTests/types/struct/type_typehash_EIP712_example.sol new file mode 100644 index 000000000..20bcea7ef --- /dev/null +++ b/test/libsolidity/semanticTests/types/struct/type_typehash_EIP712_example.sol @@ -0,0 +1,15 @@ +contract C { + struct Mail { + address from; + address to; + string contents; + } + + function f() public pure returns(bool) { + return type(Mail).typehash == keccak256("Mail(address from,address to,string contents)"); + } +} +// ==== +// compileToEwasm: also +// ---- +// f() -> true diff --git a/test/libsolidity/smtCheckerTests/types/type_typehash_different_scopes.sol b/test/libsolidity/semanticTests/types/struct/type_typehash_different_scopes.sol similarity index 55% rename from test/libsolidity/smtCheckerTests/types/type_typehash_different_scopes.sol rename to test/libsolidity/semanticTests/types/struct/type_typehash_different_scopes.sol index b9d7685c8..5eef3b602 100644 --- a/test/libsolidity/smtCheckerTests/types/type_typehash_different_scopes.sol +++ b/test/libsolidity/semanticTests/types/struct/type_typehash_different_scopes.sol @@ -15,11 +15,11 @@ library B { } contract C { - function f() public pure { - assert(A.a == B.b); + function f() public pure returns(bool) { + return A.a == B.b; } } // ==== -// SMTEngine: all +// compileToEwasm: also // ---- -// Info 1391: CHC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them. +// f() -> true diff --git a/test/libsolidity/semanticTests/types/struct/type_typehash_shadow.sol b/test/libsolidity/semanticTests/types/struct/type_typehash_shadow.sol new file mode 100644 index 000000000..5ee8021ea --- /dev/null +++ b/test/libsolidity/semanticTests/types/struct/type_typehash_shadow.sol @@ -0,0 +1,23 @@ +struct S { + uint256 x; +} + +bytes32 constant TYPE_HASH_FILE_LEVEL = type(S).typehash; + +contract C { + struct S { + uint256 y; + } + + function f() public pure returns(bool, bool, bool) { + return ( + type(S).typehash == keccak256("S(uint256 y)"), + type(S).typehash == TYPE_HASH_FILE_LEVEL, + TYPE_HASH_FILE_LEVEL == keccak256("S(uint256 x)") + ); + } +} +// ==== +// compileToEwasm: also +// ---- +// f() -> true, false, true diff --git a/test/libsolidity/semanticTests/types/struct/type_typehash_super.sol b/test/libsolidity/semanticTests/types/struct/type_typehash_super.sol new file mode 100644 index 000000000..f3acb8688 --- /dev/null +++ b/test/libsolidity/semanticTests/types/struct/type_typehash_super.sol @@ -0,0 +1,16 @@ +contract A { + struct S { + string x; + bool[10][] y; + } +} + +contract C is A { + function f() public pure returns(bool) { + return type(S).typehash == keccak256("S(string x,bool[10][] y)"); + } +} +// ==== +// compileToEwasm: also +// ---- +// f() -> true diff --git a/test/libsolidity/smtCheckerTests/types/type_typehash_inheritence.sol b/test/libsolidity/smtCheckerTests/types/type_typehash_inheritence.sol deleted file mode 100644 index cb95d25b9..000000000 --- a/test/libsolidity/smtCheckerTests/types/type_typehash_inheritence.sol +++ /dev/null @@ -1,19 +0,0 @@ -contract A { - struct S { - string x; - } -} - -contract B { - struct S { - bool y; - } -} - -contract C is A, B { - function f() public pure { - assert(type(A.S).typehash != type(B.S).typehash); - } -} -// ---- -// DeclarationError 9097: (72-104): Identifier already declared. diff --git a/test/libsolidity/smtCheckerTests/types/type_typehash_shadow.sol b/test/libsolidity/smtCheckerTests/types/type_typehash_shadow.sol deleted file mode 100644 index 13addbec1..000000000 --- a/test/libsolidity/smtCheckerTests/types/type_typehash_shadow.sol +++ /dev/null @@ -1,27 +0,0 @@ -struct S { - uint256 x; -} - -bytes32 constant TYPE_HASH_FILE_LEVEL = type(S).typehash; - -contract A { - function f() public pure { - // TYPE_HASH_FILE_LEVEL == keccak256("S(uint256 x)") - assert(TYPE_HASH_FILE_LEVEL == 0x2a7af8c10b1d48ad8e0a6aad976d8385e84377b5bd03b59e2c445dc430ac2ca2); - } -} - -contract C { - struct S { - uint256 y; - } - - function f() public pure { - // type(S).typehash == keccak256("S(uint256 y)") and not the shadowed file-level struct S - assert(type(S).typehash == 0xea24952476a382c98f2d2e42112ff8a673d8ed19d22ffc89ee9fe2f415bf6c35); - assert(type(S).typehash != TYPE_HASH_FILE_LEVEL); - } -} -// ---- -// Warning 2519: (327-362): This declaration shadows an existing declaration. -// Info 1391: CHC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them. diff --git a/test/libsolidity/smtCheckerTests/types/type_typehash_super.sol b/test/libsolidity/smtCheckerTests/types/type_typehash_super.sol deleted file mode 100644 index 6c7e6d29b..000000000 --- a/test/libsolidity/smtCheckerTests/types/type_typehash_super.sol +++ /dev/null @@ -1,15 +0,0 @@ -contract A { - struct S { - string x; - bool[10][] y; - } -} - -contract C is A { - function f() public pure { - // keccak256("S(string x,bool[10][] y)") - assert(type(S).typehash == 0xb4abec9b1d4b9d4724891b27b275d7d5e1692fe69fe6ff78379f613500046c11); - } -} -// ---- -// Info 1391: CHC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them. From b65751c030c1355e7c57a6cc45938ab014013189 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Thu, 25 May 2023 17:47:23 +0200 Subject: [PATCH 31/34] Fix spaces to tabs --- .../smtCheckerTests/types/type_typehash.sol | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/test/libsolidity/smtCheckerTests/types/type_typehash.sol b/test/libsolidity/smtCheckerTests/types/type_typehash.sol index 46673c3e6..96ba5515a 100644 --- a/test/libsolidity/smtCheckerTests/types/type_typehash.sol +++ b/test/libsolidity/smtCheckerTests/types/type_typehash.sol @@ -2,39 +2,39 @@ interface I1 { } contract C { - struct S1 { - uint256 x; - } + struct S1 { + uint256 x; + } - struct S2 { - uint256 x; - address y; - } + struct S2 { + uint256 x; + address y; + } - struct S3 { - uint256 x; - I1 y; - S2 third; - } + struct S3 { + uint256 x; + I1 y; + S2 third; + } - struct S4 { - S3 one; - S2 two; - } + struct S4 { + S3 one; + S2 two; + } - struct S5 { - S2 two; - S1 one; - S3 three; - S4[5] four; - } + struct S5 { + S2 two; + S1 one; + S3 three; + S4[5] four; + } function f() public pure { assert(type(S1).typehash == 0x78a822935e38445215ba7404686b919cbbef5725cbf9231d92802f542d7456e0); // keccak256("S1(uint256 x)") assert(type(S2).typehash == 0x6c397ebd50462a81423e44830702ee1214cb9ab734bf173eb55f04238c9d398f); // keccak256("S2(uint256 x,address y)") assert(type(S3).typehash == 0xfa5685568fb2f15c09479ecbcfe9d0494743d804587d1966db67d5e62ea4344a); // keccak256("S3(uint256 x,address y,S2 third)S2(uint256 x,address y)") - assert(type(S4).typehash == 0x17ed8da37c0446eeffef8cd38d116505b399b5644fdc3a59f8a68a68dd5d4178); // keccak256("S4(S3 one,S2 two)S2(uint256 x,address y)S3(uint256 x,address y,S2 third)") - assert(type(S5).typehash == 0x5e52252fbbc0eda2d75f57c57d47fbec3bc6b215a9a3790c7f7ca44a36eb5185); // keccak256("S5(S2 two,S1 one,S3 three,S4[5] four)S1(uint256 x)S2(uint256 x,address y)S3(uint256 x,address y,S2 third)S4(S3 one,S2 two)") + assert(type(S4).typehash == 0x17ed8da37c0446eeffef8cd38d116505b399b5644fdc3a59f8a68a68dd5d4178); // keccak256("S4(S3 one,S2 two)S2(uint256 x,address y)S3(uint256 x,address y,S2 third)") + assert(type(S5).typehash == 0x5e52252fbbc0eda2d75f57c57d47fbec3bc6b215a9a3790c7f7ca44a36eb5185); // keccak256("S5(S2 two,S1 one,S3 three,S4[5] four)S1(uint256 x)S2(uint256 x,address y)S3(uint256 x,address y,S2 third)S4(S3 one,S2 two)") } } // ==== From bcadf3c5de23eb24b02f7f85e9c003c2493803c4 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Wed, 5 Jul 2023 11:44:59 +0200 Subject: [PATCH 32/34] Add nested structs semantic tests for type(S).typehash --- .../types/struct/type_typehash_nested.sol | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 test/libsolidity/semanticTests/types/struct/type_typehash_nested.sol diff --git a/test/libsolidity/semanticTests/types/struct/type_typehash_nested.sol b/test/libsolidity/semanticTests/types/struct/type_typehash_nested.sol new file mode 100644 index 000000000..fc77b512a --- /dev/null +++ b/test/libsolidity/semanticTests/types/struct/type_typehash_nested.sol @@ -0,0 +1,28 @@ +contract C { + struct S2 { + uint256 x; + S1 y; + } + + struct S1 { + uint256 z; + S3[] w; + } + + struct S3 { + address a; + uint24 b; + } + + function f() public pure returns(bool, bool, bool) { + return ( + type(S3).typehash == keccak256("S3(address a,uint24 b)"), + type(S1).typehash == keccak256("S1(uint256 z,S3[] w)S3(address a,uint24 b)"), + type(S2).typehash == keccak256("S2(uint256 x,S1 y)S1(uint256 z,S3[] w)S3(address a,uint24 b)") + ); + } +} +// ==== +// compileToEwasm: also +// ---- +// f() -> true, true, true From a522aea3c17f27e5a3274336318b127829632c87 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Wed, 5 Jul 2023 13:15:54 +0200 Subject: [PATCH 33/34] Remove "compileToEwasm" option --- .../semanticTests/types/struct/type_typehash_EIP712_example.sol | 2 -- .../types/struct/type_typehash_different_scopes.sol | 2 -- .../semanticTests/types/struct/type_typehash_nested.sol | 2 -- .../semanticTests/types/struct/type_typehash_shadow.sol | 2 -- .../semanticTests/types/struct/type_typehash_super.sol | 2 -- 5 files changed, 10 deletions(-) diff --git a/test/libsolidity/semanticTests/types/struct/type_typehash_EIP712_example.sol b/test/libsolidity/semanticTests/types/struct/type_typehash_EIP712_example.sol index 20bcea7ef..886a1c286 100644 --- a/test/libsolidity/semanticTests/types/struct/type_typehash_EIP712_example.sol +++ b/test/libsolidity/semanticTests/types/struct/type_typehash_EIP712_example.sol @@ -9,7 +9,5 @@ contract C { return type(Mail).typehash == keccak256("Mail(address from,address to,string contents)"); } } -// ==== -// compileToEwasm: also // ---- // f() -> true diff --git a/test/libsolidity/semanticTests/types/struct/type_typehash_different_scopes.sol b/test/libsolidity/semanticTests/types/struct/type_typehash_different_scopes.sol index 5eef3b602..0126eab24 100644 --- a/test/libsolidity/semanticTests/types/struct/type_typehash_different_scopes.sol +++ b/test/libsolidity/semanticTests/types/struct/type_typehash_different_scopes.sol @@ -19,7 +19,5 @@ contract C { return A.a == B.b; } } -// ==== -// compileToEwasm: also // ---- // f() -> true diff --git a/test/libsolidity/semanticTests/types/struct/type_typehash_nested.sol b/test/libsolidity/semanticTests/types/struct/type_typehash_nested.sol index fc77b512a..8de7b6166 100644 --- a/test/libsolidity/semanticTests/types/struct/type_typehash_nested.sol +++ b/test/libsolidity/semanticTests/types/struct/type_typehash_nested.sol @@ -22,7 +22,5 @@ contract C { ); } } -// ==== -// compileToEwasm: also // ---- // f() -> true, true, true diff --git a/test/libsolidity/semanticTests/types/struct/type_typehash_shadow.sol b/test/libsolidity/semanticTests/types/struct/type_typehash_shadow.sol index 5ee8021ea..fe549295f 100644 --- a/test/libsolidity/semanticTests/types/struct/type_typehash_shadow.sol +++ b/test/libsolidity/semanticTests/types/struct/type_typehash_shadow.sol @@ -17,7 +17,5 @@ contract C { ); } } -// ==== -// compileToEwasm: also // ---- // f() -> true, false, true diff --git a/test/libsolidity/semanticTests/types/struct/type_typehash_super.sol b/test/libsolidity/semanticTests/types/struct/type_typehash_super.sol index f3acb8688..b3b504607 100644 --- a/test/libsolidity/semanticTests/types/struct/type_typehash_super.sol +++ b/test/libsolidity/semanticTests/types/struct/type_typehash_super.sol @@ -10,7 +10,5 @@ contract C is A { return type(S).typehash == keccak256("S(string x,bool[10][] y)"); } } -// ==== -// compileToEwasm: also // ---- // f() -> true From de5af35fcadd19f873a8cf77fc53e0fa0996622c Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Mon, 2 Oct 2023 12:46:10 +0200 Subject: [PATCH 34/34] Some fixes for PR comments --- libsolidity/ast/AST.cpp | 7 +++---- libsolidity/ast/Types.h | 6 +++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 3c9c64196..5ef986bdc 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -403,12 +403,11 @@ void StructDefinition::insertEip712EncodedSubtypes(std::set& subtyp declaration = m_members[i]->type()->typeDefinition(); break; case Type::Category::Array: + if (auto const* arrayType = dynamic_cast(m_members[i]->type())) { - auto const* arrayType = dynamic_cast(m_members[i]->type()); - solAssert(!!arrayType); - if (auto finalyBaseType = dynamic_cast(arrayType->finalBaseType(false))) + if (auto finalBaseType = dynamic_cast(arrayType->finalBaseType(false))) { - declaration = finalyBaseType->typeDefinition(); + declaration = finalBaseType->typeDefinition(); } } break; diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 37cb843e8..667ff3be4 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -357,7 +357,11 @@ public: /// @returns the canonical name of this type for use in library function signatures. virtual std::string canonicalName() const { return toString(true); } virtual std::string humanReadableName() const { return toString(); } - virtual std::string eip712TypeName() const { return encodingType()->toString(true); } + virtual std::string eip712TypeName() const + { + solAssert(isEIP712AllowedStructMemberType(), "Invalid type ..."); + return encodingType()->toString(true); + } virtual bool isEIP712AllowedStructMemberType() const { return false; } /// @returns the signature of this type in external functions, i.e. `uint256` for integers /// or `(uint256,bytes8)[2]` for an array of structs. If @a _structsByName,