Simplify RLP

This commit is contained in:
ligi 2015-01-22 01:18:06 +01:00
parent 81fa268f93
commit d824db620a
1 changed files with 39 additions and 82 deletions

View File

@ -20,7 +20,7 @@ import static org.spongycastle.util.BigIntegers.asUnsignedByteArray;
* The purpose of RLP is to encode arbitrarily nested arrays of binary data, and * The purpose of RLP is to encode arbitrarily nested arrays of binary data, and
* RLP is the main encoding method used to serialize objects in Ethereum. The * RLP is the main encoding method used to serialize objects in Ethereum. The
* only purpose of RLP is to encode structure; encoding specific atomic data * only purpose of RLP is to encode structure; encoding specific atomic data
* types (eg. strings, ints, floats) is left up to higher-order protocols; in * types (eg. strings, integers, floats) is left up to higher-order protocols; in
* Ethereum the standard is that integers are represented in big endian binary * Ethereum the standard is that integers are represented in big endian binary
* form. If one wishes to use RLP to encode a dictionary, the two suggested * form. If one wishes to use RLP to encode a dictionary, the two suggested
* canonical forms are to either use [[k1,v1],[k2,v2]...] with keys in * canonical forms are to either use [[k1,v1],[k2,v2]...] with keys in
@ -48,7 +48,7 @@ public class RLP {
/** /**
* Allow for content up to size of 2^64 bytes * * Allow for content up to size of 2^64 bytes *
*/ */
private static double MAX_ITEM_LENGTH = Math.pow(256, 8); private static final double MAX_ITEM_LENGTH = Math.pow(256, 8);
/** /**
* Reason for threshold according to Vitalik Buterin: * Reason for threshold according to Vitalik Buterin:
@ -59,7 +59,7 @@ public class RLP {
* - so 56 and 2^64 space seems like the right place to put the cutoff * - so 56 and 2^64 space seems like the right place to put the cutoff
* - also, that's where Bitcoin's varint does the cutof * - also, that's where Bitcoin's varint does the cutof
*/ */
private static int SIZE_THRESHOLD = 56; private static final int SIZE_THRESHOLD = 56;
/** RLP encoding rules are defined as follows: */ /** RLP encoding rules are defined as follows: */
@ -74,7 +74,7 @@ public class RLP {
* byte with value 0x80 plus the length of the string followed by the * byte with value 0x80 plus the length of the string followed by the
* string. The range of the first byte is thus [0x80, 0xb7]. * string. The range of the first byte is thus [0x80, 0xb7].
*/ */
private static int OFFSET_SHORT_ITEM = 0x80; private static final int OFFSET_SHORT_ITEM = 0x80;
/** /**
* [0xb7] * [0xb7]
@ -85,7 +85,7 @@ public class RLP {
* \xb9\x04\x00 followed by the string. The range of the first byte is thus * \xb9\x04\x00 followed by the string. The range of the first byte is thus
* [0xb8, 0xbf]. * [0xb8, 0xbf].
*/ */
private static int OFFSET_LONG_ITEM = 0xb7; private static final int OFFSET_LONG_ITEM = 0xb7;
/** /**
* [0xc0] * [0xc0]
@ -95,7 +95,7 @@ public class RLP {
* of the RLP encodings of the items. The range of the first byte is thus * of the RLP encodings of the items. The range of the first byte is thus
* [0xc0, 0xf7]. * [0xc0, 0xf7].
*/ */
private static int OFFSET_SHORT_LIST = 0xc0; private static final int OFFSET_SHORT_LIST = 0xc0;
/** /**
* [0xf7] * [0xf7]
@ -105,7 +105,7 @@ public class RLP {
* followed by the concatenation of the RLP encodings of the items. The * followed by the concatenation of the RLP encodings of the items. The
* range of the first byte is thus [0xf8, 0xff]. * range of the first byte is thus [0xf8, 0xff].
*/ */
private static int OFFSET_LONG_LIST = 0xf7; private static final int OFFSET_LONG_LIST = 0xf7;
/* ****************************************************** /* ******************************************************
@ -178,45 +178,27 @@ public class RLP {
private static String decodeStringItem(byte[] data, int index) { private static String decodeStringItem(byte[] data, int index) {
final String value;
if ((data[index] & 0xFF) >= OFFSET_LONG_ITEM if ((data[index] & 0xFF) >= OFFSET_LONG_ITEM
&& (data[index] & 0xFF) < OFFSET_SHORT_LIST) { && (data[index] & 0xFF) < OFFSET_SHORT_LIST) {
byte lengthOfLength = (byte) (data[index] - OFFSET_LONG_ITEM); byte lengthOfLength = (byte) (data[index] - OFFSET_LONG_ITEM);
int length = calcLengthRaw(lengthOfLength, data, index); int length = calcLengthRaw(lengthOfLength, data, index);
value = new String(data, index + lengthOfLength + 1, length); return new String(data, index + lengthOfLength + 1, length);
} else if ((data[index] & 0xFF) > OFFSET_SHORT_ITEM } else if ((data[index] & 0xFF) > OFFSET_SHORT_ITEM
&& (data[index] & 0xFF) < OFFSET_LONG_ITEM) { && (data[index] & 0xFF) < OFFSET_LONG_ITEM) {
byte length = (byte) ((data[index] & 0xFF) - OFFSET_SHORT_ITEM); byte length = (byte) ((data[index] & 0xFF) - OFFSET_SHORT_ITEM);
value = new String(data, index + 1, length); return new String(data, index + 1, length);
} else { } else {
throw new RuntimeException("wrong decode attempt"); throw new RuntimeException("wrong decode attempt");
} }
return value;
} }
private static byte[] decodeItemBytes(byte[] data, int index) { private static byte[] decodeItemBytes(byte[] data, int index) {
final int length; final int length = calculateLength(data, index);
if ((data[index] & 0xFF) >= OFFSET_LONG_ITEM
&& (data[index] & 0xFF) < OFFSET_SHORT_LIST) {
byte lengthOfLength = (byte) (data[index] - OFFSET_LONG_ITEM);
length = calcLengthRaw(lengthOfLength, data, index);
} else if ((data[index] & 0xFF) > OFFSET_SHORT_ITEM
&& (data[index] & 0xFF) < OFFSET_LONG_ITEM) {
length = (byte) (data[index] - OFFSET_SHORT_ITEM);
} else {
throw new RuntimeException("wrong decode attempt");
}
byte[] valueBytes = new byte[length]; byte[] valueBytes = new byte[length];
System.arraycopy(data, index, valueBytes, 0, length); System.arraycopy(data, index, valueBytes, 0, length);
return valueBytes; return valueBytes;
@ -224,22 +206,7 @@ public class RLP {
public static BigInteger decodeBigInteger(byte[] data, int index) { public static BigInteger decodeBigInteger(byte[] data, int index) {
final int length; final int length = calculateLength(data, index);
if ((data[index] & 0xFF) >= OFFSET_LONG_ITEM
&& (data[index] & 0xFF) < OFFSET_SHORT_LIST) {
byte lengthOfLength = (byte) (data[index] - OFFSET_LONG_ITEM);
length = calcLengthRaw(lengthOfLength, data, index);
} else if ((data[index] & 0xFF) > OFFSET_SHORT_ITEM
&& (data[index] & 0xFF) < OFFSET_LONG_ITEM) {
length = (byte) (data[index] - OFFSET_SHORT_ITEM);
} else {
throw new RuntimeException("wrong decode attempt");
}
byte[] valueBytes = new byte[length]; byte[] valueBytes = new byte[length];
System.arraycopy(data, index, valueBytes, 0, length); System.arraycopy(data, index, valueBytes, 0, length);
return new BigInteger(1, valueBytes); return new BigInteger(1, valueBytes);
@ -247,22 +214,7 @@ public class RLP {
private static byte[] decodeByteArray(byte[] data, int index) { private static byte[] decodeByteArray(byte[] data, int index) {
final int length; final int length = calculateLength(data, index);
if ((data[index] & 0xFF) >= OFFSET_LONG_ITEM
&& (data[index] & 0xFF) < OFFSET_SHORT_LIST) {
byte lengthOfLength = (byte) (data[index] - OFFSET_LONG_ITEM);
length = calcLengthRaw(lengthOfLength, data, index);
} else if ((data[index] & 0xFF) > OFFSET_SHORT_ITEM
&& (data[index] & 0xFF) < OFFSET_LONG_ITEM) {
length = (byte) (data[index] - OFFSET_SHORT_ITEM);
} else {
throw new RuntimeException("wrong decode attempt");
}
byte[] valueBytes = new byte[length]; byte[] valueBytes = new byte[length];
System.arraycopy(data, index, valueBytes, 0, length); System.arraycopy(data, index, valueBytes, 0, length);
return valueBytes; return valueBytes;
@ -302,31 +254,19 @@ public class RLP {
public static byte[] decodeIP4Bytes(byte[] data, int index) { public static byte[] decodeIP4Bytes(byte[] data, int index) {
int length = (data[index] & 0xFF) - OFFSET_SHORT_LIST;
int offset = 1; int offset = 1;
byte aByte = decodeOneByteItem(data, index + offset); final byte[] result=new byte[4];
for ( int i =0 ; i<4 ; i++) {
if ((data[index + offset] & 0xFF) > OFFSET_SHORT_ITEM) result[i] = decodeOneByteItem(data, index + offset);
offset = offset + 2; if ((data[index + offset] & 0xFF) > OFFSET_SHORT_ITEM)
else offset += 2;
offset = offset + 1; else
byte bByte = decodeOneByteItem(data, index + offset); offset += 1;
}
if ((data[index + offset] & 0xFF) > OFFSET_SHORT_ITEM)
offset = offset + 2;
else
offset = offset + 1;
byte cByte = decodeOneByteItem(data, index + offset);
if ((data[index + offset] & 0xFF) > OFFSET_SHORT_ITEM)
offset = offset + 2;
else
offset = offset + 1;
byte dByte = decodeOneByteItem(data, index + offset);
// return IP address // return IP address
return new byte[]{aByte, bByte, cByte, dByte}; return result;
} }
public static int getFirstListElement(byte[] payload, int pos) { public static int getFirstListElement(byte[] payload, int pos) {
@ -640,7 +580,6 @@ public class RLP {
RLPItem rlpItem = new RLPItem(item); RLPItem rlpItem = new RLPItem(item);
rlpList.add(rlpItem); rlpList.add(rlpItem);
pos += 1; pos += 1;
continue;
} }
} }
} catch (Exception e) { } catch (Exception e) {
@ -914,4 +853,22 @@ public class RLP {
} }
throw new RuntimeException("Unsupported type: Only accepting String, Integer and BigInteger for now"); throw new RuntimeException("Unsupported type: Only accepting String, Integer and BigInteger for now");
} }
private static int calculateLength(byte[] data, int index) {
if ((data[index] & 0xFF) >= OFFSET_LONG_ITEM
&& (data[index] & 0xFF) < OFFSET_SHORT_LIST) {
byte lengthOfLength = (byte) (data[index] - OFFSET_LONG_ITEM);
return calcLengthRaw(lengthOfLength, data, index);
} else if ((data[index] & 0xFF) > OFFSET_SHORT_ITEM
&& (data[index] & 0xFF) < OFFSET_LONG_ITEM) {
return (byte) (data[index] - OFFSET_SHORT_ITEM);
} else {
throw new RuntimeException("wrong decode attempt");
}
}
} }