Skip to content

Commit

Permalink
perf: improve decoding in CallTransaction
Browse files Browse the repository at this point in the history
  • Loading branch information
Vovchyk committed Jul 26, 2024
1 parent 2eccc84 commit 1267e76
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 54 deletions.
22 changes: 12 additions & 10 deletions rskj-core/src/main/java/org/ethereum/core/CallTransaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
package org.ethereum.core;

import co.rsk.core.RskAddress;
import co.rsk.core.types.bytes.Bytes;
import co.rsk.core.types.bytes.BytesSlice;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonInclude;
Expand Down Expand Up @@ -119,9 +121,9 @@ public static Type getType(String typeName) {
*/
public abstract byte[] encode(Object value);

public abstract Object decode(byte[] encoded, int offset);
public abstract Object decode(BytesSlice encoded, int offset);

public Object decode(byte[] encoded) {
public Object decode(BytesSlice encoded) {
return decode(encoded, 0);
}

Expand Down Expand Up @@ -187,12 +189,12 @@ public byte[] encode(Object value) {
}

@Override
public Object decode(byte[] encoded, int offset) {
public Object decode(BytesSlice encoded, int offset) {
return decodeInt(encoded, offset);
}

public static BigInteger decodeInt(byte[] encoded, int offset) {
return new BigInteger(Arrays.copyOfRange(encoded, offset, offset + 32));
public static BigInteger decodeInt(BytesSlice encoded, int offset) {
return new BigInteger(encoded.copyArrayOfRange(offset, offset + 32));
}

public static byte[] encodeInt(int i) {
Expand Down Expand Up @@ -222,7 +224,7 @@ public byte[] encode(Object value) {
}

@Override
public Object decode(byte[] encoded, int offset) {
public Object decode(BytesSlice encoded, int offset) {
return Boolean.valueOf(((Number) super.decode(encoded, offset)).intValue() != 0);
}
}
Expand Down Expand Up @@ -350,7 +352,7 @@ public Object[] decodeEventData(byte[] encodedData) {
checkFunctionType(FunctionType.event);
Param[] dataInputs = Arrays.stream(inputs).filter(i -> !i.indexed).toArray(Param[]::new);

return decode(encodedData, dataInputs);
return decode(Bytes.of(encodedData), dataInputs);
}

private void checkFunctionType(FunctionType expected) {
Expand Down Expand Up @@ -405,7 +407,7 @@ public byte[] encodeOutputs(Object... args) {
return encodeArguments(outputs, args);
}

private Object[] decode(byte[] encoded, Param[] params) {
private Object[] decode(BytesSlice encoded, Param[] params) {
Object[] ret = new Object[params.length];

int off = 0;
Expand All @@ -421,11 +423,11 @@ private Object[] decode(byte[] encoded, Param[] params) {
}

public Object[] decode(byte[] encoded) {
return decode(subarray(encoded, 4, encoded.length), inputs);
return decode(Bytes.of(encoded).slice(4, encoded.length), inputs);
}

public Object[] decodeResult(byte[] encodedRet) {
return decode(encodedRet, outputs);
return decode(Bytes.of(encodedRet), outputs);
}

public String formatSignature() {
Expand Down
27 changes: 14 additions & 13 deletions rskj-core/src/main/java/org/ethereum/solidity/SolidityType.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package org.ethereum.solidity;

import co.rsk.core.types.bytes.Bytes;
import co.rsk.core.types.bytes.BytesSlice;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import org.ethereum.util.ByteUtil;
Expand Down Expand Up @@ -101,9 +102,9 @@ public static SolidityType getType(String typeName) {
*/
public abstract byte[] encode(Object value);

public abstract Object decode(byte[] encoded, int offset);
public abstract Object decode(BytesSlice encoded, int offset);

public Object decode(byte[] encoded) {
public Object decode(BytesSlice encoded) {
return decode(encoded, 0);
}

Expand Down Expand Up @@ -196,7 +197,7 @@ public byte[] encodeList(List l) {
}

@Override
public Object[] decode(byte[] encoded, int offset) {
public Object[] decode(BytesSlice encoded, int offset) {
Utils.validateArrayAllegedSize(encoded, offset, getFixedSize());
Object[] result = new Object[size];
for (int i = 0; i < size; i++) {
Expand Down Expand Up @@ -247,8 +248,8 @@ public byte[] encodeList(List l) {
}

@Override
public Object decode(byte[] encoded, int origOffset) {
if (encoded.length == 0) {
public Object decode(BytesSlice encoded, int origOffset) {
if (encoded.length() == 0) {
return new Object[0];
}
int len = IntType.decodeInt(encoded, origOffset).intValue();
Expand Down Expand Up @@ -299,7 +300,7 @@ public byte[] encode(Object value) {
}

@Override
public Object decode(byte[] encoded, int offset) {
public Object decode(BytesSlice encoded, int offset) {
int len = IntType.decodeInt(encoded, offset).intValue();
offset += IntType.INT_SIZE;
return Utils.safeCopyOfRange(encoded, offset, len);
Expand All @@ -325,7 +326,7 @@ public byte[] encode(Object value) {
}

@Override
public Object decode(byte[] encoded, int offset) {
public Object decode(BytesSlice encoded, int offset) {
return new String((byte[]) super.decode(encoded, offset), StandardCharsets.UTF_8);
}
}
Expand Down Expand Up @@ -357,7 +358,7 @@ public byte[] encode(Object value) {
}

@Override
public Object decode(byte[] encoded, int offset) {
public Object decode(BytesSlice encoded, int offset) {
return Utils.safeCopyOfRange(encoded, offset, getFixedSize());
}
}
Expand All @@ -383,7 +384,7 @@ public byte[] encode(Object value) {
}

@Override
public Object decode(byte[] encoded, int offset) {
public Object decode(BytesSlice encoded, int offset) {
BigInteger asBigInteger = (BigInteger) super.decode(encoded, offset);
return DataWord.valueOf(asBigInteger.toByteArray());
}
Expand Down Expand Up @@ -434,14 +435,14 @@ public byte[] encode(Object value) {
}

@Override
public Object decode(byte[] encoded, int offset) {
public Object decode(BytesSlice encoded, int offset) {
return decodeInt(encoded, offset);
}

public static BigInteger decodeInt(byte[] encoded, int offset) {
public static BigInteger decodeInt(BytesSlice encoded, int offset) {
// This is here because getGasForData might send an empty payload which will produce an exception
// But currently the bridge would return the cost of RELEASE_BTC in this situation
if (encoded.length == 0) {
if (encoded.length() == 0) {
return BigInteger.ZERO;
}
return new BigInteger(Utils.safeCopyOfRange(encoded, offset, INT_SIZE));
Expand Down Expand Up @@ -474,7 +475,7 @@ public byte[] encode(Object value) {
}

@Override
public Object decode(byte[] encoded, int offset) {
public Object decode(BytesSlice encoded, int offset) {
return Boolean.valueOf(((Number) super.decode(encoded, offset)).intValue() != 0);
}
}
Expand Down
9 changes: 5 additions & 4 deletions rskj-core/src/main/java/org/ethereum/util/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

package org.ethereum.util;

import co.rsk.core.types.bytes.BytesSlice;
import org.bouncycastle.util.encoders.DecoderException;
import org.bouncycastle.util.encoders.Hex;
import java.lang.reflect.Array;
Expand Down Expand Up @@ -206,15 +207,15 @@ public static boolean contains(List<byte[]> list, byte[] valueToFind) {
return false;
}

public static void validateArrayAllegedSize(byte[] data, int offset, int allegedSize) {
if (data.length < Math.addExact(allegedSize, offset)) {
public static void validateArrayAllegedSize(BytesSlice data, int offset, int allegedSize) {
if (data.length() < Math.addExact(allegedSize, offset)) {
throw new IllegalArgumentException("The specified size exceeds the size of the payload");
}
}

public static byte[] safeCopyOfRange(byte[] data, int from, int size) {
public static byte[] safeCopyOfRange(BytesSlice data, int from, int size) {
validateArrayAllegedSize(data, from, size);
return Arrays.copyOfRange(data, from, from + size);
return data.copyArrayOfRange(from, from + size);
}

public static boolean isDecimalString(String s) {
Expand Down
3 changes: 2 additions & 1 deletion rskj-core/src/test/java/co/rsk/core/CallTransactionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package co.rsk.core;

import co.rsk.core.types.bytes.Bytes;
import org.bouncycastle.util.encoders.Hex;
import org.ethereum.core.CallTransaction;
import org.ethereum.solidity.SolidityType;
Expand Down Expand Up @@ -115,7 +116,7 @@ void decodeString() {
// string
104, 101, 108, 108, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

Assertions.assertEquals("hello", type.decode(toDecode));
Assertions.assertEquals("hello", type.decode(Bytes.of(toDecode)));
}

@Test
Expand Down
3 changes: 2 additions & 1 deletion rskj-core/src/test/java/co/rsk/core/TransactionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package co.rsk.core;

import co.rsk.config.TestSystemProperties;
import co.rsk.core.types.bytes.Bytes;
import co.rsk.peg.BridgeSupportFactory;
import co.rsk.peg.RepositoryBtcBlockStoreWithCache;
import org.bouncycastle.util.BigIntegers;
Expand Down Expand Up @@ -283,7 +284,7 @@ protected ProgramResult executeTransaction(Transaction tx) {

track.rollback();

System.out.println("Return value: " + new CallTransaction.IntType("uint").decode(executor.getResult().getHReturn()));
System.out.println("Return value: " + new CallTransaction.IntType("uint").decode(Bytes.of(executor.getResult().getHReturn())));
}

// now executing the JSON test transaction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import co.rsk.core.RskAddress;
import co.rsk.core.TransactionExecutorFactory;
import co.rsk.core.genesis.TestGenesisLoader;
import co.rsk.core.types.bytes.Bytes;
import co.rsk.crypto.Keccak256;
import co.rsk.db.HashMapBlocksIndex;
import co.rsk.db.MutableTrieImpl;
Expand Down Expand Up @@ -508,7 +509,7 @@ protected ProgramResult executeTransaction(Transaction tx) {

track.rollback();

System.out.println("Return value: " + new CallTransaction.IntType("uint").decode(executor.getResult().getHReturn()));
System.out.println("Return value: " + new CallTransaction.IntType("uint").decode(Bytes.of(executor.getResult().getHReturn())));
}

// now executing the JSON test transaction
Expand Down
21 changes: 11 additions & 10 deletions rskj-core/src/test/java/org/ethereum/solidity/SolidityTypeTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.ethereum.solidity;

import co.rsk.core.types.bytes.Bytes;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

Expand All @@ -16,7 +17,7 @@ void TestDynamicArrayTypeWithInvalidDataSize() {
input[31] = 0x10; // Indicating we should have 16 elements in the array should fail

try {
dat.decode(input, 0);
dat.decode(Bytes.of(input), 0);
Assertions.fail();
} catch (IllegalArgumentException e) {
// Only acceptable exception
Expand All @@ -35,7 +36,7 @@ void TestDynamicArrayTypeWithInvalidDataSize() {
input[97] = 0x69;

try {
dat.decode(input, 0);
dat.decode(Bytes.of(input), 0);
Assertions.fail();
} catch (IllegalArgumentException e) {
// Only acceptable exception
Expand All @@ -60,7 +61,7 @@ void TestDynamicArrayTypeWithInvalidDataSize() {
input[163] = 0x69;

try {
dat.decode(input, 0);
dat.decode(Bytes.of(input), 0);
Assertions.fail();
} catch (IllegalArgumentException e) {
// Only acceptable exception
Expand Down Expand Up @@ -96,7 +97,7 @@ void TestDynamicArrayTypeWithValidDataSize() {
input[229] = 0x68;
input[230] = 0x75;

Object[] ret = (Object[])dat.decode(input, 0);
Object[] ret = (Object[])dat.decode(Bytes.of(input), 0);
Assertions.assertEquals(3, ret.length);
Assertions.assertTrue(ret[0].toString().contains("hi"));
Assertions.assertTrue(ret[1].toString().contains("ih"));
Expand All @@ -114,7 +115,7 @@ void TestStaticArrayTypeWithInvalidSize() {
// the actual data
input[32] = 0x68;
input[33] = 0x69;
dat.decode(input, 0);
dat.decode(Bytes.of(input), 0);
Assertions.fail("should have failed");
}
catch (IllegalArgumentException e) {
Expand All @@ -130,7 +131,7 @@ void TestStaticArrayTypeWithInvalidSize() {
// the actual data
input[32] = 0x68;
input[33] = 0x69;
dat.decode(input, 0);
dat.decode(Bytes.of(input), 0);
Assertions.fail("should have failed");
}
catch (IllegalArgumentException e) {
Expand All @@ -149,7 +150,7 @@ void TestStaticArrayType() {
input[32] = 0x68;
input[33] = 0x69;

Object[] ret = dat.decode(input, 0);
Object[] ret = dat.decode(Bytes.of(input), 0);
Assertions.assertEquals(1, ret.length);
Assertions.assertTrue(ret[0].toString().contains("hi"));
}
Expand All @@ -159,7 +160,7 @@ void TestIntType() {
// Should fail, the array is smaller than the offset we define
try {
byte[] input = new byte[] {0x4f, 0x4f};
SolidityType.IntType.decodeInt(input, 12);
SolidityType.IntType.decodeInt(Bytes.of(input), 12);
Assertions.fail("should have failed to deserialize the array");
} catch (IllegalArgumentException e) {
// Only acceptable exception
Expand All @@ -168,11 +169,11 @@ void TestIntType() {

// Should get a valid number
input[31] = 0x01;
BigInteger value = SolidityType.IntType.decodeInt(input, 0);
BigInteger value = SolidityType.IntType.decodeInt(Bytes.of(input), 0);
Assertions.assertEquals(1, value.intValue());

// Should get a valid number
value = SolidityType.IntType.decodeInt(input, 32);
value = SolidityType.IntType.decodeInt(Bytes.of(input), 32);
Assertions.assertEquals(0, value.intValue());
}

Expand Down
Loading

0 comments on commit 1267e76

Please sign in to comment.