-
Notifications
You must be signed in to change notification settings - Fork 21
Recursive Length Prefix
An ultra-fast Recursive Length Prefix library in Java for use on the Ethereum network (see https://github.com/ethereum/wiki/wiki/RLP). Highly optimized to avoid unnecessary loops, branches, and array copies.
Example usage:
public Student(byte[] rlp) throws DecodeException {
Iterator<RLPItem> iter = RLP_STRICT.sequenceIterator(rlp);
this.name = iter.next().asString(UTF_8);
this.gpa = iter.next().asFloat();
this.publicKey = iter.next().asBytes();
this.balance = new BigDecimal(iter.next().asBigInt(), iter.next().asInt());
}
@Override
public Object[] toObjectArray() {
return new Object[] {
Strings.decode(name, UTF_8),
FloatingPoint.toBytes(gpa),
publicKey,
balance.unscaledValue().toByteArray(),
Integers.toBytes(balance.scale())
};
}
@Override
public byte[] toRLP() {
return RLPEncoder.sequence(toObjectArray());
}
Alternative style:
public class StudentRLPAdapter implements RLPAdapter<Student> {
@Override
public Student decode(byte[] rlp, int index) throws DecodeException {
Iterator<RLPItem> iter = RLP_STRICT.listIterator(rlp, index);
return new Student(iter.next().asString(UTF_8),
iter.next().asFloat(),
iter.next().asBytes(),
new BigDecimal(iter.next().asBigInt(), iter.next().asInt())
);
}
@Override
public byte[] encode(Student student) {
return RLPEncoder.list(student.toObjectArray());
}
}
Using the low-level API:
public Student(byte[] rlp, int index) throws DecodeException {
RLPItem item = RLP_STRICT.wrap(rlp, index);
this.name = item.asString(UTF_8);
item = RLP_STRICT.wrap(rlp, item.endIndex);
this.gpa = item.asFloat();
item = RLP_STRICT.wrap(rlp, item.endIndex);
this.publicKey = item.asBytes();
item = RLP_STRICT.wrap(rlp, item.endIndex);
BigInteger intVal = item.asBigInt();
item = RLP_STRICT.wrap(rlp, item.endIndex);
this.balance = new BigDecimal(intVal, item.asInt());
}
@Override
public byte[] toRLP() {
return RLPEncoder.sequence(toObjectArray());
}
Features support for integers (including negative), floating point numbers, chars, and booleans, as well as Strings, byte arrays, Object arrays, and Iterable<Object>.
Decode tested with data up to 2,147,483,634 bytes in length (list of 2,147,483,634 single-byte items). See RLPDecoderTest.java for more.
Object notation and parser for debugging:
byte[] rlp = FastHex.decode("8363617420c2c00900");
String notation = Notation.forEncoding(rlp).toString();
System.out.println(notation);
/*
(
'636174',
'20',
[ [ ], '09' ],
'00'
)
*/
List<Object> rlpObjects = NotationParser.parse(notation);
byte[] rlp2 = RLPEncoder.sequence(rlpObjects);
System.out.println(FastHex.encodeToString(rlp2)); // "8363617420c2c00900"
Decoding of sub-items is done on-demand, not eagerly. The source array is retained throughout the decoding process and is shared by all items.
You may verify the artifacts on Maven Central with my public key (fingerprint D2EA 6BCD 43B3 663C DF62 22C1 35AE 09FD 38F0 CFAE
):
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBFxH8QMBCADYL3yUozFs4jWSEpD3WDlvmVtwo0mu2AY4i4+IF679Zk7iDB+Q
COzcgGqmVsDlG7yUNGJ5q267BbMVM+XE+HAPiZgnh+a2q6hyW0Zt1BfArUUIqjSx
S16Yyl8FsXEMpLNF9AeE5QXcxfb4I/AIxWCWtq+UKY39ApgsiDvgjcIsutPxs7Cm
Fb9HjNnY48dGUEOew6QOdj+70dHwRW+O84h79Lcuu1IpR2PNts1CqOhQIZfFZ0J7
LYXRdWqYHE1/peqd1t1o7Kyrk7Y/toSMeK/Y8I3WP877YqJEUsndoofUFnsEXDo8
WvZJkE551kykwjG8r2/QvXOK+Kn/FmNCSFy5ABEBAAG0KUV2YW4gU2F1bHBhdWdo
IDxldmFuLnNhdWxwYXVnaEBnbWFpbC5jb20+iQFUBBMBCAA+AhsDBQsJCAcCBhUK
CQgLAgQWAgMBAh4BAheAFiEE0uprzUOzZjzfYiLBNa4J/Tjwz64FAmFeLl0FCQeG
MVsACgkQNa4J/Tjwz66fBwf/cNlZxxeRzr5OBHCQH/hcqEMPMs07vJhd/UE+frz2
T1MuT8UQPJl+tT/YxToI/Y+ZFnOxQQW+/Ryj+Gpgd0VQR9fRj3qY+bDmG/TLwN+i
YAW81aCGWzV0WQfF8RG9x9lsdZt2fZ5zmY9O2vN7G5hRhbkjDHlV8k9UfmukTMg5
sB6R3VsoVVS1Y9L1cE6876fTOY2RAajgxQFhxDLRujPOFFypX0HeKF1ApO4EuVPw
pJTR7X7+OJX/kEA5XQ2R8/ySRXritQ/XBCHR90aUWFeG+3mpwGegx4AVQzG+Pe1e
GL1eyzmiXRuQs/NAYrbOL+FyBbUTP7gOoTtVd1dZ04VS3rkBDQRcR/EDAQgAoUIj
i3uMn1DYhTRI2oVTVYUaPhqgd0yAhcuGP8ZlEG1+oCxLdUNeNiWh85LTWLNh0Yze
FGZE+6wOmDWA0epCpV45CgXoA6rFig7j2W3D+RTwFZuZK8tCaQEdhJhCeXqK2ye/
IDAUmTnrJyN+Vt+cIkceasY8VFRKpoJabaUPGo9MIAsxIYdiJPh96nyTbpAADGBk
/J2G6nffre2KSLVamEoFTlbO8vKDaXEfi2uCNWXd3OA+jDziszrGFJGIHTyfl9+w
QaH/Rleg2G/VXiLKgLnmeOkoS2QUisvJwbpVOpyxUVFfrcpsEs6UYRO0bYp44iHd
a6oUfZj3PCJT/VIx4QARAQABiQE8BBgBCAAmFiEE0uprzUOzZjzfYiLBNa4J/Tjw
z64FAlxH8QMCGwwFCQPDIZ0ACgkQNa4J/Tjwz67vjQf+JluNkKlc45nIEteq0B0X
os7RRWFCvbuH/le4JyGvD3zg9dtBrqknui+gdqfBPyeMXNorIozH5SxsBhbqxKoy
tHfX9dwwUPdkm1wacwjNnzxcuF04NxO2hxnoi7UeizyWx31BQuiT95/2pZ9OBgYt
n/9p7/iEH93wjLaUoYIK0WGucaSgDy1gweE7Z1egGBSPZD6YJIhFuD9uDqZMpKlV
+6mSdDHS2ZvYeYG/WpSxiGMo3quvsRyLDXc7/Geqgfhd3JXovvq8JrOF2AOCQmbP
f2m9l/cy8v/nuu1GvPADe5KqKlAUOszvFbc7mT93scRfSrXwoG9+TfJa/R588TXL
lw==
=I9lv
-----END PGP PUBLIC KEY BLOCK-----