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

Commit c8177a3

Browse files
authored
Merge pull request #1239 from ethereum/fix/abi-mutidim
Fix ABI code for multidimensional arrays
2 parents 5c796de + 037747a commit c8177a3

File tree

2 files changed

+305
-126
lines changed

2 files changed

+305
-126
lines changed

ethereumj-core/src/main/java/org/ethereum/solidity/SolidityType.java

Lines changed: 65 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import static org.ethereum.util.ByteUtil.toHexString;
3333

3434
public abstract class SolidityType {
35+
private final static int Int32Size = 32;
3536
protected String name;
3637

3738
public SolidityType(String name) {
@@ -56,7 +57,7 @@ public String getCanonicalName() {
5657

5758
@JsonCreator
5859
public static SolidityType getType(String typeName) {
59-
if (typeName.contains("[")) return ArrayType.getType(typeName);
60+
if (typeName.endsWith("]")) return ArrayType.getType(typeName);
6061
if ("bool".equals(typeName)) return new BoolType();
6162
if (typeName.startsWith("int")) return new IntType(typeName);
6263
if (typeName.startsWith("uint")) return new UnsignedIntType(typeName);
@@ -86,7 +87,7 @@ public Object decode(byte[] encoded) {
8687
* which is effectively the int offset to dynamic data
8788
*/
8889
public int getFixedSize() {
89-
return 32;
90+
return Int32Size;
9091
}
9192

9293
public boolean isDynamicType() {
@@ -101,8 +102,8 @@ public String toString() {
101102

102103
public static abstract class ArrayType extends SolidityType {
103104
public static ArrayType getType(String typeName) {
104-
int idx1 = typeName.indexOf("[");
105-
int idx2 = typeName.indexOf("]", idx1);
105+
int idx1 = typeName.lastIndexOf("[");
106+
int idx2 = typeName.lastIndexOf("]");
106107
if (idx1 + 1 == idx2) {
107108
return new DynamicArrayType(typeName);
108109
} else {
@@ -114,11 +115,7 @@ public static ArrayType getType(String typeName) {
114115

115116
public ArrayType(String name) {
116117
super(name);
117-
int idx = name.indexOf("[");
118-
String st = name.substring(0, idx);
119-
int idx2 = name.indexOf("]", idx);
120-
String subDim = idx2 + 1 == name.length() ? "" : name.substring(idx2 + 1);
121-
elementType = SolidityType.getType(st + subDim);
118+
elementType = SolidityType.getType(name.substring(0, name.lastIndexOf("[")));
122119
}
123120

124121
@Override
@@ -135,23 +132,42 @@ public byte[] encode(Object value) {
135132
throw new RuntimeException("List value expected for type " + getName());
136133
}
137134
}
138-
139-
@Override
140-
public String getCanonicalName() {
141-
return getArrayCanonicalName("");
142-
}
143135

144-
String getArrayCanonicalName(String parentDimStr) {
145-
String myDimStr = parentDimStr + getCanonicalDimension();
146-
if (getElementType() instanceof ArrayType) {
147-
return ((ArrayType) getElementType()).
148-
getArrayCanonicalName(myDimStr);
136+
protected byte[] encodeTuple(List l) {
137+
byte[][] elems;
138+
if (elementType.isDynamicType()) {
139+
elems = new byte[l.size() * 2][];
140+
int offset = l.size() * Int32Size;
141+
for (int i = 0; i < l.size(); i++) {
142+
elems[i] = IntType.encodeInt(offset);
143+
byte[] encoded = elementType.encode(l.get(i));
144+
elems[l.size() + i] = encoded;
145+
offset += Int32Size * ((encoded.length - 1) / Int32Size + 1);
146+
}
149147
} else {
150-
return getElementType().getCanonicalName() + myDimStr;
148+
elems = new byte[l.size()][];
149+
for (int i = 0; i < l.size(); i++) {
150+
elems[i] = elementType.encode(l.get(i));
151+
}
151152
}
153+
return ByteUtil.merge(elems);
154+
}
155+
156+
public Object[] decodeTuple(byte[] encoded, int origOffset, int len) {
157+
int offset = origOffset;
158+
Object[] ret = new Object[len];
159+
160+
for (int i = 0; i < len; i++) {
161+
if (elementType.isDynamicType()) {
162+
ret[i] = elementType.decode(encoded, origOffset + IntType.decodeInt(encoded, offset).intValue());
163+
} else {
164+
ret[i] = elementType.decode(encoded, offset);
165+
}
166+
offset += elementType.getFixedSize();
167+
}
168+
return ret;
152169
}
153170

154-
protected abstract String getCanonicalDimension();
155171

156172
public SolidityType getElementType() {
157173
return elementType;
@@ -165,52 +181,40 @@ public static class StaticArrayType extends ArrayType {
165181

166182
public StaticArrayType(String name) {
167183
super(name);
168-
int idx1 = name.indexOf("[");
169-
int idx2 = name.indexOf("]", idx1);
184+
int idx1 = name.lastIndexOf("[");
185+
int idx2 = name.lastIndexOf("]");
170186
String dim = name.substring(idx1 + 1, idx2);
171187
size = Integer.parseInt(dim);
172188
}
173189

174190
@Override
175191
public String getCanonicalName() {
176-
if (elementType instanceof ArrayType) {
177-
String elementTypeName = elementType.getCanonicalName();
178-
int idx1 = elementTypeName.indexOf("[");
179-
return elementTypeName.substring(0, idx1) + "[" + size + "]" + elementTypeName.substring(idx1);
180-
} else {
181-
return elementType.getCanonicalName() + "[" + size + "]";
182-
}
183-
}
184-
185-
@Override
186-
protected String getCanonicalDimension() {
187-
return "[" + size + "]";
192+
return getElementType().getCanonicalName() + "[" + size + "]";
188193
}
189194

190195
@Override
191196
public byte[] encodeList(List l) {
192197
if (l.size() != size) throw new RuntimeException("List size (" + l.size() + ") != " + size + " for type " + getName());
193-
byte[][] elems = new byte[size][];
194-
for (int i = 0; i < l.size(); i++) {
195-
elems[i] = elementType.encode(l.get(i));
196-
}
197-
return ByteUtil.merge(elems);
198+
return encodeTuple(l);
198199
}
199200

200201
@Override
201202
public Object[] decode(byte[] encoded, int offset) {
202-
Object[] result = new Object[size];
203-
for (int i = 0; i < size; i++) {
204-
result[i] = elementType.decode(encoded, offset + i * elementType.getFixedSize());
205-
}
206-
207-
return result;
203+
return decodeTuple(encoded, offset, size);
208204
}
209205

210206
@Override
211207
public int getFixedSize() {
212-
// return negative if elementType is dynamic
213-
return elementType.getFixedSize() * size;
208+
if (isDynamicType()) {
209+
return Int32Size;
210+
} else {
211+
return elementType.getFixedSize() * size;
212+
}
213+
}
214+
215+
@Override
216+
public boolean isDynamicType() {
217+
return getElementType().isDynamicType() && size > 0;
214218
}
215219
}
216220

@@ -221,60 +225,18 @@ public DynamicArrayType(String name) {
221225

222226
@Override
223227
public String getCanonicalName() {
224-
if (elementType instanceof ArrayType) {
225-
String elementTypeName = elementType.getCanonicalName();
226-
int idx1 = elementTypeName.indexOf("[");
227-
return elementTypeName.substring(0, idx1) + "[]" + elementTypeName.substring(idx1);
228-
} else {
229-
return elementType.getCanonicalName() + "[]";
230-
}
231-
}
232-
233-
@Override
234-
protected String getCanonicalDimension() {
235-
return "[]";
228+
return elementType.getCanonicalName() + "[]";
236229
}
237230

238231
@Override
239232
public byte[] encodeList(List l) {
240-
byte[][] elems;
241-
if (elementType.isDynamicType()) {
242-
elems = new byte[l.size() * 2 + 1][];
243-
elems[0] = IntType.encodeInt(l.size());
244-
int offset = l.size() * 32;
245-
for (int i = 0; i < l.size(); i++) {
246-
elems[i + 1] = IntType.encodeInt(offset);
247-
byte[] encoded = elementType.encode(l.get(i));
248-
elems[l.size() + i + 1] = encoded;
249-
offset += 32 * ((encoded.length - 1) / 32 + 1);
250-
}
251-
} else {
252-
elems = new byte[l.size() + 1][];
253-
elems[0] = IntType.encodeInt(l.size());
254-
255-
for (int i = 0; i < l.size(); i++) {
256-
elems[i + 1] = elementType.encode(l.get(i));
257-
}
258-
}
259-
return ByteUtil.merge(elems);
233+
return ByteUtil.merge(IntType.encodeInt(l.size()), encodeTuple(l));
260234
}
261235

262236
@Override
263237
public Object decode(byte[] encoded, int origOffset) {
264238
int len = IntType.decodeInt(encoded, origOffset).intValue();
265-
origOffset += 32;
266-
int offset = origOffset;
267-
Object[] ret = new Object[len];
268-
269-
for (int i = 0; i < len; i++) {
270-
if (elementType.isDynamicType()) {
271-
ret[i] = elementType.decode(encoded, origOffset + IntType.decodeInt(encoded, offset).intValue());
272-
} else {
273-
ret[i] = elementType.decode(encoded, offset);
274-
}
275-
offset += elementType.getFixedSize();
276-
}
277-
return ret;
239+
return decodeTuple(encoded, origOffset + Int32Size, len);
278240
}
279241

280242
@Override
@@ -302,7 +264,7 @@ public byte[] encode(Object value) {
302264
} else {
303265
throw new RuntimeException("byte[] or String value is expected for type 'bytes'");
304266
}
305-
byte[] ret = new byte[((bb.length - 1) / 32 + 1) * 32]; // padding 32 bytes
267+
byte[] ret = new byte[((bb.length - 1) / Int32Size + 1) * Int32Size]; // padding 32 bytes
306268
System.arraycopy(bb, 0, ret, 0, bb.length);
307269

308270
return ByteUtil.merge(IntType.encodeInt(bb.length), ret);
@@ -312,7 +274,7 @@ public byte[] encode(Object value) {
312274
public Object decode(byte[] encoded, int offset) {
313275
int len = IntType.decodeInt(encoded, offset).intValue();
314276
if (len == 0) return new byte[0];
315-
offset += 32;
277+
offset += Int32Size;
316278
return Arrays.copyOfRange(encoded, offset, offset + len);
317279
}
318280

@@ -350,14 +312,14 @@ public byte[] encode(Object value) {
350312
BigInteger bigInt = new BigInteger(value.toString());
351313
return IntType.encodeInt(bigInt);
352314
} else if (value instanceof String) {
353-
byte[] ret = new byte[32];
315+
byte[] ret = new byte[Int32Size];
354316
byte[] bytes = ((String) value).getBytes(StandardCharsets.UTF_8);
355317
System.arraycopy(bytes, 0, ret, 0, bytes.length);
356318
return ret;
357319
} else if (value instanceof byte[]) {
358320
byte[] bytes = (byte[]) value;
359-
byte[] ret = new byte[32];
360-
System.arraycopy(bytes, 0, ret, 32 - bytes.length, bytes.length);
321+
byte[] ret = new byte[Int32Size];
322+
System.arraycopy(bytes, 0, ret, Int32Size - bytes.length, bytes.length);
361323
return ret;
362324
}
363325

@@ -370,7 +332,7 @@ public Object decode(byte[] encoded, int offset) {
370332
}
371333

372334
public static byte[] decodeBytes32(byte[] encoded, int offset) {
373-
return Arrays.copyOfRange(encoded, offset, offset + 32);
335+
return Arrays.copyOfRange(encoded, offset, offset + Int32Size);
374336
}
375337
}
376338

@@ -443,13 +405,13 @@ public String getCanonicalName() {
443405
return super.getCanonicalName();
444406
}
445407
public static BigInteger decodeInt(byte[] encoded, int offset) {
446-
return new BigInteger(Arrays.copyOfRange(encoded, offset, offset + 32));
408+
return new BigInteger(Arrays.copyOfRange(encoded, offset, offset + Int32Size));
447409
}
448410
public static byte[] encodeInt(int i) {
449411
return encodeInt(new BigInteger("" + i));
450412
}
451413
public static byte[] encodeInt(BigInteger bigInt) {
452-
return ByteUtil.bigIntegerToBytesSigned(bigInt, 32);
414+
return ByteUtil.bigIntegerToBytesSigned(bigInt, Int32Size);
453415
}
454416
@Override
455417
public Object decode(byte[] encoded, int offset) {
@@ -473,7 +435,7 @@ public String getCanonicalName() {
473435
return super.getCanonicalName();
474436
}
475437
public static BigInteger decodeInt(byte[] encoded, int offset) {
476-
return new BigInteger(1, Arrays.copyOfRange(encoded, offset, offset + 32));
438+
return new BigInteger(1, Arrays.copyOfRange(encoded, offset, offset + Int32Size));
477439
}
478440
public static byte[] encodeInt(int i) {
479441
return encodeInt(new BigInteger("" + i));
@@ -482,7 +444,7 @@ public static byte[] encodeInt(BigInteger bigInt) {
482444
if (bigInt.signum() == -1) {
483445
throw new RuntimeException("Wrong value for uint type: " + bigInt);
484446
}
485-
return ByteUtil.bigIntegerToBytes(bigInt, 32);
447+
return ByteUtil.bigIntegerToBytes(bigInt, Int32Size);
486448
}
487449
@Override
488450
public byte[] encode(Object value) {

0 commit comments

Comments
 (0)