Description
DefaultFunctionEncoder calculates offset incorrectly for nested structs
Steps To Reproduce
Minimal example:
- Create function which has nested structs as parameters, like:
var f = new org.web3j.abi.datatypes.Function(
"myCustomFunction",
Arrays.asList(
new StaticStruct(
new StaticStruct(
new org.web3j.abi.datatypes.Address("0x1"),
new org.web3j.abi.datatypes.Address("0x2"))),
new org.web3j.abi.datatypes.DynamicBytes(new byte[]{1,2,3})),
Collections.emptyList());
Note that first argument is StaticStruct having one property which is also StaticStruct, nested one have two Address properties, which is important in this example. Also having dynamic type as second argument is important.
- Execute
FunctionEncoder.encode(f)
. Result will be:
0x76a4d94f
0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000002
0000000000000000000000000000000000000000000000000000000000000040
0000000000000000000000000000000000000000000000000000000000000003
0102030000000000000000000000000000000000000000000000000000000000
- In result, since second argument is dynamic (DynamicBytes type) offset is included.
Expected behavior
Offset value in that case should equal to 0x60
.
Actual behavior
Offset value is (as you can see above) 0x40
, this is because nested StaticStruct is calculated to have size of 1 (but 2 addresses are inside, so size should be 2).
Environment
- Web3j version 4.10.3
- Java 17
- Operating System Fedora 38 x64, kernel Linux 6.8.7-100.fc38.x86_64
Additional context
My production case, Im attaching two executions:
- first one with wrong offset (
0xe0
in my case), failure:
MethodID: 0x30f28b7a
[0]: 00000000000000000000000002567e4b14b25549331fcee2b56c647a8bab16fd
[1]: 0000000000000000000000000000000000000000000000000de0b6b3a7640000
[2]: 0000000000000000000000000000000000000000000000000000000000000006
[3]: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
[4]: 000000000000000000000000f909259faf3f052792d7d28fb25ae54c43243041
[5]: 0000000000000000000000000000000000000000000000000de0b6b3a7640000
[6]: 000000000000000000000000d1f92a7f86cc94639ed6f3acd2ed540c742602dc
[7]: 00000000000000000000000000000000000000000000000000000000000000e0
[8]: 0000000000000000000000000000000000000000000000000000000000000041
[9]: 7d117587f7976edc3e9043e2ed79be2aa61b49d4513a410bfcc915b146663854
[10]: 253ccba5465141beb4f92adafdef1ab510a5854a61cdb860a1a3ceb1ae86d971
[11]: 1c00000000000000000000000000000000000000000000000000000000000000
- second with adjusted offset (
0x100
), succeeded:
MethodID: 0x30f28b7a
[0]: 00000000000000000000000002567e4b14b25549331fcee2b56c647a8bab16fd
[1]: 0000000000000000000000000000000000000000000000000de0b6b3a7640000
[2]: 0000000000000000000000000000000000000000000000000000000000000006
[3]: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
[4]: 000000000000000000000000f909259faf3f052792d7d28fb25ae54c43243041
[5]: 0000000000000000000000000000000000000000000000000de0b6b3a7640000
[6]: 000000000000000000000000d1f92a7f86cc94639ed6f3acd2ed540c742602dc
[7]: 0000000000000000000000000000000000000000000000000000000000000100
[8]: 0000000000000000000000000000000000000000000000000000000000000041
[9]: 7d117587f7976edc3e9043e2ed79be2aa61b49d4513a410bfcc915b146663854
[10]: 253ccba5465141beb4f92adafdef1ab510a5854a61cdb860a1a3ceb1ae86d971
[11]: 1c00000000000000000000000000000000000000000000000000000000000000
I think the solution is to make getLength
function recursive, and change line:
https://github.com/hyperledger/web3j/blob/5173684412b4d816fc1b4b8bf6c112424a37c7ce/abi/src/main/java/org/web3j/abi/DefaultFunctionEncoder.java#L102
to count += getLength(((StaticArray) type).getValue())