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() }