ethereum / ethereumj

DEPRECATED! Java implementation of the Ethereum yellowpaper. For JSON-RPC and other client features check Ethereum Harmony
GNU Lesser General Public License v3.0
2.18k stars 1.09k forks source link

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

Closed jondoe1337 closed 5 years ago

jondoe1337 commented 6 years ago

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
mkalinin commented 6 years ago

Would like to fix that one?

jondoe1337 commented 6 years ago

Any help appreciated. :)

mkalinin commented 6 years ago

requesting @Nashatyrev to take a look!

Nashatyrev commented 6 years ago

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 :)

Nashatyrev commented 6 years ago

@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)

jondoe1337 commented 6 years ago

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.

mkalinin commented 5 years ago

Addressed by https://github.com/ethereum/ethereumj/pull/1239