Skip to content

Commit

Permalink
fix length inserted for dynamic arrays with fixed number of elements
Browse files Browse the repository at this point in the history
bump version
  • Loading branch information
esaulpaugh committed May 17, 2019
1 parent 0c919fd commit 9535639
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 60 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,14 @@ Or build locally:
Clone the project and install to your local maven repository using `gradle publishToMavenLocal` or `mvn install`. Then you can use one of these:

```groovy
implementation 'com.esaulpaugh:headlong:1.4.3-SNAPSHOT'
implementation 'com.esaulpaugh:headlong:1.4.4-SNAPSHOT'
```

```xml
<dependency>
<groupId>com.esaulpaugh</groupId>
<artifactId>headlong</artifactId>
<version>1.4.3-SNAPSHOT</version>
<version>1.4.4-SNAPSHOT</version>
</dependency>
```
Alternatively:
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {
}

group 'com.esaulpaugh'
version '1.4.3-SNAPSHOT'
version '1.4.4-SNAPSHOT'

test {
maxParallelForks = (int) Runtime.runtime.availableProcessors().intdiv(2) ?: 1
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.esaulpaugh</groupId>
<artifactId>headlong</artifactId>
<version>1.4.3-SNAPSHOT</version>
<version>1.4.4-SNAPSHOT</version>
<packaging>jar</packaging>

<url>http://maven.apache.org</url>
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/esaulpaugh/headlong/abi/ABIType.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public abstract class ABIType<J> implements Serializable {
private String name;

ABIType(String canonicalType, Class<?> clazz, boolean dynamic) {
this.canonicalType = canonicalType;
this.canonicalType = canonicalType; // .intern() to save memory and allow == comparison?
this.clazz = clazz;
this.dynamic = dynamic;
this.name = null;
Expand Down
56 changes: 26 additions & 30 deletions src/main/java/com/esaulpaugh/headlong/abi/ArrayType.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ public final class ArrayType<T extends ABIType<?>, J> extends ABIType<J> {
this.length = length;
this.arrayClassNameStub = arrayClassNameStub;
this.isString = String.class == clazz;
if(isString && length != DYNAMIC_LENGTH) {
throw new IllegalArgumentException("illegal fixed string length");
}
}

public T getElementType() {
Expand Down Expand Up @@ -86,37 +89,37 @@ int typeCode() {
*/
@Override
int byteLength(Object value) {
int staticLen;
int len;
final ABIType<?> elementType = this.elementType;
switch (elementType.typeCode()) {
case TYPE_CODE_BOOLEAN: staticLen = ((boolean[]) value).length << LOG_2_UNIT_LENGTH_BYTES; break;
case TYPE_CODE_BYTE: staticLen =
case TYPE_CODE_BOOLEAN: len = ((boolean[]) value).length << LOG_2_UNIT_LENGTH_BYTES; break;
case TYPE_CODE_BYTE: len =
roundLengthUp(
(isString ? ((String) value).getBytes(CHARSET_UTF_8) : (byte[]) value).length
);
break;
case TYPE_CODE_INT: staticLen = ((int[]) value).length << LOG_2_UNIT_LENGTH_BYTES; break;
case TYPE_CODE_LONG: staticLen = ((long[]) value).length << LOG_2_UNIT_LENGTH_BYTES; break;
case TYPE_CODE_INT: len = ((int[]) value).length << LOG_2_UNIT_LENGTH_BYTES; break;
case TYPE_CODE_LONG: len = ((long[]) value).length << LOG_2_UNIT_LENGTH_BYTES; break;
case TYPE_CODE_BIG_INTEGER:
case TYPE_CODE_BIG_DECIMAL: staticLen = ((Number[]) value).length << LOG_2_UNIT_LENGTH_BYTES; break;
case TYPE_CODE_BIG_DECIMAL: len = ((Number[]) value).length << LOG_2_UNIT_LENGTH_BYTES; break;
case TYPE_CODE_ARRAY:
case TYPE_CODE_TUPLE:
final Object[] elements = (Object[]) value;
final int len = elements.length;
staticLen = 0;
for (int i = 0; i < len; i++) {
staticLen += elementType.byteLength(elements[i]);
final int n = elements.length;
len = 0;
for (int i = 0; i < n; i++) {
len += elementType.byteLength(elements[i]);
}
if(elementType.dynamic) { // implies this.dynamic
// 32 bytes per offset, 32 for array length
return (len << LOG_2_UNIT_LENGTH_BYTES) + ARRAY_LENGTH_BYTE_LEN + staticLen;
len += n << LOG_2_UNIT_LENGTH_BYTES; // 32 bytes per offset
}
return staticLen;
break;
default: throw new IllegalArgumentException("unrecognized type: " + elementType.toString());
}

// dynamics get +32 for the array length
return dynamic ? ARRAY_LENGTH_BYTE_LEN + staticLen : staticLen;
// arrays with variable number of elements get +32 for the array length
return length == DYNAMIC_LENGTH
? ARRAY_LENGTH_BYTE_LEN + len
: len;
}

@Override
Expand Down Expand Up @@ -166,8 +169,10 @@ public int validate(final Object value) {
case TYPE_CODE_TUPLE: staticLen = validateObjectArray((Object[]) value); break;
default: throw new IllegalArgumentException("unrecognized type: " + value.getClass().getName());
}

return dynamic ? ARRAY_LENGTH_BYTE_LEN + staticLen : staticLen;
// arrays with variable number of elements get +32 for the array length
return length == DYNAMIC_LENGTH
? ARRAY_LENGTH_BYTE_LEN + staticLen
: staticLen;
}

private int validateIntArray(int[] arr) {
Expand Down Expand Up @@ -272,18 +277,9 @@ private int checkLength(final int valueLength, Object value) {
@Override
@SuppressWarnings("unchecked")
J decode(ByteBuffer bb, byte[] elementBuffer) {
final int arrayLen;
if(dynamic) {
arrayLen = ARRAY_LENGTH_TYPE.decode(bb, elementBuffer);
final int expectedLen = this.length;
if(expectedLen != DYNAMIC_LENGTH && arrayLen != expectedLen) {
throw new IllegalArgumentException("array length mismatch @ "
+ (bb.position() - ARRAY_LENGTH_BYTE_LEN)
+ ": actual != expected: " + arrayLen + " != " + expectedLen);
}
} else {
arrayLen = length;
}
final int arrayLen = length == DYNAMIC_LENGTH
? ARRAY_LENGTH_TYPE.decode(bb, elementBuffer)
: length;

switch (elementType.typeCode()) {
case TYPE_CODE_BOOLEAN: return (J) decodeBooleanArray(bb, arrayLen, elementBuffer);
Expand Down
16 changes: 9 additions & 7 deletions src/main/java/com/esaulpaugh/headlong/abi/CallEncoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -176,42 +176,42 @@ private static void encodeArrayTail(ArrayType<?, ?> arrayType, Object value, Byt
switch (elementType.typeCode()) {
case TYPE_CODE_BOOLEAN:
boolean[] booleans = (boolean[]) value;
if(arrayType.dynamic) {
if(arrayType.length == ArrayType.DYNAMIC_LENGTH) {
insertInt(booleans.length, dest);
}
insertBooleans(booleans, dest);
return;
case TYPE_CODE_BYTE:
byte[] bytes = (byte[]) value;
if(arrayType.dynamic) {
if(arrayType.length == ArrayType.DYNAMIC_LENGTH) {
insertInt(bytes.length, dest);
}
insertBytes(bytes, dest);
return;
case TYPE_CODE_INT:
int[] ints = (int[]) value;
if(arrayType.dynamic) {
if(arrayType.length == ArrayType.DYNAMIC_LENGTH) {
insertInt(ints.length, dest);
}
insertInts(ints, dest);
return;
case TYPE_CODE_LONG:
long[] longs = (long[]) value;
if(arrayType.dynamic) {
if(arrayType.length == ArrayType.DYNAMIC_LENGTH) {
insertInt(longs.length, dest);
}
insertLongs(longs, dest);
return;
case TYPE_CODE_BIG_INTEGER:
BigInteger[] bigInts = (BigInteger[]) value;
if(arrayType.dynamic) {
if(arrayType.length == ArrayType.DYNAMIC_LENGTH) {
insertInt(bigInts.length, dest);
}
insertBigIntegers(bigInts, dest);
return;
case TYPE_CODE_BIG_DECIMAL:
BigDecimal[] bigDecs = (BigDecimal[]) value;
if(arrayType.dynamic) {
if(arrayType.length == ArrayType.DYNAMIC_LENGTH) {
insertInt(bigDecs.length, dest);
}
insertBigDecimals(bigDecs, dest);
Expand All @@ -221,7 +221,9 @@ private static void encodeArrayTail(ArrayType<?, ?> arrayType, Object value, Byt
final Object[] objects = (Object[]) value;
final int len = objects.length;
if(arrayType.dynamic) {
insertInt(len, dest); // insertLength
if(arrayType.length == ArrayType.DYNAMIC_LENGTH) {
insertInt(len, dest); // insertLength
}
if (elementType.dynamic) { // if elements are dynamic
final int[] offset = new int[] { len << 5 }; // mul 32 (0x20)
for (int i = 0; i < len; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ private static int parseTupleType(final String signature,
TupleType tupleType = TupleType.create(innerList);

// check for suffix i.e. array syntax
if (argEnd < sigEnd && signature.charAt(argEnd) == '[') {
if (argEnd < sigEnd && signature.charAt(argEnd) == '[') { // TODO allow parsing of non-tuple types by end-user
final int nextTerminator = nextParamTerminator(signature, argEnd);
if (nextTerminator > argEnd) {
String suffix = signature.substring(argEnd, nextTerminator); // e.g. "[4][]"
Expand Down
41 changes: 25 additions & 16 deletions src/test/java/com/esaulpaugh/headlong/abi/ABIJsonTest2.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,14 @@ private static class TestCase {

private static final Integers.UintType ADDRESS = new Integers.UintType(160);

private final String name;

private final TupleType types;
private final Tuple values;
private final byte[] result;

public TestCase(JsonObject object) throws ParseException {
this.name = object.get("name").getAsString();
String typesStr = object.get("types").getAsString();
String valuesStr = object.get("values").getAsString();
String resultStr = object.get("result").getAsString();
Expand All @@ -69,9 +72,18 @@ private boolean test() {
Assert.assertArrayEquals(result, encoding);
return true;
} catch (AssertionError ae) {
// System.out.println(types.canonicalType);
// System.out.println(format(result) + "\n");
// System.out.println(format(encoding));
String[] resultTokens = format(result).split("[\n]");
String[] encodingTokens = format(encoding).split("[\n]");
System.out.println(types.canonicalType);
int i = 0;
for ( ; i < resultTokens.length; i++) {
String r = resultTokens[i];
String e = encodingTokens[i];
System.out.println(r + " " + e + " " + (r.equals(e) ? "" : "**************"));
}
for ( ; i < encodingTokens.length; i++) {
System.out.println("----------------------------------------------------------------" + " " + encodingTokens[i]);
}
return false;
}
}
Expand All @@ -80,10 +92,7 @@ private static String format(byte[] abi) {
StringBuilder sb = new StringBuilder();
int idx = 0;
while(idx < abi.length) {
sb // .append(idx >>> UnitType.LOG_2_UNIT_LENGTH_BYTES)
// .append('\t')
.append(encode(Arrays.copyOfRange(abi, idx, idx + UNIT_LENGTH_BYTES), HEX))
.append('\n');
sb.append(encode(Arrays.copyOfRange(abi, idx, idx + UNIT_LENGTH_BYTES), HEX)).append('\n');
idx += UNIT_LENGTH_BYTES;
}
return sb.toString();
Expand Down Expand Up @@ -114,15 +123,12 @@ private static Object parseValue(ABIType<?> type, JsonElement value) {
return new BigDecimal(new BigInteger(valueValue), 18);
}
case ABIType.TYPE_CODE_ARRAY: return parseArray((ArrayType<?, ?>) type, value);
case ABIType.TYPE_CODE_TUPLE: {
return parseTuple((TupleType) type, value.getAsJsonObject().get("value").getAsJsonArray());
}
case ABIType.TYPE_CODE_TUPLE: return parseTuple((TupleType) type, value.getAsJsonObject().get("value").getAsJsonArray());
default: throw new Error();
}
}

private static Object parseArray(ArrayType<?, ?> arrayType, JsonElement value) {
// System.out.println("____ " + arrayType.canonicalType);
if (arrayType.isString) {
return value.getAsJsonObject().get("value").getAsString();
} else if (value.isJsonArray()) {
Expand Down Expand Up @@ -195,15 +201,18 @@ private static String completeTupleTypeString(StringBuilder canonicalTupleType)

@Test
public void testMegaJson() throws ParseException {
// int i = 0;
int i = 0;
int failed = 0;
for (JsonElement e : TEST_CASES) {
// System.out.println(i);
if(!new TestCase(e.getAsJsonObject()).test()) {
TestCase t = new TestCase(e.getAsJsonObject());
if(!t.test()) {
System.out.println("failure @ " + i + " " + t.name);
failed++;
} else {
System.out.println("success @ " + i);
}
// i++;
i++;
}
System.out.println("failed = " + failed);
System.out.println("failed = " + failed + "/" + i);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
]
}
],
"result": "0000000000000000000000000000000000000000000000000000000005d94e83000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000063078666631310000000000000000000000000000000000000000000000000000",
"result": "0000000000000000000000000000000000000000000000000000000005d94e8300000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000063078666631310000000000000000000000000000000000000000000000000000",
"types": [
"uint256",
"(uint8[])[2][][1]",
Expand Down

0 comments on commit 9535639

Please sign in to comment.