/** * Recursively decodes an RLP encoded value. Byte strings are assumed to be non-scalar (leading * zeros are allowed). * * @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(RLP.input(value)); }
@Test public void raw() { final BytesValue initial = h("0xc80102c51112c22122"); final RLPInput in = RLP.input(initial); assertThat(in.raw()).isEqualTo(initial); }
@Test public void decodeValueWithLeadingZerosAsUnsignedInt() { RLPInput in = RLP.input(h("0x84000000D0")); assertThat(in.readUnsignedInt()).isEqualTo(208); }
@Test public void decodeValueWithLeadingZerosAsSignedInt() { RLPInput in = RLP.input(h("0x84000000D0")); assertThat(in.readInt()).isEqualTo(208); }
@Test public void decodeValueWithLeadingZerosAsSignedLong() { RLPInput in = RLP.input(h("0x8800000000000000D0")); assertThat(in.readLong()).isEqualTo(208); }
@Test public void emptyList() { final RLPInput in = RLP.input(h("0xc0")); assertThat(in.isDone()).isFalse(); assertThat(in.enterList()).isEqualTo(0); assertThat(in.isDone()).isFalse(); in.leaveList(); assertThat(in.isDone()).isTrue(); }
@Test public void singleByte() { final RLPInput in = RLP.input(h("0x01")); assertThat(in.isDone()).isFalse(); assertThat(in.readByte()).isEqualTo((byte) 1); assertThat(in.isDone()).isTrue(); }
@Test public void simpleListwithBytesValue() { final RLPInput in = RLP.input(h("0xc28180")); assertThat(in.isDone()).isFalse(); assertThat(in.enterList()).isEqualTo(1); assertThat(in.readBytesValue()).isEqualTo(h("0x80")); in.leaveList(); assertThat(in.isDone()).isTrue(); }
@Test public void decodeValueWithLeadingZerosAsBytesValue() { RLPInput in = RLP.input(h("0x8800000000000000D0")); assertThat(BytesValues.extractLong(in.readBytesValue())).isEqualTo(208); } }
@Test public void singleBarelyLongElement() { final RLPInput in = RLP.input(h("0xb838" + times("2b", 56))); assertThat(in.isDone()).isFalse(); assertThat(in.readBytesValue()).isEqualTo(h(times("2b", 56))); assertThat(in.isDone()).isTrue(); }
@Test public void singleLongElement() { final RLPInput in = RLP.input(h("0xb908c1" + times("3c", 2241))); assertThat(in.isDone()).isFalse(); assertThat(in.readBytesValue()).isEqualTo(h(times("3c", 2241))); assertThat(in.isDone()).isTrue(); }
@Test public void simpleLongListBoundaryCase_1() { final RLPInput in = RLP.input(h("0xf8ff" + times("3c", 255))); assertThat(in.isDone()).isFalse(); assertThat(in.enterList()).isEqualTo(255); for (int i = 0; i < 255; i++) { assertThat(in.readByte()).isEqualTo((byte) 0x3c); } in.leaveList(); assertThat(in.isDone()).isTrue(); }
@Test public void simpleLongListBoundaryCase_4() { final RLPInput in = RLP.input(h("0xfa010000" + times("3c", 65536))); assertThat(in.isDone()).isFalse(); assertThat(in.enterList()).isEqualTo(65536); for (int i = 0; i < 65536; i++) { assertThat(in.readByte()).isEqualTo((byte) 0x3c); } in.leaveList(); assertThat(in.isDone()).isTrue(); }
@Test public void singleLongElementBoundaryCase_4() { final RLPInput in = RLP.input(h("0xba010000" + times("3c", 65536))); assertThat(in.isDone()).isFalse(); assertThat(in.readBytesValue()).isEqualTo(h(times("3c", 65536))); assertThat(in.isDone()).isTrue(); }
@Test public void singleLongElementBoundaryCase_6() { // A RLPx Frame can have a maximum length of 0xffffff, so boundary above this // will be not be real world scenarios. final RLPInput in = RLP.input(h("0xbb01000000" + times("3c", 16777216))); assertThat(in.isDone()).isFalse(); assertThat(in.readBytesValue()).isEqualTo(h(times("3c", 16777216))); assertThat(in.isDone()).isTrue(); }
@Test public void simpleLongListBoundaryCase_2() { final RLPInput in = RLP.input(h("0xf90100" + times("3c", 256))); assertThat(in.isDone()).isFalse(); assertThat(in.enterList()).isEqualTo(256); for (int i = 0; i < 256; i++) { assertThat(in.readByte()).isEqualTo((byte) 0x3c); } in.leaveList(); assertThat(in.isDone()).isTrue(); }
@Test public void rlpItemSizeOverflowsSignedInt() { // Size value encoded in 4 bytes but exceeds max positive int value AssertionsForClassTypes.assertThatThrownBy(() -> RLP.input(h("0xBB80000000"))) .isInstanceOf(RLPException.class) .hasMessageContaining( "RLP item at offset 1 with size value consuming 4 bytes exceeds max supported size of 2147483647"); }
@Test public void rlpItemSizeOverflowsInt() { // Size value is encoded with 5 bytes - overflowing int AssertionsForClassTypes.assertThatThrownBy(() -> RLP.input(h("0xBC0100000000"))) .isInstanceOf(RLPException.class) .hasMessageContaining( "RLP item at offset 1 with size value consuming 5 bytes exceeds max supported size of 2147483647"); }
@Test public void rlpListSizeOverflowsSignedInt() { // Size value encoded in 4 bytes but exceeds max positive int value AssertionsForClassTypes.assertThatThrownBy(() -> RLP.input(h("0xFB80000000"))) .isInstanceOf(RLPException.class) .hasMessageContaining( "RLP item at offset 1 with size value consuming 4 bytes exceeds max supported size of 2147483647"); }
@Test public void toFromRlp() { final BlockDataGenerator gen = new BlockDataGenerator(); final TransactionReceipt receipt = gen.receipt(); final TransactionReceipt copy = TransactionReceipt.readFrom(RLP.input(RLP.encode(receipt::writeTo))); assertEquals(receipt, copy); } }