Skip to content

Commit

Permalink
Non dynamic structs fix on multidimensional arrays
Browse files Browse the repository at this point in the history
This ensures the element type is initialised on multiple inner arrays of structs as it needs to be calculated the size beforehand
  • Loading branch information
juanfranblanco committed Aug 12, 2023
1 parent 9d3ce60 commit 929c336
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 12 deletions.
48 changes: 36 additions & 12 deletions src/Nethereum.ABI/FunctionEncoding/ParameterDecoder.cs
Expand Up @@ -138,18 +138,7 @@ public List<ParameterOutputProperty> GetParameterOutputsFromAttributes(PropertyI
}
else if (parameterAttribute.Parameter.ABIType is ArrayType arrayType)
{
if (arrayType.ElementType is TupleType tupleTypeElement)
{
#if NETSTANDARD1_1 || PCL && !NET35
var type = property.PropertyType.GenericTypeArguments.FirstOrDefault();
#else
var type = property.PropertyType.GetGenericArguments().FirstOrDefault();
#endif
if (type == null) throw new Exception("Tuple array has to decode to a IList<T>: " + parameterAttribute.Parameter.Name);

attributesToABIExtractor.InitTupleComponentsFromTypeAttributes(type,
tupleTypeElement);
}
InitTupleElementFromArray(property, parameterAttribute, arrayType);

parameterAttribute.Parameter.DecodedType = property.PropertyType;
}
Expand All @@ -164,6 +153,41 @@ public List<ParameterOutputProperty> GetParameterOutputsFromAttributes(PropertyI
return parameterObjects;
}

private void InitTupleElementFromArray(PropertyInfo property, ParameterAttribute parameterAttribute, ArrayType arrayType, int depth = 1)
{
if (arrayType.ElementType is TupleType tupleTypeElement)
{
var type = GetListElementType(property.PropertyType, depth);
if (type == null) throw new Exception("Tuple array has to decode to a IList<T>: " + parameterAttribute.Parameter.Name);

attributesToABIExtractor.InitTupleComponentsFromTypeAttributes(type,
tupleTypeElement);
}

if(arrayType.ElementType is ArrayType arrayElementType)
{
InitTupleElementFromArray(property, parameterAttribute, arrayElementType, depth + 1);
}
}

private Type GetListElementType(Type startType, int depthOfLists)
{
#if NETSTANDARD1_1 || PCL && !NET35
var type = startType.GenericTypeArguments.FirstOrDefault();
#else
var type = startType.GetGenericArguments().FirstOrDefault();
#endif
for(int i = 1; i < depthOfLists; i++)
{
#if NETSTANDARD1_1 || PCL && !NET35
type = type.GenericTypeArguments.FirstOrDefault();
#else
type = type.GetGenericArguments().FirstOrDefault();
#endif
}
return type;

}

public List<ParameterOutputProperty> GetParameterOutputsFromAttributes(Type type)
{
Expand Down
@@ -0,0 +1,82 @@
using System.Collections.Generic;
using System.Numerics;
using Nethereum.ABI.FunctionEncoding;
using Nethereum.ABI.FunctionEncoding.Attributes;
using Xunit;

namespace Nethereum.ABI.UnitTests
{
public class FunctionMultidimensionalStructNonDynamicArrayDecodingTests
{
public partial class TestStruct : TestStructBase { }

public class TestStructBase
{
[Parameter("uint256", "x", 1)]
public virtual BigInteger X { get; set; }
[Parameter("uint256", "y", 2)]
public virtual BigInteger Y { get; set; }
[Parameter("uint256", "z", 3)]
public virtual BigInteger Z { get; set; }
}

public partial class GetTestStruct3dOutputDTO : GetTestStruct3dOutputDTOBase { }

[FunctionOutput]
public class GetTestStruct3dOutputDTOBase : IFunctionOutputDTO
{
[Parameter("tuple[][][]", "testStructs", 1)]
public virtual List<List<List<TestStruct>>> TestStructs { get; set; }
}

/*
function getTestStruct3d() public view returns (TestStruct[][][] memory testStructs) {
uint256 maxX = 2;
uint256 maxY = 2;
testStructs = new TestStruct[][][](maxX);
for (uint256 x; x < maxY; x++) {
testStructs[x] = new TestStruct[][](maxY);
for (uint256 y; y < maxY; y++) {
testStructs[x][y] = getTestStruct(x, y, 2);
}
}
}
struct TestStruct {
uint256 x;
uint256 y;
uint256 z;
}
function getTestStruct(uint x ,uint256 y, uint256 z) public view returns (TestStruct[] memory testStruct)
{
testStruct = new TestStruct[](z);
for (uint256 a = 0; a < z; a++) {
testStruct[a] =
TestStruct(x,
y,
a);
}
}
*/


[Fact]
public void ShouldDecode3dArrayWithStructsAsNonDynamic()
{
var output = "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001";
var functionDecoder = new FunctionCallDecoder();
var result = functionDecoder.DecodeFunctionOutput<GetTestStruct3dOutputDTO>(output);
Assert.Equal(1, result.TestStructs[1][1][1].Y);
Assert.Equal(1, result.TestStructs[1][1][1].Z);
Assert.Equal(1, result.TestStructs[1][1][1].X);

}


}
}

0 comments on commit 929c336

Please sign in to comment.