From 04aa0cc9baa9a9d657f7d9da984c35e7bdc54149 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 3 Feb 2015 14:02:58 +0100 Subject: [PATCH 01/10] Solidity SHA3 can now take multiple arguments --- libsolidity/AST.cpp | 19 ++++++++++++++++--- libsolidity/ExpressionCompiler.cpp | 23 ++++++++++++++++++----- libsolidity/ExpressionCompiler.h | 8 +++++--- test/SolidityEndToEndTest.cpp | 19 +++++++++++++++++++ 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index d1c7d5371..c4fd7e2dd 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -487,14 +487,27 @@ void FunctionCall::checkTypeRequirements() // and then ask if that is implicitly convertible to the struct represented by the // function parameters TypePointers const& parameterTypes = functionType->getParameterTypes(); - if (parameterTypes.size() != m_arguments.size()) + if (functionType->getLocation() !=FunctionType::Location::SHA3 && parameterTypes.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); - if (m_names.empty()) + if (m_names.empty()) // LTODO: Totally ignoring sha3 case for named arguments for now just for the rebase to work { for (size_t i = 0; i < m_arguments.size(); ++i) - if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) + { + if (functionType->getLocation() == FunctionType::Location::SHA3) + { +#if 0 // are we sure we want that? Literal constant nums can't live outside storage and so sha3(42) will fail + if (!m_arguments[i]->getType()->canLiveOutsideStorage()) + BOOST_THROW_EXCEPTION(createTypeError("SHA3 called with argument that can't live outside storage")); +#endif + if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[0])) + BOOST_THROW_EXCEPTION(createTypeError(std::string("SHA3 argument ") + + boost::lexical_cast(i) + + std::string("can't be converted to hash"))); + + } else if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call.")); + } } else { diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 875e00bc2..8672611a4 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -206,7 +206,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) TypePointers const& parameterTypes = function.getParameterTypes(); vector> const& callArguments = _functionCall.getArguments(); vector> const& callArgumentNames = _functionCall.getNames(); - solAssert(callArguments.size() == parameterTypes.size(), ""); + if (function.getLocation() != Location::SHA3) + solAssert(callArguments.size() == parameterTypes.size(), ""); vector> arguments; if (callArgumentNames.empty()) @@ -325,9 +326,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << eth::Instruction::SUICIDE; break; case Location::SHA3: - appendExpressionCopyToMemory(*function.getParameterTypes().front(), *arguments.front()); - m_context << u256(32) << u256(0) << eth::Instruction::SHA3; + { + unsigned length = appendSameTypeArgumentsCopyToMemory(function.getParameterTypes().front(), arguments, 0); + m_context << u256(length) << u256(0) << eth::Instruction::SHA3; break; + } case Location::LOG0: case Location::LOG1: case Location::LOG2: @@ -843,8 +846,18 @@ unsigned ExpressionCompiler::appendArgumentCopyToMemory(TypePointers const& _typ return length; } -unsigned ExpressionCompiler::appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, - Location const& _location, unsigned _memoryOffset) +unsigned ExpressionCompiler::appendSameTypeArgumentsCopyToMemory(TypePointer const& _type, + vector> const& _arguments, + unsigned _memoryOffset) +{ + unsigned length = 0; + for (unsigned i = 0; i < _arguments.size(); ++i) + length += appendExpressionCopyToMemory(*_type, *_arguments[i], _memoryOffset + length); + return length; +} + +unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, + Expression const& _expression, unsigned _memoryOffset) { appendTypeConversion(_type, _expectedType, true); unsigned const c_numBytes = CompilerUtils::getPaddedSize(_expectedType.getCalldataEncodedSize()); diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 7de577e6c..b977657b1 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -97,10 +97,12 @@ private: unsigned appendArgumentCopyToMemory(TypePointers const& _types, std::vector> const& _arguments, unsigned _memoryOffset = 0); - /// Appends code that copies a type to memory. + /// Appends code that copies the given arguments that should all have the + /// same @a _type to memory (with optional offset). /// @returns the number of bytes copied to memory - unsigned appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, - Location const& _location, unsigned _memoryOffset = 0); + unsigned appendSameTypeArgumentsCopyToMemory(TypePointer const& _type, + std::vector> const& _arguments, + unsigned _memoryOffset = 0); /// Appends code that evaluates a single expression and copies it to memory (with optional offset). /// @returns the number of bytes copied to memory unsigned appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression, diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index f248a5a07..824519fd2 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2095,6 +2095,25 @@ BOOST_AUTO_TEST_CASE(event_lots_of_data) BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(address,hash256,uint256,bool)"))); } +BOOST_AUTO_TEST_CASE(sha3_multiple_arguments) +{ + char const* sourceCode = R"( + contract c { + // function foo(uint a) returns (hash d) + function foo(uint a, uint b, uint c) returns (hash d) + { + d = sha3(a, b, c); + } + })"; + compileAndRun(sourceCode); + + BOOST_CHECK(callContractFunction("foo(uint256,uint256,uint256)", 10 , 12, 13) == encodeArgs( + dev::sha3( + toBigEndian(u256(10)) + + toBigEndian(u256(12)) + + toBigEndian(u256(13))))); +} + BOOST_AUTO_TEST_SUITE_END() } From 5b1adccf6de0a946d5f45a75bd1160a14449ce4e Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 3 Feb 2015 14:21:08 +0100 Subject: [PATCH 02/10] Renaming a function for clarity --- libsolidity/AST.cpp | 2 +- libsolidity/ExpressionCompiler.cpp | 10 +++++----- libsolidity/ExpressionCompiler.h | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index c4fd7e2dd..39ba10f32 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -502,7 +502,7 @@ void FunctionCall::checkTypeRequirements() #endif if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[0])) BOOST_THROW_EXCEPTION(createTypeError(std::string("SHA3 argument ") + - boost::lexical_cast(i) + + boost::lexical_cast(i + 1) + std::string("can't be converted to hash"))); } else if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 8672611a4..0acc9c9ed 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -275,7 +275,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << u256(0) << eth::Instruction::CODECOPY; unsigned length = bytecode.size(); - length += appendArgumentCopyToMemory(function.getParameterTypes(), arguments, length); + length += appendArgumentsCopyToMemory(function.getParameterTypes(), arguments, length); // size, offset, endowment m_context << u256(length) << u256(0); if (function.valueSet()) @@ -800,7 +800,7 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio // reserve space for the function identifier unsigned dataOffset = bare ? 0 : CompilerUtils::dataStartOffset; - dataOffset += appendArgumentCopyToMemory(_functionType.getParameterTypes(), _arguments, dataOffset); + dataOffset += appendArgumentsCopyToMemory(_functionType.getParameterTypes(), _arguments, dataOffset); //@todo only return the first return value for now Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr : @@ -836,9 +836,9 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio } } -unsigned ExpressionCompiler::appendArgumentCopyToMemory(TypePointers const& _types, - vector> const& _arguments, - unsigned _memoryOffset) +unsigned ExpressionCompiler::appendArgumentsCopyToMemory(TypePointers const& _types, + vector> const& _arguments, + unsigned _memoryOffset) { unsigned length = 0; for (unsigned i = 0; i < _arguments.size(); ++i) diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index b977657b1..1f42d8225 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -94,9 +94,9 @@ private: bool bare = false); /// Appends code that copies the given arguments to memory (with optional offset). /// @returns the number of bytes copied to memory - unsigned appendArgumentCopyToMemory(TypePointers const& _types, - std::vector> const& _arguments, - unsigned _memoryOffset = 0); + unsigned appendArgumentsCopyToMemory(TypePointers const& _types, + std::vector> const& _arguments, + unsigned _memoryOffset = 0); /// Appends code that copies the given arguments that should all have the /// same @a _type to memory (with optional offset). /// @returns the number of bytes copied to memory From d3f9c89ee0bfc63e50253e133771dd1bb522846b Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 5 Feb 2015 15:05:58 +0100 Subject: [PATCH 03/10] Fixes after rebase --- libsolidity/AST.cpp | 2 +- libsolidity/ExpressionCompiler.cpp | 4 ++-- libsolidity/ExpressionCompiler.h | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 39ba10f32..f2fbc5284 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -487,7 +487,7 @@ void FunctionCall::checkTypeRequirements() // and then ask if that is implicitly convertible to the struct represented by the // function parameters TypePointers const& parameterTypes = functionType->getParameterTypes(); - if (functionType->getLocation() !=FunctionType::Location::SHA3 && parameterTypes.size() != m_arguments.size()) + if (functionType->getLocation() != FunctionType::Location::SHA3 && parameterTypes.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); if (m_names.empty()) // LTODO: Totally ignoring sha3 case for named arguments for now just for the rebase to work diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 0acc9c9ed..e2c632a3c 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -856,8 +856,8 @@ unsigned ExpressionCompiler::appendSameTypeArgumentsCopyToMemory(TypePointer con return length; } -unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, - Expression const& _expression, unsigned _memoryOffset) +unsigned ExpressionCompiler::appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, + Location const& _location, unsigned _memoryOffset) { appendTypeConversion(_type, _expectedType, true); unsigned const c_numBytes = CompilerUtils::getPaddedSize(_expectedType.getCalldataEncodedSize()); diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 1f42d8225..90a60afc7 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -97,6 +97,10 @@ private: unsigned appendArgumentsCopyToMemory(TypePointers const& _types, std::vector> const& _arguments, unsigned _memoryOffset = 0); + /// Appends code that copies a type to memory. + /// @returns the number of bytes copied to memory + unsigned appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, + Location const& _location, unsigned _memoryOffset = 0); /// Appends code that copies the given arguments that should all have the /// same @a _type to memory (with optional offset). /// @returns the number of bytes copied to memory From bbede4c31c845bba44d6ac541e2d0b386ed9d698 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 6 Feb 2015 10:42:24 +0100 Subject: [PATCH 04/10] appendArgumentsCopyToMemory() has more complicated logic now - Plus other fixes. --- libsolidity/AST.cpp | 8 ++--- libsolidity/ExpressionCompiler.cpp | 48 +++++++++++++++++------------- libsolidity/ExpressionCompiler.h | 11 +++---- test/SolidityEndToEndTest.cpp | 2 +- 4 files changed, 36 insertions(+), 33 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index f2fbc5284..c0a120b82 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -490,7 +490,7 @@ void FunctionCall::checkTypeRequirements() if (functionType->getLocation() != FunctionType::Location::SHA3 && parameterTypes.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); - if (m_names.empty()) // LTODO: Totally ignoring sha3 case for named arguments for now just for the rebase to work + if (m_names.empty()) { for (size_t i = 0; i < m_arguments.size(); ++i) { @@ -501,14 +501,14 @@ void FunctionCall::checkTypeRequirements() BOOST_THROW_EXCEPTION(createTypeError("SHA3 called with argument that can't live outside storage")); #endif if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[0])) - BOOST_THROW_EXCEPTION(createTypeError(std::string("SHA3 argument ") + - boost::lexical_cast(i + 1) + - std::string("can't be converted to hash"))); + BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError("SHA3 argument can't be converted to hash")); } else if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call.")); } } + else if (functionType->getLocation() == FunctionType::Location::SHA3) + BOOST_THROW_EXCEPTION(createTypeError("Named arguments can't be used for SHA3.")); else { auto const& parameterNames = functionType->getParameterNames(); diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index e2c632a3c..fbf5cbcfd 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -275,7 +275,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << u256(0) << eth::Instruction::CODECOPY; unsigned length = bytecode.size(); - length += appendArgumentsCopyToMemory(function.getParameterTypes(), arguments, length); + length += appendArgumentsCopyToMemory(arguments, function.getParameterTypes(), length); // size, offset, endowment m_context << u256(length) << u256(0); if (function.valueSet()) @@ -327,7 +327,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) break; case Location::SHA3: { - unsigned length = appendSameTypeArgumentsCopyToMemory(function.getParameterTypes().front(), arguments, 0); + unsigned length = appendArgumentsCopyToMemory(arguments); m_context << u256(length) << u256(0) << eth::Instruction::SHA3; break; } @@ -800,7 +800,7 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio // reserve space for the function identifier unsigned dataOffset = bare ? 0 : CompilerUtils::dataStartOffset; - dataOffset += appendArgumentsCopyToMemory(_functionType.getParameterTypes(), _arguments, dataOffset); + dataOffset += appendArgumentsCopyToMemory(_arguments, _functionType.getParameterTypes(), dataOffset); //@todo only return the first return value for now Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr : @@ -836,40 +836,46 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio } } -unsigned ExpressionCompiler::appendArgumentsCopyToMemory(TypePointers const& _types, - vector> const& _arguments, +unsigned ExpressionCompiler::appendArgumentsCopyToMemory(vector> const& _arguments, + TypePointers const& _types, unsigned _memoryOffset) { unsigned length = 0; - for (unsigned i = 0; i < _arguments.size(); ++i) - length += appendExpressionCopyToMemory(*_types[i], *_arguments[i], _memoryOffset + length); - return length; -} + if (!_types.empty()) + { + for (unsigned i = 0; i < _arguments.size(); ++i) + length += appendExpressionCopyToMemory(*_types[i], *_arguments[i], _memoryOffset + length); + return length; + } -unsigned ExpressionCompiler::appendSameTypeArgumentsCopyToMemory(TypePointer const& _type, - vector> const& _arguments, - unsigned _memoryOffset) -{ - unsigned length = 0; + // without type conversion for (unsigned i = 0; i < _arguments.size(); ++i) - length += appendExpressionCopyToMemory(*_type, *_arguments[i], _memoryOffset + length); + { + _arguments[i]->accept(*this); + length += moveTypeToMemory(*_arguments[i]->getType(), _arguments[i]->getLocation(), _memoryOffset + length); + } return length; } -unsigned ExpressionCompiler::appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, - Location const& _location, unsigned _memoryOffset) +unsigned ExpressionCompiler::moveTypeToMemory(Type const& _type, Location const& _location, unsigned _memoryOffset) { - appendTypeConversion(_type, _expectedType, true); - unsigned const c_numBytes = CompilerUtils::getPaddedSize(_expectedType.getCalldataEncodedSize()); + unsigned const c_numBytes = CompilerUtils::getPaddedSize(_type.getCalldataEncodedSize()); if (c_numBytes == 0 || c_numBytes > 32) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location) - << errinfo_comment("Type " + _expectedType.toString() + " not yet supported.")); - bool const c_leftAligned = _expectedType.getCategory() == Type::Category::STRING; + << errinfo_comment("Type " + _type.toString() + " not yet supported.")); + bool const c_leftAligned = _type.getCategory() == Type::Category::STRING; bool const c_padToWords = true; return CompilerUtils(m_context).storeInMemory(_memoryOffset, c_numBytes, c_leftAligned, c_padToWords); } +unsigned ExpressionCompiler::appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, + Location const& _location, unsigned _memoryOffset) +{ + appendTypeConversion(_type, _expectedType, true); + return moveTypeToMemory(_expectedType, _location, _memoryOffset); +} + unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression, unsigned _memoryOffset) diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 90a60afc7..70cc2426b 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -94,19 +94,16 @@ private: bool bare = false); /// Appends code that copies the given arguments to memory (with optional offset). /// @returns the number of bytes copied to memory - unsigned appendArgumentsCopyToMemory(TypePointers const& _types, - std::vector> const& _arguments, + unsigned appendArgumentsCopyToMemory(std::vector> const& _arguments, + TypePointers const& _types = {}, unsigned _memoryOffset = 0); /// Appends code that copies a type to memory. /// @returns the number of bytes copied to memory unsigned appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, Location const& _location, unsigned _memoryOffset = 0); - /// Appends code that copies the given arguments that should all have the - /// same @a _type to memory (with optional offset). + /// Appends code that moves a type to memory /// @returns the number of bytes copied to memory - unsigned appendSameTypeArgumentsCopyToMemory(TypePointer const& _type, - std::vector> const& _arguments, - unsigned _memoryOffset = 0); + unsigned moveTypeToMemory(Type const& _type, Location const& _location, unsigned _memoryOffset); /// Appends code that evaluates a single expression and copies it to memory (with optional offset). /// @returns the number of bytes copied to memory unsigned appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression, diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 824519fd2..083f55025 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2107,7 +2107,7 @@ BOOST_AUTO_TEST_CASE(sha3_multiple_arguments) })"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("foo(uint256,uint256,uint256)", 10 , 12, 13) == encodeArgs( + BOOST_CHECK(callContractFunction("foo(uint256,uint256,uint256)", 10, 12, 13) == encodeArgs( dev::sha3( toBigEndian(u256(10)) + toBigEndian(u256(12)) + From deea982c00ca81aae97ff687afe87c51d2b434ba Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 6 Feb 2015 13:42:51 +0100 Subject: [PATCH 05/10] getRealType() introduced --- libsolidity/ExpressionCompiler.cpp | 2 +- libsolidity/Types.cpp | 8 ++++++++ libsolidity/Types.h | 6 +++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index fbf5cbcfd..39593a6ed 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -852,7 +852,7 @@ unsigned ExpressionCompiler::appendArgumentsCopyToMemory(vectoraccept(*this); - length += moveTypeToMemory(*_arguments[i]->getType(), _arguments[i]->getLocation(), _memoryOffset + length); + length += moveTypeToMemory(*_arguments[i]->getType()->getRealType(), _arguments[i]->getLocation(), _memoryOffset + length); } return length; } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 648cf9cb2..a9051a2ca 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -361,6 +361,14 @@ u256 IntegerConstantType::literalValue(Literal const* _literal) const return value; } +TypePointer IntegerConstantType::getRealType() const +{ + auto intType = getIntegerType(); + if (!intType) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("getRealType called with invalid integer constant" + toString())); + return intType; +} + shared_ptr IntegerConstantType::getIntegerType() const { bigint value = m_value; diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 1f4d27a25..18a53f9a5 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -130,6 +130,8 @@ public: /// i.e. it behaves differently in lvalue context and in value context. virtual bool isValueType() const { return false; } virtual unsigned getSizeOnStack() const { return 1; } + /// @returns the real type of some types, like e.g: IntegerConstant + virtual TypePointer getRealType() const { return TypePointer(); } /// Returns the list of all members of this type. Default implementation: no members. virtual MemberList const& getMembers() const { return EmptyMemberList; } @@ -140,7 +142,7 @@ public: virtual u256 literalValue(Literal const*) const { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Literal value requested " - "for type without literals.")); + "for type without literals.")); } protected: @@ -175,6 +177,7 @@ public: virtual MemberList const& getMembers() const { return isAddress() ? AddressMemberList : EmptyMemberList; } virtual std::string toString() const override; + virtual TypePointer getRealType() const { return std::make_shared(m_bits, m_modifier); } int getNumBits() const { return m_bits; } bool isHash() const { return m_modifier == Modifier::HASH || m_modifier == Modifier::ADDRESS; } @@ -214,6 +217,7 @@ public: virtual std::string toString() const override; virtual u256 literalValue(Literal const* _literal) const override; + virtual TypePointer getRealType() const override; /// @returns the smallest integer type that can hold the value or an empty pointer if not possible. std::shared_ptr getIntegerType() const; From 8d239921e98995d3c03fca3bc2dbf25120bd38a4 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 6 Feb 2015 16:27:41 +0100 Subject: [PATCH 06/10] SHA3 of string literals now should work --- libsolidity/AST.cpp | 14 ++-------- libsolidity/ExpressionCompiler.cpp | 11 ++++---- libsolidity/ExpressionCompiler.h | 2 +- libsolidity/Types.h | 1 + test/SolidityEndToEndTest.cpp | 45 +++++++++++++++++++++++++++++- 5 files changed, 54 insertions(+), 19 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index c0a120b82..26897ddae 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -493,19 +493,9 @@ void FunctionCall::checkTypeRequirements() if (m_names.empty()) { for (size_t i = 0; i < m_arguments.size(); ++i) - { - if (functionType->getLocation() == FunctionType::Location::SHA3) - { -#if 0 // are we sure we want that? Literal constant nums can't live outside storage and so sha3(42) will fail - if (!m_arguments[i]->getType()->canLiveOutsideStorage()) - BOOST_THROW_EXCEPTION(createTypeError("SHA3 called with argument that can't live outside storage")); -#endif - if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[0])) - BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError("SHA3 argument can't be converted to hash")); - - } else if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) + if (functionType->getLocation() != FunctionType::Location::SHA3 && + !m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call.")); - } } else if (functionType->getLocation() == FunctionType::Location::SHA3) BOOST_THROW_EXCEPTION(createTypeError("Named arguments can't be used for SHA3.")); diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 39593a6ed..4f091db4c 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -851,22 +851,23 @@ unsigned ExpressionCompiler::appendArgumentsCopyToMemory(vectorgetType()->getCategory() == Type::Category::STRING) ? false : true; _arguments[i]->accept(*this); - length += moveTypeToMemory(*_arguments[i]->getType()->getRealType(), _arguments[i]->getLocation(), _memoryOffset + length); + length += moveTypeToMemory(*_arguments[i]->getType()->getRealType(), _arguments[i]->getLocation(), _memoryOffset + length, wantPadding); } return length; } -unsigned ExpressionCompiler::moveTypeToMemory(Type const& _type, Location const& _location, unsigned _memoryOffset) +unsigned ExpressionCompiler::moveTypeToMemory(Type const& _type, Location const& _location, unsigned _memoryOffset, bool _padToWordBoundaries) { - unsigned const c_numBytes = CompilerUtils::getPaddedSize(_type.getCalldataEncodedSize()); + unsigned const encodedSize = _type.getCalldataEncodedSize(); + unsigned const c_numBytes = _padToWordBoundaries ? CompilerUtils::getPaddedSize(encodedSize) : encodedSize; if (c_numBytes == 0 || c_numBytes > 32) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location) << errinfo_comment("Type " + _type.toString() + " not yet supported.")); bool const c_leftAligned = _type.getCategory() == Type::Category::STRING; - bool const c_padToWords = true; - return CompilerUtils(m_context).storeInMemory(_memoryOffset, c_numBytes, c_leftAligned, c_padToWords); + return CompilerUtils(m_context).storeInMemory(_memoryOffset, c_numBytes, c_leftAligned, _padToWordBoundaries); } unsigned ExpressionCompiler::appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 70cc2426b..006858cb8 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -103,7 +103,7 @@ private: Location const& _location, unsigned _memoryOffset = 0); /// Appends code that moves a type to memory /// @returns the number of bytes copied to memory - unsigned moveTypeToMemory(Type const& _type, Location const& _location, unsigned _memoryOffset); + unsigned moveTypeToMemory(Type const& _type, Location const& _location, unsigned _memoryOffset, bool _padToWordBoundaries = true); /// Appends code that evaluates a single expression and copies it to memory (with optional offset). /// @returns the number of bytes copied to memory unsigned appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression, diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 18a53f9a5..677e5e49e 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -249,6 +249,7 @@ public: virtual std::string toString() const override { return "string" + dev::toString(m_bytes); } virtual u256 literalValue(Literal const* _literal) const override; + virtual TypePointer getRealType() const override { return std::make_shared(m_bytes); } int getNumBytes() const { return m_bytes; } diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 083f55025..bd473af56 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2099,7 +2099,6 @@ BOOST_AUTO_TEST_CASE(sha3_multiple_arguments) { char const* sourceCode = R"( contract c { - // function foo(uint a) returns (hash d) function foo(uint a, uint b, uint c) returns (hash d) { d = sha3(a, b, c); @@ -2114,6 +2113,50 @@ BOOST_AUTO_TEST_CASE(sha3_multiple_arguments) toBigEndian(u256(13))))); } +BOOST_AUTO_TEST_CASE(sha3_multiple_arguments_with_numeric_literals) +{ + char const* sourceCode = R"( + contract c { + function foo(uint a, uint16 b) returns (hash d) + { + d = sha3(a, b, 145); + } + })"; + compileAndRun(sourceCode); + + BOOST_CHECK(callContractFunction("foo(uint256,uint16)", 10, 12) == encodeArgs( + dev::sha3( + toBigEndian(u256(10)) + + toBigEndian(u256(12)) + + toBigEndian(u256(145))))); +} + +BOOST_AUTO_TEST_CASE(sha3_multiple_arguments_with_string_literals) +{ + char const* sourceCode = R"( + contract c { + function foo() returns (hash d) + { + d = sha3("foo"); + } + function bar(uint a, uint16 b) returns (hash d) + { + d = sha3(a, b, 145, "foo"); + } + })"; + compileAndRun(sourceCode); + + BOOST_CHECK(callContractFunction("foo()") == encodeArgs(dev::sha3("foo"))); +#if 0 // work in progress + BOOST_CHECK(callContractFunction("bar(uint256,uint16)", 10, 12) == encodeArgs( + dev::sha3( + toBigEndian(u256(10)) + + toBigEndian(u256(12)) + + toBigEndian(u256(145)) + + asBytes("foo"))))); +#endif +} + BOOST_AUTO_TEST_SUITE_END() } From 351cfecae987489c49c14dc7e0fdac2a0627f8d7 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 6 Feb 2015 17:25:29 +0100 Subject: [PATCH 07/10] Small fixes for proper multitype/multiarg SHA3 --- libsolidity/ExpressionCompiler.cpp | 2 +- test/SolidityEndToEndTest.cpp | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 4f091db4c..0ce19ecd1 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -851,7 +851,7 @@ unsigned ExpressionCompiler::appendArgumentsCopyToMemory(vectorgetType()->getCategory() == Type::Category::STRING) ? false : true; + const bool wantPadding = false; _arguments[i]->accept(*this); length += moveTypeToMemory(*_arguments[i]->getType()->getRealType(), _arguments[i]->getLocation(), _memoryOffset + length, wantPadding); } diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index bd473af56..0fd71ac51 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -576,7 +576,7 @@ BOOST_AUTO_TEST_CASE(simple_mapping) " }\n" "}"; compileAndRun(sourceCode); - + BOOST_CHECK(callContractFunction("get(uint8)", byte(0)) == encodeArgs(byte(0x00))); BOOST_CHECK(callContractFunction("get(uint8)", byte(0x01)) == encodeArgs(byte(0x00))); BOOST_CHECK(callContractFunction("get(uint8)", byte(0xa7)) == encodeArgs(byte(0x00))); @@ -933,7 +933,7 @@ BOOST_AUTO_TEST_CASE(multiple_elementary_accessors) compileAndRun(sourceCode); BOOST_CHECK(callContractFunction("data()") == encodeArgs(8)); BOOST_CHECK(callContractFunction("name()") == encodeArgs("Celina")); - BOOST_CHECK(callContractFunction("a_hash()") == encodeArgs(dev::sha3(toBigEndian(u256(123))))); + BOOST_CHECK(callContractFunction("a_hash()") == encodeArgs(dev::sha3(bytes({0x7b})))); BOOST_CHECK(callContractFunction("an_address()") == encodeArgs(toBigEndian(u160(0x1337)))); BOOST_CHECK(callContractFunction("super_secret_data()") == bytes()); } @@ -2127,8 +2127,8 @@ BOOST_AUTO_TEST_CASE(sha3_multiple_arguments_with_numeric_literals) BOOST_CHECK(callContractFunction("foo(uint256,uint16)", 10, 12) == encodeArgs( dev::sha3( toBigEndian(u256(10)) + - toBigEndian(u256(12)) + - toBigEndian(u256(145))))); + bytes({0x0, 0xc}) + + bytes({0x91})))); } BOOST_AUTO_TEST_CASE(sha3_multiple_arguments_with_string_literals) @@ -2147,14 +2147,13 @@ BOOST_AUTO_TEST_CASE(sha3_multiple_arguments_with_string_literals) compileAndRun(sourceCode); BOOST_CHECK(callContractFunction("foo()") == encodeArgs(dev::sha3("foo"))); -#if 0 // work in progress + BOOST_CHECK(callContractFunction("bar(uint256,uint16)", 10, 12) == encodeArgs( dev::sha3( toBigEndian(u256(10)) + - toBigEndian(u256(12)) + - toBigEndian(u256(145)) + - asBytes("foo"))))); -#endif + bytes({0x0, 0xc}) + + bytes({0x91}) + + bytes({0x66, 0x6f, 0x6f})))); } BOOST_AUTO_TEST_SUITE_END() From 490cb5608e33051ebdf5f0a8eb259e358a44a1ae Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 6 Feb 2015 20:57:04 +0100 Subject: [PATCH 08/10] Small fixes in Types and ExpressionCompiler --- libsolidity/ExpressionCompiler.cpp | 4 ++-- libsolidity/Types.cpp | 3 +-- libsolidity/Types.h | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 0ce19ecd1..cd133222c 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -860,8 +860,8 @@ unsigned ExpressionCompiler::appendArgumentsCopyToMemory(vector 32) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index a9051a2ca..6a1282027 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -364,8 +364,7 @@ u256 IntegerConstantType::literalValue(Literal const* _literal) const TypePointer IntegerConstantType::getRealType() const { auto intType = getIntegerType(); - if (!intType) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("getRealType called with invalid integer constant" + toString())); + solAssert(!!intType, std::string("getRealType called with invalid integer constant") + toString()); return intType; } diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 677e5e49e..fcd6d9560 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -131,7 +131,7 @@ public: virtual bool isValueType() const { return false; } virtual unsigned getSizeOnStack() const { return 1; } /// @returns the real type of some types, like e.g: IntegerConstant - virtual TypePointer getRealType() const { return TypePointer(); } + virtual TypePointer getRealType() const { return shared_from_this(); } /// Returns the list of all members of this type. Default implementation: no members. virtual MemberList const& getMembers() const { return EmptyMemberList; } From 23c597ae29f8bce91256ca9d00edcfef4cbe25fa Mon Sep 17 00:00:00 2001 From: guanqun Date: Sun, 25 Jan 2015 19:35:47 +0800 Subject: [PATCH 09/10] remove AST.h Utils.h's x permission --- libsolidity/AST.h | 0 libsolidity/Utils.h | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 libsolidity/AST.h mode change 100755 => 100644 libsolidity/Utils.h diff --git a/libsolidity/AST.h b/libsolidity/AST.h old mode 100755 new mode 100644 diff --git a/libsolidity/Utils.h b/libsolidity/Utils.h old mode 100755 new mode 100644 From 833164b742738fd9fcacb6c48b141eeab50a584c Mon Sep 17 00:00:00 2001 From: Lu Guanqun Date: Sun, 8 Feb 2015 19:22:45 +0800 Subject: [PATCH 10/10] simplify two statements with selectToken() --- libsolidity/Scanner.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index b283ca10e..6a8ecd9dc 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -458,10 +458,7 @@ void Scanner::scanToken() // - -- -= advance(); if (m_char == '-') - { - advance(); - token = Token::DEC; - } + token = selectToken(Token::DEC); else if (m_char == '=') token = selectToken(Token::ASSIGN_SUB); else