ethereum/ethereumj

Invocation fails with ArrayIndexOutOfBounds when multidimensional arrays are part of the signature

jondoe1337 opened this issue · 7 comments

Referring issue #1216 - I reactivated my initial unittest and bumped into the next problem.
The function is now found by signature, but the inputdata cannot be decoded.

Thread [main] (Suspended (exception ArrayIndexOutOfBoundsException))	
	System.arraycopy(Object, int, Object, int, int) line: not available [native method]	
	Arrays.copyOfRange(byte[], int, int) line: 3521	
	SolidityType$IntType.decodeInt(byte[], int) line: 446	
	SolidityType$AddressType(SolidityType$IntType).decode(byte[], int) line: 456	
	SolidityType$AddressType.decode(byte[], int) line: 399	
	SolidityType$DynamicArrayType.decode(byte[], int) line: 273	
	SolidityType$StaticArrayType.decode(byte[], int) line: 204	
	SolidityType$StaticArrayType.decode(byte[], int) line: 163	
	CallTransaction$Function.decode(byte[], CallTransaction$Param[]) line: 158	
	CallTransaction$Function.decode(byte[]) line: 166	
	CallTransaction$Contract.parseInvocation(byte[]) line: 285

I created a new unittest, could need some help however:

@Test
    public void twoDimensionalArrayTypeAsParameter_isDecoded() {
        String funcJson = "{  \n" + 
                "      \"constant\":false,\n" + 
                "      \"inputs\":[  \n" + 
                "         {  \n" + 
                "            \"name\":\"orderAddresses\",\n" + 
                "            \"type\":\"address[5][]\"\n" + 
                "         },\n" + 
                "         {  \n" + 
                "            \"name\":\"orderValues\",\n" + 
                "            \"type\":\"uint256[6][]\"\n" + 
                "         },\n" + 
                "         {  \n" + 
                "            \"name\":\"fillTakerTokenAmounts\",\n" + 
                "            \"type\":\"uint256[]\"\n" + 
                "         },\n" + 
                "         {  \n" + 
                "            \"name\":\"v\",\n" + 
                "            \"type\":\"uint8[]\"\n" + 
                "         },\n" + 
                "         {  \n" + 
                "            \"name\":\"r\",\n" + 
                "            \"type\":\"bytes32[]\"\n" + 
                "         },\n" + 
                "         {  \n" + 
                "            \"name\":\"s\",\n" + 
                "            \"type\":\"bytes32[]\"\n" + 
                "         }\n" + 
                "      ],\n" + 
                "      \"name\":\"batchFillOrKillOrders\",\n" + 
                "      \"outputs\":[],\n" + 
                "      \"payable\":false,\n" + 
                "      \"type\":\"function\"\n" + 
                "   }";
        funcJson = funcJson.replaceAll("'", "\"");
        CallTransaction.Function function = CallTransaction.Function.fromJsonInterface(funcJson);
        String input = "4f15078700000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000004e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000001b2a9cc5ea11c11b70908d75207b5b1f0ac4a839000000000000000000000000e697a9f14f182c5291287dbeb47d41773091f035000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000002d0ea9f9591205a642eb01826ba4fa019eb0efc60000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d640000000000000000000000001b2a9cc5ea11c11b70908d75207b5b1f0ac4a839000000000000000000000000e697a9f14f182c5291287dbeb47d41773091f0350000000000000000000000002d0ea9f9591205a642eb01826ba4fa019eb0efc6000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000dcef33a6f83800000000000000000000000000000000000000000000000000564d702d38f5e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000165fb1e4c5dc37a357a19313983db8360977d0c3cfe274a9deb63fc1a994f3c290b2644f0820000000000000000000000000000000000000000000000590353dc4fa7680000000000000000000000000000000000000000000000000000e3df8f00cbea07d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000165fb2d0c49cebe85312f1f1cc97430bc1315aff0fbb0d7f1219c8759774672c9939e168d3c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000c249fdd32778000000000000000000000000000000000000000000000000000001f161421c8e00110000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000029202d3602753ffdb469e9dbae74cbe7528c648f708334f7791acc6fe0ce8182bef362daf1bc2c805797761ae93a6c46ed53d73483a2bcc5b499ab65a8ba7f16c00000000000000000000000000000000000000000000000000000000000000020b43ad3ff547ebf5089802a74e764692bdc092190438b31be34d1d79406a75ba4e87fcd4ead36423d5bbcc7f1b41616235a17ec1f053a66827281bab104b718b";
        Object[] decode = function.decode(Hex.decode(input));
        Assert.assertNotEquals(decode.length, 0);
    }

If I look at the decoding from etherscan, the result should look like this:

0	orderAddresses	address[5][]	
1b2a9cc5ea11c11b70908d75207b5b1f0ac4a839
e697a9f14f182c5291287dbeb47d41773091f035
2d0ea9f9591205a642eb01826ba4fa019eb0efc6
c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
8124071f810d533ff63de61d0c98db99eeb99d64
1	orderValues	uint256[6][]	
1642000000000000000000
16420000000000002000
0
0
1537517358153
93513067008724755490443777049125356883124657581213787456489051336421643029820
2	fillTakerTokenAmounts	uint256[]	
14000000000000000000
140000000000000017
3	v	uint8[]	
27
28
4	r	bytes32[]	
9202d3602753ffdb469e9dbae74cbe7528c648f708334f7791acc6fe0ce8182b
ef362daf1bc2c805797761ae93a6c46ed53d73483a2bcc5b499ab65a8ba7f16c
5	s	bytes32[]	
0b43ad3ff547ebf5089802a74e764692bdc092190438b31be34d1d79406a75ba
4e87fcd4ead36423d5bbcc7f1b41616235a17ec1f053a66827281bab104b718b

Would like to fix that one?

Any help appreciated. :)

requesting @Nashatyrev to take a look!

https://solidity.readthedocs.io/en/v0.4.24/types.html#arrays

As an example, an array of 5 dynamic arrays of uint is uint[][5] (note that the notation is reversed when compared to some other languages)

U-u-u-ups :)

@jondoe1337 I did some fixes and this is how your sample input looks for me:
default
Does it look correct? (it differs from your decoding, but I'm sure it is not correct)

To be honest, my decoded result was from etherscan.io as well. But that might also not be 100% correct. However looks good to me.

Addressed by #1239