Skip to content

Commit

Permalink
speed up tuple and array decoding
Browse files Browse the repository at this point in the history
  • Loading branch information
esaulpaugh committed Dec 7, 2022
1 parent f9cab76 commit 6efd455
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 33 deletions.
25 changes: 23 additions & 2 deletions src/main/java/com/esaulpaugh/headlong/abi/ArrayType.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.function.IntUnaryOperator;

import static com.esaulpaugh.headlong.abi.Encoding.OFFSET_LENGTH_BYTES;
import static com.esaulpaugh.headlong.abi.Encoding.UINT31;
import static com.esaulpaugh.headlong.abi.TupleType.countBytes;
import static com.esaulpaugh.headlong.abi.TupleType.totalLen;
import static com.esaulpaugh.headlong.abi.UnitType.UNIT_LENGTH_BYTES;
Expand Down Expand Up @@ -461,8 +462,28 @@ private static long[] decodeLongs(int len, ByteBuffer bb, LongType longType, byt
}

private Object[] decodeObjects(int len, ByteBuffer bb, byte[] unitBuffer) {
Object[] elements = (Object[]) Array.newInstance(elementType.clazz, len); // reflection ftw
TupleType.decodeObjects(bb, unitBuffer, i -> elementType, elements, false);
final Object[] elements = (Object[]) Array.newInstance(elementType.clazz, len); // reflection ftw
int i = 0;
try {
if (!elementType.dynamic) {
for ( ; i < elements.length; i++) {
elements[i] = elementType.decode(bb, unitBuffer);
}
} else {
final int start = bb.position(); // save this value before offsets are decoded
int saved = start;
for (; i < elements.length; i++) {
bb.position(saved);
final int jump = start + UINT31.decode(bb, unitBuffer);
/* LENIENT MODE; see https://github.com/ethereum/solidity/commit/3d1ca07e9b4b42355aa9be5db5c00048607986d1 */
saved = bb.position();
bb.position(jump); // leniently jump to specified offset
elements[i] = elementType.decode(bb, unitBuffer);
}
}
} catch (IllegalArgumentException cause) {
throw TupleType.decodeException(false, i, cause);
}
return elements;
}

Expand Down
59 changes: 28 additions & 31 deletions src/main/java/com/esaulpaugh/headlong/abi/TupleType.java
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,34 @@ private void encodeDynamic(Object[] values, ByteBuffer dest) {

@Override
Tuple decode(ByteBuffer bb, byte[] unitBuffer) {
Object[] elements = new Object[size()];
decodeObjects(bb, unitBuffer, TupleType.this::get, elements, true);
final Object[] elements = new Object[size()];
int i = 0;
try {
final int start = bb.position(); // save this value before offsets are decoded
final int[] offsets = new int[elements.length];
for ( ; i < elements.length; i++) {
ABIType<?> t = elementTypes[i];
if (!t.dynamic) {
elements[i] = t.decode(bb, unitBuffer);
} else {
final int offset = UINT31.decode(bb, unitBuffer);
offsets[i] = offset == 0 ? -1 : offset;
}
}
for (i = 0; i < elements.length; i++) {
final int offset = offsets[i];
if (offset != 0) {
final int jump = start + offset;
if (jump != bb.position()) {
/* LENIENT MODE; see https://github.com/ethereum/solidity/commit/3d1ca07e9b4b42355aa9be5db5c00048607986d1 */
bb.position(offset == -1 ? start : jump); // leniently jump to specified offset
}
elements[i] = elementTypes[i].decode(bb, unitBuffer);
}
}
} catch (IllegalArgumentException cause) {
throw decodeException(true, i, cause);
}
return new Tuple(elements);
}

Expand Down Expand Up @@ -287,35 +313,6 @@ int staticTupleHeadLength() {
return len;
}

static void decodeObjects(ByteBuffer bb, byte[] unitBuffer, IntFunction<ABIType<?>> getType, Object[] objects, boolean tuple) {
int i = 0;
try {
final int start = bb.position(); // save this value before offsets are decoded
final int[] offsets = new int[objects.length];
for (i = 0; i < objects.length; i++) {
ABIType<?> t = getType.apply(i);
if (!t.dynamic) {
objects[i] = t.decode(bb, unitBuffer);
} else {
offsets[i] = UINT31.decode(bb, unitBuffer);
}
}
for (i = 0; i < objects.length; i++) {
final int offset = offsets[i];
if (offset > 0) {
final int jump = start + offset;
if (jump != bb.position()) {
/* LENIENT MODE; see https://github.com/ethereum/solidity/commit/3d1ca07e9b4b42355aa9be5db5c00048607986d1 */
bb.position(jump); // leniently jump to specified offset
}
objects[i] = getType.apply(i).decode(bb, unitBuffer);
}
}
} catch (IllegalArgumentException cause) {
throw decodeException(tuple, i, cause);
}
}

static IllegalArgumentException decodeException(boolean tuple, int i, IllegalArgumentException cause) {
return new IllegalArgumentException((tuple ? "tuple index " : "array index ") + i + ": " + cause.getMessage(), cause);
}
Expand Down

0 comments on commit 6efd455

Please sign in to comment.