Skip to content
This repository has been archived by the owner on Sep 26, 2019. It is now read-only.

Commit

Permalink
Add additional RLP tests (#332)
Browse files Browse the repository at this point in the history
  • Loading branch information
mbaxter authored Nov 29, 2018
1 parent ab744a9 commit 9f432ce
Show file tree
Hide file tree
Showing 9 changed files with 605 additions and 248 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package tech.pegasys.pantheon.ethereum.rlp;

import tech.pegasys.pantheon.ethereum.rlp.util.RLPTestUtil;
import tech.pegasys.pantheon.util.bytes.BytesValue;

import java.util.ArrayList;
Expand Down Expand Up @@ -62,16 +63,16 @@ private static Object generateAndRecurse(
@Setup(Level.Trial)
public void prepare() {
toEncode = generate(depth, width, size);
toDecode = RLP.encode(toEncode);
toDecode = RLPTestUtil.encode(toEncode);
}

@Benchmark
public BytesValue getBenchmarkEncoding() {
return RLP.encode(toEncode);
return RLPTestUtil.encode(toEncode);
}

@Benchmark
public Object getBenchmarkDecoding() {
return RLP.decode(toDecode);
return RLPTestUtil.decode(toDecode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
import tech.pegasys.pantheon.util.bytes.BytesValue;
import tech.pegasys.pantheon.util.bytes.MutableBytesValue;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

import io.vertx.core.buffer.Buffer;
Expand Down Expand Up @@ -81,65 +79,6 @@ public static BytesValueRLPInput input(final Buffer buffer, final int offset) {
return new BytesValueRLPInput(BytesValue.wrapBuffer(buffer, offset), false, false);
}

/**
* Fully decodes a RLP encoded value.
*
* <p>This method is mostly intended for testing as it is often more convenient <b>and</b>
* efficient to use a {@link RLPInput} (through {@link #input(BytesValue)}) instead.
*
* @param value The RLP encoded value to decode.
* @return The output of decoding {@code value}. It will be either directly a {@link BytesValue},
* or a list whose elements are either {@link BytesValue}, or similarly composed sub-lists.
* @throws RLPException if {@code value} is not a properly formed RLP encoding.
*/
public static Object decode(final BytesValue value) {
return decode(input(value));
}

private static Object decode(final RLPInput in) {
if (!in.nextIsList()) {
return in.readBytesValue();
}

final int size = in.enterList();
final List<Object> l = new ArrayList<>(size);
for (int i = 0; i < size; i++) l.add(decode(in));
in.leaveList();
return l;
}

/**
* Fully RLP encode an object consisting of recursive lists of {@link BytesValue}.
*
* <p>This method is mostly intended for testing as it is often more convenient <b>and</b>
* efficient to use a {@link RLPOutput} (through {@link #encode(Consumer)} for instance) instead.
*
* @param obj An object that must be either directly a {@link BytesValue}, or a list whose
* elements are either {@link BytesValue}, or similarly composed sub-lists.
* @return The RLP encoding corresponding to {@code obj}.
* @throws IllegalArgumentException if {@code obj} is not a valid input (not entirely composed
* from lists and {@link BytesValue}).
*/
public static BytesValue encode(final Object obj) {
final BytesValueRLPOutput out = new BytesValueRLPOutput();
encode(obj, out);
return out.encoded();
}

private static void encode(final Object obj, final RLPOutput out) {
if (obj instanceof BytesValue) {
out.writeBytesValue((BytesValue) obj);
} else if (obj instanceof List) {
final List<?> l = (List<?>) obj;
out.startList();
for (final Object o : l) encode(o, out);
out.endList();
} else {
throw new IllegalArgumentException(
format("Invalid input type %s for RLP encoding", obj.getClass()));
}
}

/**
* Creates a {@link RLPOutput}, pass it to the provided consumer for writing, and then return the
* RLP encoded result of that writing.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,19 @@ static int extractSize(final IntUnaryOperator getter, final int offset, final in
}

/** Read from the provided offset a size of the provided length, assuming this is enough bytes. */
static int extractSizeFromLong(
static int extractSizeFromLongItem(
final LongUnaryOperator getter, final long offset, final int sizeLength) {
String oversizedErrorMessage =
"RLP item at offset "
+ offset
+ " with size value consuming "
+ sizeLength
+ " bytes exceeds max supported size of "
+ Integer.MAX_VALUE;
if (sizeLength > 4) {
throw new RLPException(oversizedErrorMessage);
}

long res = 0;
int shift = 0;
for (int i = 0; i < sizeLength; i++) {
Expand All @@ -77,9 +88,7 @@ static int extractSizeFromLong(
try {
return Math.toIntExact(res);
} catch (final ArithmeticException e) {
final String msg =
"unable to extract size from long at offset " + offset + ", sizeLen=" + sizeLength;
throw new RLPException(msg, e);
throw new RLPException(oversizedErrorMessage, e);
}
}

Expand Down Expand Up @@ -139,7 +148,7 @@ private static int readLongSize(
throw new MalformedRLPInputException("Malformed RLP item: size of payload has leading zeros");
}

final int res = RLPDecodingHelpers.extractSizeFromLong(byteGetter, item + 1, sizeLength);
final int res = RLPDecodingHelpers.extractSizeFromLongItem(byteGetter, item + 1, sizeLength);

// We should not have had the size written separately if it was less than 56 bytes long.
if (res < 56) {
Expand All @@ -166,7 +175,15 @@ static class RLPElementMetadata {

/** @return the size of the byte string holding the rlp-encoded value and metadata */
int getEncodedSize() {
return Math.toIntExact(elementEnd() - elementStart + 1);
long encodedSize = elementEnd() - elementStart + 1;
try {
return Math.toIntExact(encodedSize);
} catch (ArithmeticException e) {
String errorMessage =
String.format(
"RLP item exceeds max supported size of %d: %d", Integer.MAX_VALUE, encodedSize);
throw new RLPException(errorMessage, e);
}
}

/**
Expand Down
Loading

0 comments on commit 9f432ce

Please sign in to comment.