Skip to content
This repository has been archived by the owner on Dec 5, 2024. It is now read-only.

Fix ABI code for multidimensional arrays #1239

Merged
merged 6 commits into from
Dec 3, 2018
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 53 additions & 92 deletions ethereumj-core/src/main/java/org/ethereum/solidity/SolidityType.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public String getCanonicalName() {

@JsonCreator
public static SolidityType getType(String typeName) {
if (typeName.contains("[")) return ArrayType.getType(typeName);
if (typeName.endsWith("]")) return ArrayType.getType(typeName);
if ("bool".equals(typeName)) return new BoolType();
if (typeName.startsWith("int")) return new IntType(typeName);
if (typeName.startsWith("uint")) return new UnsignedIntType(typeName);
Expand Down Expand Up @@ -101,8 +101,8 @@ public String toString() {

public static abstract class ArrayType extends SolidityType {
public static ArrayType getType(String typeName) {
int idx1 = typeName.indexOf("[");
int idx2 = typeName.indexOf("]", idx1);
int idx1 = typeName.lastIndexOf("[");
int idx2 = typeName.lastIndexOf("]");
if (idx1 + 1 == idx2) {
return new DynamicArrayType(typeName);
} else {
Expand All @@ -114,11 +114,7 @@ public static ArrayType getType(String typeName) {

public ArrayType(String name) {
super(name);
int idx = name.indexOf("[");
String st = name.substring(0, idx);
int idx2 = name.indexOf("]", idx);
String subDim = idx2 + 1 == name.length() ? "" : name.substring(idx2 + 1);
elementType = SolidityType.getType(st + subDim);
elementType = SolidityType.getType(name.substring(0, name.lastIndexOf("[")));
}

@Override
Expand All @@ -135,23 +131,42 @@ public byte[] encode(Object value) {
throw new RuntimeException("List value expected for type " + getName());
}
}

@Override
public String getCanonicalName() {
return getArrayCanonicalName("");
}

String getArrayCanonicalName(String parentDimStr) {
String myDimStr = parentDimStr + getCanonicalDimension();
if (getElementType() instanceof ArrayType) {
return ((ArrayType) getElementType()).
getArrayCanonicalName(myDimStr);
protected byte[] encodeTuple(List l) {
byte[][] elems;
if (elementType.isDynamicType()) {
elems = new byte[l.size() * 2][];
int offset = l.size() * 32;
for (int i = 0; i < l.size(); i++) {
elems[i] = IntType.encodeInt(offset);
byte[] encoded = elementType.encode(l.get(i));
elems[l.size() + i] = encoded;
offset += 32 * ((encoded.length - 1) / 32 + 1);
}
} else {
return getElementType().getCanonicalName() + myDimStr;
elems = new byte[l.size()][];
for (int i = 0; i < l.size(); i++) {
elems[i] = elementType.encode(l.get(i));
}
}
return ByteUtil.merge(elems);
}

public Object[] decodeTuple(byte[] encoded, int origOffset, int len) {
int offset = origOffset;
Object[] ret = new Object[len];

for (int i = 0; i < len; i++) {
if (elementType.isDynamicType()) {
ret[i] = elementType.decode(encoded, origOffset + IntType.decodeInt(encoded, offset).intValue());
} else {
ret[i] = elementType.decode(encoded, offset);
}
offset += elementType.getFixedSize();
}
return ret;
}

protected abstract String getCanonicalDimension();

public SolidityType getElementType() {
return elementType;
Expand All @@ -165,52 +180,40 @@ public static class StaticArrayType extends ArrayType {

public StaticArrayType(String name) {
super(name);
int idx1 = name.indexOf("[");
int idx2 = name.indexOf("]", idx1);
int idx1 = name.lastIndexOf("[");
int idx2 = name.lastIndexOf("]");
String dim = name.substring(idx1 + 1, idx2);
size = Integer.parseInt(dim);
}

@Override
public String getCanonicalName() {
if (elementType instanceof ArrayType) {
String elementTypeName = elementType.getCanonicalName();
int idx1 = elementTypeName.indexOf("[");
return elementTypeName.substring(0, idx1) + "[" + size + "]" + elementTypeName.substring(idx1);
} else {
return elementType.getCanonicalName() + "[" + size + "]";
}
}

@Override
protected String getCanonicalDimension() {
return "[" + size + "]";
return getElementType().getCanonicalName() + "[" + size + "]";
}

@Override
public byte[] encodeList(List l) {
if (l.size() != size) throw new RuntimeException("List size (" + l.size() + ") != " + size + " for type " + getName());
byte[][] elems = new byte[size][];
for (int i = 0; i < l.size(); i++) {
elems[i] = elementType.encode(l.get(i));
}
return ByteUtil.merge(elems);
return encodeTuple(l);
}

@Override
public Object[] decode(byte[] encoded, int offset) {
Object[] result = new Object[size];
for (int i = 0; i < size; i++) {
result[i] = elementType.decode(encoded, offset + i * elementType.getFixedSize());
}

return result;
return decodeTuple(encoded, offset, size);
}

@Override
public int getFixedSize() {
// return negative if elementType is dynamic
return elementType.getFixedSize() * size;
if (isDynamicType()) {
return 32;
Nashatyrev marked this conversation as resolved.
Show resolved Hide resolved
} else {
return elementType.getFixedSize() * size;
}
}

@Override
public boolean isDynamicType() {
return getElementType().isDynamicType() && size > 0;
}
}

Expand All @@ -221,60 +224,18 @@ public DynamicArrayType(String name) {

@Override
public String getCanonicalName() {
if (elementType instanceof ArrayType) {
String elementTypeName = elementType.getCanonicalName();
int idx1 = elementTypeName.indexOf("[");
return elementTypeName.substring(0, idx1) + "[]" + elementTypeName.substring(idx1);
} else {
return elementType.getCanonicalName() + "[]";
}
}

@Override
protected String getCanonicalDimension() {
return "[]";
return elementType.getCanonicalName() + "[]";
}

@Override
public byte[] encodeList(List l) {
byte[][] elems;
if (elementType.isDynamicType()) {
elems = new byte[l.size() * 2 + 1][];
elems[0] = IntType.encodeInt(l.size());
int offset = l.size() * 32;
for (int i = 0; i < l.size(); i++) {
elems[i + 1] = IntType.encodeInt(offset);
byte[] encoded = elementType.encode(l.get(i));
elems[l.size() + i + 1] = encoded;
offset += 32 * ((encoded.length - 1) / 32 + 1);
}
} else {
elems = new byte[l.size() + 1][];
elems[0] = IntType.encodeInt(l.size());

for (int i = 0; i < l.size(); i++) {
elems[i + 1] = elementType.encode(l.get(i));
}
}
return ByteUtil.merge(elems);
return ByteUtil.merge(IntType.encodeInt(l.size()), encodeTuple(l));
}

@Override
public Object decode(byte[] encoded, int origOffset) {
int len = IntType.decodeInt(encoded, origOffset).intValue();
origOffset += 32;
int offset = origOffset;
Object[] ret = new Object[len];

for (int i = 0; i < len; i++) {
if (elementType.isDynamicType()) {
ret[i] = elementType.decode(encoded, origOffset + IntType.decodeInt(encoded, offset).intValue());
} else {
ret[i] = elementType.decode(encoded, offset);
}
offset += elementType.getFixedSize();
}
return ret;
return decodeTuple(encoded, origOffset + 32, len);
}

@Override
Expand Down
Loading