diff options
-rw-r--r-- | docs/abi-spec.rst | 30 | ||||
-rw-r--r-- | libsolidity/interface/ABI.cpp | 2 | ||||
-rw-r--r-- | test/libsolidity/SolidityABIJSON.cpp | 16 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 31 |
4 files changed, 52 insertions, 27 deletions
diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index 6df9f1d5..f4822be7 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -68,13 +68,12 @@ The following non-fixed-size types exist: - ``<type>[]``: a variable-length array of the given fixed-length type. -Types can be combined to anonymous structs by enclosing a finite non-negative number +Types can be combined to a tuple by enclosing a finite non-negative number of them inside parentheses, separated by commas: -- ``(T1,T2,...,Tn)``: anonymous struct (ordered tuple) consisting of the types ``T1``, ..., ``Tn``, ``n >= 0`` - -It is possible to form structs of structs, arrays of structs and so on. +- ``(T1,T2,...,Tn)``: tuple consisting of the types ``T1``, ..., ``Tn``, ``n >= 0`` +It is possible to form tuples of tuples, arrays of tuples and so on. Formal Specification of the Encoding ==================================== @@ -133,7 +132,7 @@ on the type of ``X`` being ``enc(X) = enc((X[0], ..., X[k-1]))`` - i.e. it is encoded as if it were an anonymous struct with ``k`` elements + i.e. it is encoded as if it were a tuple with ``k`` elements of the same type. - ``T[]`` where ``X`` has ``k`` elements (``k`` is assumed to be of type ``uint256``): @@ -176,7 +175,7 @@ and the return values ``v_1, ..., v_k`` of ``f`` are encoded as ``enc((v_1, ..., v_k))`` -i.e. the values are combined into an anonymous struct and encoded. +i.e. the values are combined into a tuple and encoded. Examples ======== @@ -357,16 +356,17 @@ would result in the JSON: "outputs": [] }] -Use of Structs in Types ------------------------ +Handling tuple types +-------------------- -If structs are part of the type, we still want to know the name of the components. Because of that, +If tuples are part of the type, we still want to know the name of the components. Because of that, the json structure gets arbitrarily nested in the following way: An object with members ``name``, ``type`` and potentially ``components`` describes a typed variable. -The canonical type is determined until a struct type is reached and the string description up -to that point is stored in ``type``, i.e. it will be a sequence of ``[]`` and ``[k]`` with -integers ``k``. The components of the struct are then stored in the member ``components``, +The canonical type is determined until a tuple type is reached and the string description up +to that point is stored in ``type`` prefix with the word ``tuple``, i.e. it will be ``tuple`` followed by +a sequence of ``[]`` and ``[k]`` with +integers ``k``. The components of the tuple are then stored in the member ``components``, which is of array type and has the same structure as the top-level object except that ``indexed`` is not allowed there. @@ -391,7 +391,7 @@ would result in the JSON: "inputs": [ { "name": "s", - "type": "", + "type": "tuple", "components": [ { "name": "a", @@ -403,7 +403,7 @@ would result in the JSON: }, { "name": "c", - "type": "[]", + "type": "tuple[]", "components": [ { "name": "x", @@ -419,7 +419,7 @@ would result in the JSON: }, { "name": "t", - "type": "", + "type": "tuple", "components": [ { "name": "x", diff --git a/libsolidity/interface/ABI.cpp b/libsolidity/interface/ABI.cpp index 9af7cdc3..aefb34af 100644 --- a/libsolidity/interface/ABI.cpp +++ b/libsolidity/interface/ABI.cpp @@ -147,7 +147,7 @@ Json::Value ABI::formatType(string const& _name, Type const& _type, bool _forLib } else if (StructType const* structType = dynamic_cast<StructType const*>(&_type)) { - ret["type"] = string(); + ret["type"] = "tuple"; ret["components"] = Json::arrayValue; for (auto const& member: structType->members(nullptr)) { diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp index e4ab54ec..e5d9e99c 100644 --- a/test/libsolidity/SolidityABIJSON.cpp +++ b/test/libsolidity/SolidityABIJSON.cpp @@ -973,11 +973,11 @@ BOOST_AUTO_TEST_CASE(return_structs) } ], "name" : "sub", - "type" : "[]" + "type" : "tuple[]" } ], "name" : "s", - "type" : "" + "type" : "tuple" } ], "payable" : false, @@ -1015,7 +1015,7 @@ BOOST_AUTO_TEST_CASE(return_structs_with_contracts) } ], "name": "s", - "type": "" + "type": "tuple" }, { "name": "c", @@ -1052,7 +1052,7 @@ BOOST_AUTO_TEST_CASE(event_structs) ], "indexed": false, "name": "t", - "type": "" + "type": "tuple" }, { "components": [ @@ -1068,7 +1068,7 @@ BOOST_AUTO_TEST_CASE(event_structs) } ], "name": "sub", - "type": "[]" + "type": "tuple[]" }, { "name": "b", @@ -1077,7 +1077,7 @@ BOOST_AUTO_TEST_CASE(event_structs) ], "indexed": false, "name": "s", - "type": "" + "type": "tuple" } ], "name": "E", @@ -1115,7 +1115,7 @@ BOOST_AUTO_TEST_CASE(structs_in_libraries) } ], "name": "sub", - "type": "[]" + "type": "tuple[]" }, { "name": "b", @@ -1123,7 +1123,7 @@ BOOST_AUTO_TEST_CASE(structs_in_libraries) } ], "name": "s", - "type": "" + "type": "tuple" } ], "name": "g", diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 778c12c5..5ab824d3 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -601,7 +601,6 @@ BOOST_AUTO_TEST_CASE(enum_external_type) BOOST_AUTO_TEST_CASE(external_structs) { - ASTPointer<SourceUnit> sourceUnit; char const* text = R"( contract Test { enum ActionChoices { GoLeft, GoRight, GoStraight, Sit } @@ -614,7 +613,7 @@ BOOST_AUTO_TEST_CASE(external_structs) function i(Nested[]) external {} } )"; - ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseAndAnalyse(text), "Parsing and name Resolving failed"); + SourceUnit const* sourceUnit = parseAndAnalyse(text); for (ASTPointer<ASTNode> const& node: sourceUnit->nodes()) if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get())) { @@ -627,7 +626,33 @@ BOOST_AUTO_TEST_CASE(external_structs) } } -// TODO: Add a test that checks the signature of library functions taking structs +BOOST_AUTO_TEST_CASE(external_structs_in_libraries) +{ + char const* text = R"( + library Test { + enum ActionChoices { GoLeft, GoRight, GoStraight, Sit } + struct Empty {} + struct Nested { X[2][] a; mapping(uint => uint) m; uint y; } + struct X { bytes32 x; Test t; Empty[] e; } + function f(ActionChoices, uint, Empty) external {} + function g(Test, Nested) external {} + function h(function(Nested) external returns (uint)[]) external {} + function i(Nested[]) external {} + } + )"; + SourceUnit const* sourceUnit = parseAndAnalyse(text); + for (ASTPointer<ASTNode> const& node: sourceUnit->nodes()) + if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get())) + { + auto functions = contract->definedFunctions(); + BOOST_REQUIRE(!functions.empty()); + BOOST_CHECK_EQUAL("f(Test.ActionChoices,uint256,Test.Empty)", functions[0]->externalSignature()); + BOOST_CHECK_EQUAL("g(Test,Test.Nested)", functions[1]->externalSignature()); + BOOST_CHECK_EQUAL("h(function[])", functions[2]->externalSignature()); + BOOST_CHECK_EQUAL("i(Test.Nested[])", functions[3]->externalSignature()); + } +} + BOOST_AUTO_TEST_CASE(function_external_call_allowed_conversion) { |