mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Use "tuple" for struct types in ABI JSON.
Only use tuple as a type in the ABI (and remove all "anonymous struct" references too)
This commit is contained in:
parent
70d70e7816
commit
c5063d3155
docs
libsolidity/interface
test/libsolidity
@ -68,13 +68,12 @@ The following non-fixed-size types exist:
|
|||||||
|
|
||||||
- ``<type>[]``: a variable-length array of the given fixed-length type.
|
- ``<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:
|
of them inside parentheses, separated by commas:
|
||||||
|
|
||||||
- ``(T1,T2,...,Tn)``: anonymous struct (ordered tuple) consisting of the types ``T1``, ..., ``Tn``, ``n >= 0``
|
- ``(T1,T2,...,Tn)``: tuple consisting of the types ``T1``, ..., ``Tn``, ``n >= 0``
|
||||||
|
|
||||||
It is possible to form structs of structs, arrays of structs and so on.
|
|
||||||
|
|
||||||
|
It is possible to form tuples of tuples, arrays of tuples and so on.
|
||||||
|
|
||||||
Formal Specification of the Encoding
|
Formal Specification of the Encoding
|
||||||
====================================
|
====================================
|
||||||
@ -133,7 +132,7 @@ on the type of ``X`` being
|
|||||||
|
|
||||||
``enc(X) = enc((X[0], ..., X[k-1]))``
|
``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.
|
of the same type.
|
||||||
|
|
||||||
- ``T[]`` where ``X`` has ``k`` elements (``k`` is assumed to be of type ``uint256``):
|
- ``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))``
|
``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
|
Examples
|
||||||
========
|
========
|
||||||
@ -357,16 +356,17 @@ would result in the JSON:
|
|||||||
"outputs": []
|
"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:
|
the json structure gets arbitrarily nested in the following way:
|
||||||
|
|
||||||
An object with members ``name``, ``type`` and potentially ``components`` describes a typed variable.
|
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
|
The canonical type is determined until a tuple 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
|
to that point is stored in ``type`` prefix with the word ``tuple``, i.e. it will be ``tuple`` followed by
|
||||||
integers ``k``. The components of the struct are then stored in the member ``components``,
|
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
|
which is of array type and has the same structure as the top-level object except that
|
||||||
``indexed`` is not allowed there.
|
``indexed`` is not allowed there.
|
||||||
|
|
||||||
@ -391,7 +391,7 @@ would result in the JSON:
|
|||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
"name": "s",
|
"name": "s",
|
||||||
"type": "",
|
"type": "tuple",
|
||||||
"components": [
|
"components": [
|
||||||
{
|
{
|
||||||
"name": "a",
|
"name": "a",
|
||||||
@ -403,7 +403,7 @@ would result in the JSON:
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "c",
|
"name": "c",
|
||||||
"type": "[]",
|
"type": "tuple[]",
|
||||||
"components": [
|
"components": [
|
||||||
{
|
{
|
||||||
"name": "x",
|
"name": "x",
|
||||||
@ -419,7 +419,7 @@ would result in the JSON:
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "t",
|
"name": "t",
|
||||||
"type": "",
|
"type": "tuple",
|
||||||
"components": [
|
"components": [
|
||||||
{
|
{
|
||||||
"name": "x",
|
"name": "x",
|
||||||
|
@ -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))
|
else if (StructType const* structType = dynamic_cast<StructType const*>(&_type))
|
||||||
{
|
{
|
||||||
ret["type"] = string();
|
ret["type"] = "tuple";
|
||||||
ret["components"] = Json::arrayValue;
|
ret["components"] = Json::arrayValue;
|
||||||
for (auto const& member: structType->members(nullptr))
|
for (auto const& member: structType->members(nullptr))
|
||||||
{
|
{
|
||||||
|
@ -973,11 +973,11 @@ BOOST_AUTO_TEST_CASE(return_structs)
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name" : "sub",
|
"name" : "sub",
|
||||||
"type" : "[]"
|
"type" : "tuple[]"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name" : "s",
|
"name" : "s",
|
||||||
"type" : ""
|
"type" : "tuple"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"payable" : false,
|
"payable" : false,
|
||||||
@ -1015,7 +1015,7 @@ BOOST_AUTO_TEST_CASE(return_structs_with_contracts)
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name": "s",
|
"name": "s",
|
||||||
"type": ""
|
"type": "tuple"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "c",
|
"name": "c",
|
||||||
@ -1052,7 +1052,7 @@ BOOST_AUTO_TEST_CASE(event_structs)
|
|||||||
],
|
],
|
||||||
"indexed": false,
|
"indexed": false,
|
||||||
"name": "t",
|
"name": "t",
|
||||||
"type": ""
|
"type": "tuple"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"components": [
|
"components": [
|
||||||
@ -1068,7 +1068,7 @@ BOOST_AUTO_TEST_CASE(event_structs)
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name": "sub",
|
"name": "sub",
|
||||||
"type": "[]"
|
"type": "tuple[]"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "b",
|
"name": "b",
|
||||||
@ -1077,7 +1077,7 @@ BOOST_AUTO_TEST_CASE(event_structs)
|
|||||||
],
|
],
|
||||||
"indexed": false,
|
"indexed": false,
|
||||||
"name": "s",
|
"name": "s",
|
||||||
"type": ""
|
"type": "tuple"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name": "E",
|
"name": "E",
|
||||||
@ -1115,7 +1115,7 @@ BOOST_AUTO_TEST_CASE(structs_in_libraries)
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name": "sub",
|
"name": "sub",
|
||||||
"type": "[]"
|
"type": "tuple[]"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "b",
|
"name": "b",
|
||||||
@ -1123,7 +1123,7 @@ BOOST_AUTO_TEST_CASE(structs_in_libraries)
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name": "s",
|
"name": "s",
|
||||||
"type": ""
|
"type": "tuple"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name": "g",
|
"name": "g",
|
||||||
|
@ -601,7 +601,6 @@ BOOST_AUTO_TEST_CASE(enum_external_type)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(external_structs)
|
BOOST_AUTO_TEST_CASE(external_structs)
|
||||||
{
|
{
|
||||||
ASTPointer<SourceUnit> sourceUnit;
|
|
||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
contract Test {
|
contract Test {
|
||||||
enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }
|
enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }
|
||||||
@ -614,7 +613,7 @@ BOOST_AUTO_TEST_CASE(external_structs)
|
|||||||
function i(Nested[]) external {}
|
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())
|
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
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)
|
BOOST_AUTO_TEST_CASE(function_external_call_allowed_conversion)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user