From 91a2a9a9c3cc46b7ef199c2691f06bfcbcda5203 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Fri, 15 Mar 2019 14:47:17 +0100 Subject: [PATCH] Implement ABI encoding of calldata arrays and structs. --- Changelog.md | 1 + libsolidity/codegen/ABIFunctions.cpp | 148 +++++++++++++++--- libsolidity/codegen/ABIFunctions.h | 3 + test/cmdlineTests/gas_test_abiv2/output | 2 +- test/libsolidity/SolidityEndToEndTest.cpp | 12 ++ .../abiEncoderV2/calldata_array.sol | 22 +++ .../abiEncoderV2/calldata_array_dynamic.sol | 33 ++++ .../calldata_array_dynamic_index_access.sol | 34 ++++ .../calldata_array_dynamic_static_dynamic.sol | 49 ++++++ .../calldata_array_function_types.sol | 30 ++++ .../calldata_array_multi_dynamic.sol | 31 ++++ .../abiEncoderV2/calldata_array_static.sol | 25 +++ .../calldata_array_static_dynamic_static.sol | 49 ++++++ .../calldata_array_static_index_access.sol | 25 +++ .../calldata_array_struct_dynamic.sol | 16 ++ .../calldata_array_two_dynamic.sol | 20 +++ .../calldata_array_two_static.sol | 20 +++ .../abiEncoderV2/calldata_struct_dynamic.sol | 18 +++ .../abiEncoderV2/calldata_struct_simple.sol | 18 +++ 19 files changed, 531 insertions(+), 25 deletions(-) create mode 100644 test/libsolidity/semanticTests/abiEncoderV2/calldata_array.sol create mode 100644 test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic.sol create mode 100644 test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_index_access.sol create mode 100644 test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_dynamic.sol create mode 100644 test/libsolidity/semanticTests/abiEncoderV2/calldata_array_function_types.sol create mode 100644 test/libsolidity/semanticTests/abiEncoderV2/calldata_array_multi_dynamic.sol create mode 100644 test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static.sol create mode 100644 test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_dynamic_static.sol create mode 100644 test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_index_access.sol create mode 100644 test/libsolidity/semanticTests/abiEncoderV2/calldata_array_struct_dynamic.sol create mode 100644 test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_dynamic.sol create mode 100644 test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_static.sol create mode 100644 test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_dynamic.sol create mode 100644 test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_simple.sol diff --git a/Changelog.md b/Changelog.md index 6b000b55b..0957d9275 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ Language Features: * Code Generation: Implement copying recursive structs from storage to memory. + * ABIEncoderV2: Implement encoding of calldata arrays and structs. Compiler Features: diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index b17267b36..41ec073f0 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -831,29 +831,34 @@ string ABIFunctions::abiEncodingFunctionSimpleArray( solAssert(_from.isDynamicallySized() == _to.isDynamicallySized(), ""); solAssert(_from.length() == _to.length(), ""); - solAssert(_from.dataStoredIn(DataLocation::Memory) || _from.dataStoredIn(DataLocation::Storage), ""); solAssert(!_from.isByteArray(), ""); - solAssert(_from.dataStoredIn(DataLocation::Memory) || _from.baseType()->storageBytes() > 16, ""); + if (_from.dataStoredIn(DataLocation::Storage)) + solAssert(_from.baseType()->storageBytes() > 16, ""); return createFunction(functionName, [&]() { bool dynamic = _to.isDynamicallyEncoded(); bool dynamicBase = _to.baseType()->isDynamicallyEncoded(); - bool inMemory = _from.dataStoredIn(DataLocation::Memory); bool const usesTail = dynamicBase && !_options.dynamicInplace; + EncodingOptions subOptions(_options); + subOptions.encodeFunctionFromStack = false; + subOptions.padded = true; + string elementValues = m_utils.suffixedVariableNameList("elementValue", 0, numVariablesForType(*_from.baseType(), subOptions)); Whiskers templ( usesTail ? R"( // -> - function (value, pos) { - let length := (value) + function (value, pos) { + pos := (pos, length) let headStart := pos let tail := add(pos, mul(length, 0x20)) - let srcPtr := (value) + let baseRef := (value) + let srcPtr := baseRef for { let i := 0 } lt(i, length) { i := add(i, 1) } { mstore(pos, sub(tail, headStart)) - tail := (, tail) + let := + tail := (, tail) srcPtr := (srcPtr) pos := add(pos, 0x20) } @@ -863,13 +868,15 @@ string ABIFunctions::abiEncodingFunctionSimpleArray( )" : R"( // -> - function (value, pos) { - let length := (value) + function (value, pos) { + pos := (pos, length) - let srcPtr := (value) + let baseRef := (value) + let srcPtr := baseRef for { let i := 0 } lt(i, length) { i := add(i, 1) } { - pos := (, pos) + let := + pos := (, pos) srcPtr := (srcPtr) } @@ -877,27 +884,43 @@ string ABIFunctions::abiEncodingFunctionSimpleArray( )" ); templ("functionName", functionName); + templ("elementValues", elementValues); + bool lengthAsArgument = _from.dataStoredIn(DataLocation::CallData) && _from.isDynamicallySized(); + if (lengthAsArgument) + { + templ("maybeLength", " length,"); + templ("declareLength", ""); + } + else + { + templ("maybeLength", ""); + templ("declareLength", "let length := " + m_utils.arrayLengthFunction(_from) + "(value)"); + } templ("readableTypeNameFrom", _from.toString(true)); templ("readableTypeNameTo", _to.toString(true)); templ("return", dynamic ? " -> end " : ""); templ("assignEnd", dynamic ? "end := pos" : ""); - templ("lengthFun", m_utils.arrayLengthFunction(_from)); templ("storeLength", arrayStoreLengthForEncodingFunction(_to, _options)); templ("dataAreaFun", m_utils.arrayDataAreaFunction(_from)); - EncodingOptions subOptions(_options); - subOptions.encodeFunctionFromStack = false; - subOptions.padded = true; templ("encodeToMemoryFun", abiEncodeAndReturnUpdatedPosFunction(*_from.baseType(), *_to.baseType(), subOptions)); - if (inMemory) - templ("arrayElementAccess", "mload(srcPtr)"); - else if (_from.baseType()->isValueType()) + switch (_from.location()) { - solAssert(_from.dataStoredIn(DataLocation::Storage), ""); - templ("arrayElementAccess", readFromStorage(*_from.baseType(), 0, false) + "(srcPtr)"); + case DataLocation::Memory: + templ("arrayElementAccess", "mload(srcPtr)"); + break; + case DataLocation::Storage: + if (_from.baseType()->isValueType()) + templ("arrayElementAccess", readFromStorage(*_from.baseType(), 0, false) + "(srcPtr)"); + else + templ("arrayElementAccess", "srcPtr"); + break; + case DataLocation::CallData: + templ("arrayElementAccess", calldataAccessFunction(*_from.baseType()) + "(baseRef, srcPtr)"); + break; + default: + solAssert(false, ""); } - else - templ("arrayElementAccess", "srcPtr"); templ("nextArrayElement", m_utils.nextArrayElementFunction(_from)); return templ.render(); }); @@ -1189,7 +1212,11 @@ string ABIFunctions::abiEncodingFunctionStruct( break; } case DataLocation::CallData: - solUnimplementedAssert(false, "Encoding struct from calldata is not yet supported."); + { + string sourceOffset = toCompactHexWithPrefix(_from.calldataOffsetOfMember(member.name)); + members.back()["retrieveValue"] = calldataAccessFunction(*memberTypeFrom) + "(value, add(value, " + sourceOffset + "))"; + break; + } default: solAssert(false, ""); } @@ -1675,7 +1702,6 @@ string ABIFunctions::abiDecodingFunctionFunctionType(FunctionType const& _type, }); } - string ABIFunctions::readFromStorage(Type const& _type, size_t _offset, bool _splitFunctionTypes) { solUnimplementedAssert(!_splitFunctionTypes, ""); @@ -1721,6 +1747,80 @@ string ABIFunctions::extractFromStorageValue(Type const& _type, size_t _offset, }); } +string ABIFunctions::calldataAccessFunction(Type const& _type) +{ + solAssert(_type.isValueType() || _type.dataStoredIn(DataLocation::CallData), ""); + string functionName = "calldata_access_" + _type.identifier(); + return createFunction(functionName, [&]() { + if (_type.isDynamicallyEncoded()) + { + unsigned int baseEncodedSize = _type.calldataEncodedSize(); + solAssert(baseEncodedSize > 1, ""); + Whiskers w(R"( + function (base_ref, ptr) -> { + let rel_offset_of_tail := calldataload(ptr) + if iszero(slt(rel_offset_of_tail, sub(sub(calldatasize(), base_ref), sub(, 1)))) { revert(0, 0) } + value := add(rel_offset_of_tail, base_ref) + + } + )"); + if (_type.isDynamicallySized()) + { + auto const* arrayType = dynamic_cast(&_type); + solAssert(!!arrayType, ""); + unsigned int calldataStride = arrayType->calldataStride(); + w("handleLength", Whiskers(R"( + length := calldataload(value) + value := add(value, 0x20) + if gt(length, 0xffffffffffffffff) { revert(0, 0) } + if sgt(base_ref, sub(calldatasize(), mul(length, ))) { revert(0, 0) } + )")("calldataStride", toCompactHexWithPrefix(calldataStride)).render()); + w("return", "value, length"); + } + else + { + w("handleLength", ""); + w("return", "value"); + } + w("neededLength", toCompactHexWithPrefix(baseEncodedSize)); + w("functionName", functionName); + return w.render(); + } + else if (_type.isValueType()) + { + string decodingFunction; + if (auto const* functionType = dynamic_cast(&_type)) + decodingFunction = abiDecodingFunctionFunctionType(*functionType, false, false); + else + decodingFunction = abiDecodingFunctionValueType(_type, false); + // Note that the second argument to the decoding function should be discarded after inlining. + return Whiskers(R"( + function (baseRef, ptr) -> value { + value := (ptr, add(ptr, 32)) + } + )") + ("functionName", functionName) + ("decodingFunction", decodingFunction) + .render(); + } + else + { + solAssert( + _type.category() == Type::Category::Array || + _type.category() == Type::Category::Struct, + "" + ); + return Whiskers(R"( + function (baseRef, ptr) -> value { + value := ptr + } + )") + ("functionName", functionName) + .render(); + } + }); +} + string ABIFunctions::arrayStoreLengthForEncodingFunction(ArrayType const& _type, EncodingOptions const& _options) { string functionName = "array_storeLengthForEncoding_" + _type.identifier() + _options.toFunctionNameSuffix(); diff --git a/libsolidity/codegen/ABIFunctions.h b/libsolidity/codegen/ABIFunctions.h index a13308db9..272ca3607 100644 --- a/libsolidity/codegen/ABIFunctions.h +++ b/libsolidity/codegen/ABIFunctions.h @@ -265,6 +265,9 @@ private: /// single variable. std::string extractFromStorageValue(Type const& _type, size_t _offset, bool _splitFunctionTypes); + /// @returns the name of a function that retrieves an element from calldata. + std::string calldataAccessFunction(Type const& _type); + /// @returns the name of a function used during encoding that stores the length /// if the array is dynamically sized (and the options do not request in-place encoding). /// It returns the new encoding position. diff --git a/test/cmdlineTests/gas_test_abiv2/output b/test/cmdlineTests/gas_test_abiv2/output index 8815bd743..609d6669f 100644 --- a/test/cmdlineTests/gas_test_abiv2/output +++ b/test/cmdlineTests/gas_test_abiv2/output @@ -2,7 +2,7 @@ ======= gas_test_abiv2/input.sol:C ======= Gas estimation: construction: - 1160 + 1115800 = 1116960 + 1160 + 1119000 = 1120160 external: a(): 530 b(uint256): infinite diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 626876e67..3c913fc01 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -8447,6 +8447,9 @@ BOOST_AUTO_TEST_CASE(calldata_array_two_dimensional) function test()" + arrayType + R"( calldata a, uint256 i, uint256 j) external returns (uint256) { return a[i][j]; } + function reenc()" + arrayType + R"( calldata a, uint256 i, uint256 j) external returns (uint256) { + return this.test(a, i, j); + } } )"; compileAndRun(sourceCode, 0, "C"); @@ -8464,7 +8467,10 @@ BOOST_AUTO_TEST_CASE(calldata_array_two_dimensional) { ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256)", 0x40, i, encoding), encodeArgs(data[i].size())); for (size_t j = 0; j < data[i].size(); j++) + { ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, j, encoding), encodeArgs(data[i][j])); + ABI_CHECK(callContractFunction("reenc(" + arrayType + ",uint256,uint256)", 0x60, i, j, encoding), encodeArgs(data[i][j])); + } // out of bounds access ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, data[i].size(), encoding), encodeArgs()); } @@ -8514,6 +8520,9 @@ BOOST_AUTO_TEST_CASE(calldata_array_dynamic_three_dimensional) function test()" + arrayType + R"( calldata a, uint256 i, uint256 j, uint256 k) external returns (uint256) { return a[i][j][k]; } + function reenc()" + arrayType + R"( calldata a, uint256 i, uint256 j, uint256 k) external returns (uint256) { + return this.test(a, i, j, k); + } } )"; compileAndRun(sourceCode, 0, "C"); @@ -8540,7 +8549,10 @@ BOOST_AUTO_TEST_CASE(calldata_array_dynamic_three_dimensional) { ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, j, encoding), encodeArgs(data[i][j].size())); for (size_t k = 0; k < data[i][j].size(); k++) + { ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, k, encoding), encodeArgs(data[i][j][k])); + ABI_CHECK(callContractFunction("reenc(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, k, encoding), encodeArgs(data[i][j][k])); + } // out of bounds access ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, data[i][j].size(), encoding), encodeArgs()); } diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array.sol new file mode 100644 index 000000000..6a1bbcffa --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array.sol @@ -0,0 +1,22 @@ +pragma experimental ABIEncoderV2; + +contract C { + function g(uint256[] calldata) external pure returns (bytes memory) { + return msg.data; + } + function f(uint256[][1] calldata s) external view returns (bool) { + bytes memory a = this.g(s[0]); + uint256[] memory m = s[0]; + bytes memory b = this.g(m); + assert(a.length == b.length); + for (uint i = 0; i < a.length; i++) + assert(a[i] == b[i]); + return true; + } +} +// ==== +// EVMVersion: >homestead +// ---- +// f(uint256[][1]): 32, 32, 0 -> true +// f(uint256[][1]): 32, 32, 1, 42 -> true +// f(uint256[][1]): 32, 32, 8, 421, 422, 423, 424, 425, 426, 427, 428 -> true diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic.sol new file mode 100644 index 000000000..b2076b370 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic.sol @@ -0,0 +1,33 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f(uint256[] calldata s) external pure returns (bytes memory) { + return abi.encode(s); + } + function g(uint256[] calldata s) external view returns (bytes memory) { + return this.f(s); + } + function h(uint8[] calldata s) external pure returns (bytes memory) { + return abi.encode(s); + } + function i(uint8[] calldata s) external view returns (bytes memory) { + return this.h(s); + } + function j(bytes calldata s) external pure returns (bytes memory) { + return abi.encode(s); + } + function k(bytes calldata s) external view returns (bytes memory) { + return this.j(s); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// f(uint256[]): 32, 3, 23, 42, 87 -> 32, 160, 32, 3, 23, 42, 87 +// g(uint256[]): 32, 3, 23, 42, 87 -> 32, 160, 32, 3, 23, 42, 87 +// h(uint8[]): 32, 3, 23, 42, 87 -> 32, 160, 32, 3, 23, 42, 87 +// i(uint8[]): 32, 3, 23, 42, 87 -> 32, 160, 32, 3, 23, 42, 87 +// h(uint8[]): 32, 3, 0xFF23, 0x1242, 0xAB87 -> FAILURE +// i(uint8[]): 32, 3, 0xAB23, 0x1242, 0xFF87 -> FAILURE +// j(bytes): 32, 3, hex"123456" -> 32, 96, 32, 3, left(0x123456) +// k(bytes): 32, 3, hex"AB33FF" -> 32, 96, 32, 3, left(0xAB33FF) diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_index_access.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_index_access.sol new file mode 100644 index 000000000..f2224c803 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_index_access.sol @@ -0,0 +1,34 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f(uint256[] calldata s) external pure returns (bytes memory) { + return abi.encode(s); + } + function g(uint256[][2] calldata s, uint256 which) external view returns (bytes memory) { + return this.f(s[which]); + } + function h(uint8[] calldata s) external pure returns (bytes memory) { + return abi.encode(s); + } + function i(uint8[][2] calldata s, uint256 which) external view returns (bytes memory) { + return this.h(s[which]); + } + function j(bytes calldata s) external pure returns (bytes memory) { + return abi.encode(s); + } + function k(bytes[2] calldata s, uint256 which) external view returns (bytes memory) { + return this.j(s[which]); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// f(uint256[]): 32, 3, 42, 23, 87 -> 32, 160, 32, 3, 42, 23, 87 +// g(uint256[][2],uint256): 0x40, 0, 0x40, 0xC0, 3, 42, 23, 87, 4, 11, 13, 17 -> 32, 160, 32, 3, 42, 23, 87 +// g(uint256[][2],uint256): 0x40, 1, 0x40, 0xC0, 3, 42, 23, 87, 4, 11, 13, 17, 27 -> 32, 192, 32, 4, 11, 13, 17, 27 +// h(uint8[]): 32, 3, 42, 23, 87 -> 32, 160, 32, 3, 42, 23, 87 +// i(uint8[][2],uint256): 0x40, 0, 0x40, 0xC0, 3, 42, 23, 87, 4, 11, 13, 17 -> 32, 160, 32, 3, 42, 23, 87 +// i(uint8[][2],uint256): 0x40, 1, 0x40, 0xC0, 3, 42, 23, 87, 4, 11, 13, 17, 27 -> 32, 192, 32, 4, 11, 13, 17, 27 +// j(bytes): 32, 3, hex"AB11FF" -> 32, 96, 32, 3, left(0xAB11FF) +// k(bytes[2],uint256): 0x40, 0, 0x40, 0x63, 3, hex"AB11FF", 4, hex"FF791432" -> 32, 96, 32, 3, left(0xAB11FF) +// k(bytes[2],uint256): 0x40, 1, 0x40, 0x63, 3, hex"AB11FF", 4, hex"FF791432" -> 32, 96, 32, 4, left(0xFF791432) diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_dynamic.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_dynamic.sol new file mode 100644 index 000000000..6bb10c143 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_dynamic.sol @@ -0,0 +1,49 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f(uint8[][1][] calldata s) external pure returns (bytes memory) { + return msg.data; + } + function f2(uint256[][2][] calldata s) external pure returns (bytes memory) { + return msg.data; + } + function reenc_f(uint8[][1][] calldata s) external view returns (bytes memory) { + return this.f(s); + } + function reenc_f2(uint256[][2][] calldata s) external view returns (bytes memory) { + return this.f2(s); + } + function g() external returns (bytes memory) { + uint8[][1][] memory m = new uint8[][1][](1); + m[0][0] = new uint8[](1); + m[0][0][0] = 42; + return this.f(m); + } + function h() external returns (bytes memory) { + uint8[][1][] memory m = new uint8[][1][](1); + m[0][0] = new uint8[](1); + m[0][0][0] = 42; + return this.reenc_f(m); + } + function i() external returns (bytes memory) { + uint256[][2][] memory m = new uint256[][2][](1); + m[0][0] = new uint256[](1); + m[0][1] = new uint256[](1); + m[0][0][0] = 42; + m[0][1][0] = 42; + return this.f2(m); + } + function j() external returns (bytes memory) { + uint256[][2][] memory m = new uint256[][2][](1); + m[0][0] = new uint256[](1); + m[0][1] = new uint256[](1); + m[0][0][0] = 42; + m[0][1][0] = 42; + return this.reenc_f2(m); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// g() -> 32, 196, hex"eccb829a", 32, 1, 32, 32, 1, 42, hex"00000000000000000000000000000000000000000000000000000000" +// h() -> 32, 196, hex"eccb829a", 32, 1, 32, 32, 1, 42, hex"00000000000000000000000000000000000000000000000000000000" diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_function_types.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_function_types.sol new file mode 100644 index 000000000..c9ccc88a8 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_function_types.sol @@ -0,0 +1,30 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f(function() external returns (uint)[] calldata s) external returns (uint, uint, uint) { + assert(s.length == 3); + return (s[0](), s[1](), s[2]()); + } + function f_reenc(function() external returns (uint)[] calldata s) external returns (uint, uint, uint) { + return this.f(s); + } + function getter1() external returns (uint) { + return 23; + } + function getter2() external returns (uint) { + return 37; + } + function getter3() external returns (uint) { + return 71; + } + function g(bool reenc) external returns (uint, uint, uint) { + function() external returns (uint)[] memory a = new function() external returns (uint)[](3); + a[0] = this.getter1; + a[1] = this.getter2; + a[2] = this.getter3; + return reenc ? this.f_reenc(a) : this.f(a); + } +} +// ---- +// g(bool): false -> 23, 37, 71 +// g(bool): true -> 23, 37, 71 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_multi_dynamic.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_multi_dynamic.sol new file mode 100644 index 000000000..f981a6e46 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_multi_dynamic.sol @@ -0,0 +1,31 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f(uint256[][] calldata s) external pure returns (bytes memory) { + return abi.encode(s); + } + function g(uint256[][] calldata s) external view returns (bytes memory) { + return this.f(s); + } + function h(uint8[][] calldata s) external pure returns (bytes memory) { + return abi.encode(s); + } + function i(uint8[][] calldata s) external view returns (bytes memory) { + return this.h(s); + } + function j(bytes[] calldata s) external pure returns (bytes memory) { + return abi.encode(s); + } + function k(bytes[] calldata s) external view returns (bytes memory) { + return this.j(s); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// f(uint256[][]): 0x20, 2, 0x40, 0xC0, 3, 13, 17, 23, 4, 27, 31, 37, 41 -> 32, 416, 32, 2, 64, 192, 3, 13, 17, 23, 4, 27, 31, 37, 41 +// g(uint256[][]): 0x20, 2, 0x40, 0xC0, 3, 13, 17, 23, 4, 27, 31, 37, 41 -> 32, 416, 32, 2, 64, 192, 3, 13, 17, 23, 4, 27, 31, 37, 41 +// h(uint8[][]): 0x20, 2, 0x40, 0xC0, 3, 13, 17, 23, 4, 27, 31, 37, 41 -> 32, 416, 32, 2, 64, 192, 3, 13, 17, 23, 4, 27, 31, 37, 41 +// i(uint8[][]): 0x20, 2, 0x40, 0xC0, 3, 13, 17, 23, 4, 27, 31, 37, 41 -> 32, 416, 32, 2, 64, 192, 3, 13, 17, 23, 4, 27, 31, 37, 41 +// j(bytes[]): 0x20, 2, 0x40, 0x63, 3, hex"131723", 4, hex"27313741" -> 32, 256, 32, 2, 64, 128, 3, left(0x131723), 4, left(0x27313741) +// k(bytes[]): 0x20, 2, 0x40, 0x63, 3, hex"131723", 4, hex"27313741" -> 32, 256, 32, 2, 64, 128, 3, left(0x131723), 4, left(0x27313741) diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static.sol new file mode 100644 index 000000000..9c6386e31 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static.sol @@ -0,0 +1,25 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f(uint256[3] calldata s) external pure returns (bytes memory) { + return abi.encode(s); + } + function g(uint256[3] calldata s) external view returns (bytes memory) { + return this.f(s); + } + function h(uint8[3] calldata s) external pure returns (bytes memory) { + return abi.encode(s); + } + function i(uint8[3] calldata s) external view returns (bytes memory) { + return this.h(s); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// f(uint256[3]): 23, 42, 87 -> 32, 96, 23, 42, 87 +// g(uint256[3]): 23, 42, 87 -> 32, 96, 23, 42, 87 +// h(uint8[3]): 23, 42, 87 -> 32, 96, 23, 42, 87 +// i(uint8[3]): 23, 42, 87 -> 32, 96, 23, 42, 87 +// h(uint8[3]): 0xFF23, 0x1242, 0xAB87 -> FAILURE +// i(uint8[3]): 0xAB23, 0x1242, 0xFF87 -> FAILURE diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_dynamic_static.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_dynamic_static.sol new file mode 100644 index 000000000..6e8361d4a --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_dynamic_static.sol @@ -0,0 +1,49 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f(uint8[1][][1] calldata s) external pure returns (bytes memory) { + return msg.data; + } + function f2(uint256[2][][2] calldata s) external pure returns (bytes memory) { + return msg.data; + } + function reenc_f(uint8[1][][1] calldata s) external view returns (bytes memory) { + return this.f(s); + } + function reenc_f2(uint256[2][][2] calldata s) external view returns (bytes memory) { + return this.f2(s); + } + function g() external returns (bytes memory) { + uint8[1][][1] memory m = [new uint8[1][](1)]; + m[0][0][0] = 42; + return this.f(m); + } + function h() external returns (bytes memory) { + uint8[1][][1] memory m = [new uint8[1][](1)]; + m[0][0][0] = 42; + return this.reenc_f(m); + } + function i() external returns (bytes memory) { + uint256[2][][2] memory m = [new uint256[2][](1),new uint256[2][](1)]; + m[0][0][0] = 0x00042; + m[0][0][1] = 0x00142; + m[1][0][0] = 0x10042; + m[1][0][1] = 0x10142; + return this.f2(m); + } + function j() external returns (bytes memory) { + uint256[2][][2] memory m = [new uint256[2][](1),new uint256[2][](1)]; + m[0][0][0] = 0x00042; + m[0][0][1] = 0x00142; + m[1][0][0] = 0x10042; + m[1][0][1] = 0x10142; + return this.reenc_f2(m); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// g() -> 32, 132, hex"15cfcc01", 32, 32, 1, 42, hex"00000000000000000000000000000000000000000000000000000000" +// h() -> 32, 132, hex"15cfcc01", 32, 32, 1, 42, hex"00000000000000000000000000000000000000000000000000000000" +// i() -> 32, 292, hex"dc0ee233", 32, 64, 160, 1, 0x42, 0x000142, 1, 0x010042, 0x010142, hex"00000000000000000000000000000000000000000000000000000000" +// j() -> 32, 292, hex"dc0ee233", 32, 64, 160, 1, 0x42, 0x000142, 1, 0x010042, 0x010142, hex"00000000000000000000000000000000000000000000000000000000" diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_index_access.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_index_access.sol new file mode 100644 index 000000000..4bf181db3 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_index_access.sol @@ -0,0 +1,25 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f(uint256[3] calldata s) external pure returns (bytes memory) { + return abi.encode(s); + } + function g(uint256[3][2] calldata s, uint256 which) external view returns (bytes memory) { + return this.f(s[which]); + } + function h(uint8[3] calldata s) external pure returns (bytes memory) { + return abi.encode(s); + } + function i(uint8[3][2] calldata s, uint256 which) external view returns (bytes memory) { + return this.h(s[which]); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// f(uint256[3]): 23, 42, 87 -> 32, 96, 23, 42, 87 +// g(uint256[3][2],uint256): 23, 42, 87, 123, 142, 187, 0 -> 32, 96, 23, 42, 87 +// g(uint256[3][2],uint256): 23, 42, 87, 123, 142, 187, 1 -> 32, 96, 123, 142, 187 +// h(uint8[3]): 23, 42, 87 -> 32, 96, 23, 42, 87 +// i(uint8[3][2],uint256): 23, 42, 87, 123, 142, 187, 0 -> 32, 96, 23, 42, 87 +// i(uint8[3][2],uint256): 23, 42, 87, 123, 142, 187, 1 -> 32, 96, 123, 142, 187 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_struct_dynamic.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_struct_dynamic.sol new file mode 100644 index 000000000..02322d504 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_struct_dynamic.sol @@ -0,0 +1,16 @@ +pragma experimental ABIEncoderV2; + +contract C { + struct S { uint256[] a; } + function f(S[] calldata s) external pure returns (bytes memory) { + return abi.encode(s); + } + function g(S[] calldata s) external view returns (bytes memory) { + return this.f(s); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// f((uint256[])[]): 32, 1, 32, 32, 3, 17, 42, 23 -> 32, 256, 32, 1, 32, 32, 3, 17, 42, 23 +// g((uint256[])[]): 32, 1, 32, 32, 3, 17, 42, 23 -> 32, 256, 32, 1, 32, 32, 3, 17, 42, 23 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_dynamic.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_dynamic.sol new file mode 100644 index 000000000..16ba40630 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_dynamic.sol @@ -0,0 +1,20 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f(uint256[] calldata s1, uint256[] calldata s2, bool which) external pure returns (bytes memory) { + if (which) + return abi.encode(s1); + else + return abi.encode(s2); + } + function g(uint256[] calldata s1, uint256[] calldata s2, bool which) external view returns (bytes memory) { + return this.f(s1, s2, which); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// f(uint256[],uint256[],bool): 0x60, 0xE0, true, 3, 23, 42, 87, 2, 51, 72 -> 32, 160, 0x20, 3, 23, 42, 87 +// f(uint256[],uint256[],bool): 0x60, 0xE0, false, 3, 23, 42, 87, 2, 51, 72 -> 32, 128, 0x20, 2, 51, 72 +// g(uint256[],uint256[],bool): 0x60, 0xE0, true, 3, 23, 42, 87, 2, 51, 72 -> 32, 160, 0x20, 3, 23, 42, 87 +// g(uint256[],uint256[],bool): 0x60, 0xE0, false, 3, 23, 42, 87, 2, 51, 72 -> 32, 128, 0x20, 2, 51, 72 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_static.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_static.sol new file mode 100644 index 000000000..a4d1af66d --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_static.sol @@ -0,0 +1,20 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f(uint256[3] calldata s1, uint256[2] calldata s2, bool which) external pure returns (bytes memory) { + if (which) + return abi.encode(s1); + else + return abi.encode(s2); + } + function g(uint256[3] calldata s1, uint256[2] calldata s2, bool which) external view returns (bytes memory) { + return this.f(s1, s2, which); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// f(uint256[3],uint256[2],bool): 23, 42, 87, 51, 72, true -> 32, 96, 23, 42, 87 +// f(uint256[3],uint256[2],bool): 23, 42, 87, 51, 72, false -> 32, 64, 51, 72 +// g(uint256[3],uint256[2],bool): 23, 42, 87, 51, 72, true -> 32, 96, 23, 42, 87 +// g(uint256[3],uint256[2],bool): 23, 42, 87, 51, 72, false -> 32, 64, 51, 72 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_dynamic.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_dynamic.sol new file mode 100644 index 000000000..29ff15692 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_dynamic.sol @@ -0,0 +1,18 @@ +pragma experimental ABIEncoderV2; + +contract C { + struct S { uint256[] a; } + + function f(S calldata s) external returns (bytes memory) { + return abi.encode(s); + } + + function g(S calldata s) external returns (bytes memory) { + return this.f(s); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// f((uint256[])): 0x20, 0x20, 3, 42, 23, 17 -> 32, 192, 0x20, 0x20, 3, 42, 23, 17 +// g((uint256[])): 0x20, 0x20, 3, 42, 23, 17 -> 32, 192, 0x20, 0x20, 3, 42, 23, 17 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_simple.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_simple.sol new file mode 100644 index 000000000..f369321c3 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_simple.sol @@ -0,0 +1,18 @@ +pragma experimental ABIEncoderV2; + +contract C { + struct S { uint256 a; } + + function f(S calldata s) external returns (bytes memory) { + return abi.encode(s); + } + + function g(S calldata s) external returns (bytes memory) { + return this.f(s); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// f((uint256)): 3 -> 32, 32, 3 +// g((uint256)): 3 -> 32, 32, 3