Skip to content

Instantly share code, notes, and snippets.

@jrhea
Created September 3, 2020 18:16
Show Gist options
  • Save jrhea/28f679d5b6837f45242e810edd49b612 to your computer and use it in GitHub Desktop.
Save jrhea/28f679d5b6837f45242e810edd49b612 to your computer and use it in GitHub Desktop.
class Playground {
public static int OFFSET_SHORT_STRING = 0x80;
public static int OFFSET_LONG_STRING = 0xb7;
public static int OFFSET_SHORT_LIST = 0xc0;
public static int OFFSET_LONG_LIST = 0xf7;
public static void main(String[ ] args) {
try {
byte[] data = new byte[] {
(byte) 0xbb, (byte) 0x7f, (byte) 0xff, (byte) 0xff, (byte) 0xff,
};
traverse(data, 0, data.length, -1);
System.out.println(data);
} catch (Exception e) {
System.out.println(e.toString());
}
System.out.println("###############################################################################");
try {
byte[] data = new byte[] {
(byte) 0x58, (byte) 0x58, (byte) 0x58, (byte) 0x58, (byte) 0x58,
};
traverse(data, 0, data.length, -1);
} catch (Exception e) {
System.out.println(e.toString());
}
System.out.println("###############################################################################");
try {
byte[] data = new byte[] {
(byte) 0xb8, (byte) 0x01, (byte) 0xFF, (byte) 0xFF,
};
traverse(data, 0, data.length, -1);
} catch (Exception e) {
System.out.println(e.toString());
}
System.out.println("###############################################################################");
try {
byte[] data = new byte[] {
(byte) 0xc0, (byte) 0x58, (byte) 0x58, (byte) 0x58,
};
traverse(data, 0, data.length, -1);
} catch (Exception e) {
System.out.println(e.toString());
}
System.out.println("###############################################################################");
try {
byte[] data = new byte[] {
(byte) 0xc0
};
traverse(data, 0, data.length, -1);
} catch (Exception e) {
System.out.println(e.toString());
}
System.out.println("###############################################################################");
try {
byte[] data = new byte[] {
(byte) 0xc1, (byte) 0x58
};
traverse(data, 0, data.length, -1);
} catch (Exception e) {
System.out.println(e.toString());
}
System.out.println("###############################################################################");
try {
byte[] data = new byte[] {
(byte) 0x08, (byte) 0x7f, (byte) 0x7f, (byte) 0x7f, (byte) 0x58,
};
traverse(data, 0, data.length, -1);
} catch (Exception e) {
System.out.println(e.toString());
}
System.out.println("###############################################################################");
try {
byte[] data = new byte[] {
(byte) 0x58,
};
traverse(data, 0, data.length, -1);
} catch (Exception e) {
System.out.println(e.toString());
}
}
private static void traverse(byte[] data, int startPos, int endPos, int outerPrefixLength) {
try {
if (data == null || data.length == 0) {
return;
}
System.out.println("startPos: " + startPos + " endPos: " + endPos + " data.length: " + data.length + " outerPrefixLength: " + outerPrefixLength);
for (int j=0; j<data.length; j++) {
System.out.format("%02X ", data[j]);
}
System.out.println();
// endPos is derived from input data during recursion, so we must validate it
if (endPos < 0 || endPos > data.length) {
throw new RuntimeException("RLP invalid parameters while decoding");
}
while (startPos < endPos) {
System.out.printf("data[" + startPos + "]: %02X\n", data[startPos]);
int prefix = data[startPos] & 0xff;
System.out.printf("prefix: %02X\n", data[startPos] & 0xff);
if (prefix < OFFSET_SHORT_STRING) {
System.out.println("prefix < OFFSET_SHORT_STRING");
// 1. the data is a string if the range of the
// first byte(i.e. prefix) is [0x00, 0x7f],
// and the string is the first byte itself exactly;
// Input validation
System.out.println(outerPrefixLength);
if ( (outerPrefixLength == 0 || outerPrefixLength > 1) || ( outerPrefixLength == -1 && (endPos - (startPos + 1) > 0 )) ) {
System.out.println("endPos - (startPos + 1) > 0");
throw new RuntimeException("RLP length mismatch 0");
}
byte[] rlpData = {(byte) prefix};
//rlpList.getValues().add(RlpString.create(rlpData));
startPos += 1;
} else if (prefix == OFFSET_SHORT_STRING) {
System.out.println("prefix == OFFSET_SHORT_STRING");
// null
//rlpList.getValues().add(RlpString.create(new byte[0]));
startPos += 1;
} else if (prefix > OFFSET_SHORT_STRING && prefix <= OFFSET_LONG_STRING) {
System.out.println("prefix > OFFSET_SHORT_STRING && prefix <= OFFSET_LONG_STRING");
// 2. the data is a string if the range of the
// first byte is [0x80, 0xb7], and the string
// which length is equal to the first byte minus 0x80
// follows the first byte;
byte strLen = (byte) (prefix - OFFSET_SHORT_STRING);
// Input validation
if (strLen > endPos - (startPos + 1)) {
System.out.println("strLen > endPos - (startPos + 1)");
throw new RuntimeException("RLP length mismatch");
}
byte[] rlpData = new byte[strLen];
System.arraycopy(data, startPos + 1, rlpData, 0, strLen);
//rlpList.getValues().add(RlpString.create(rlpData));
startPos += 1 + strLen;
} else if (prefix > OFFSET_LONG_STRING && prefix < OFFSET_SHORT_LIST) {
System.out.println("prefix > OFFSET_LONG_STRING && prefix < OFFSET_SHORT_LIST");
// 3. the data is a string if the range of the
// first byte is [0xb8, 0xbf], and the length of the
// string which length in bytes is equal to the
// first byte minus 0xb7 follows the first byte,
// and the string follows the length of the string;
byte lenOfStrLen = (byte) (prefix - OFFSET_LONG_STRING);
int strLen = calcLength(lenOfStrLen, data, startPos);
// Input validation
if (strLen > endPos - (startPos + lenOfStrLen + 1)) {
System.out.println("strLen > endPos - (startPos + lenOfStrLen + 1)");
throw new RuntimeException("RLP length mismatch");
}
System.out.println("startPos: " + startPos + " endPos: " + endPos + " strLen: " + strLen + " lenOfStrLen: " + lenOfStrLen);
// now we can parse an item for data[1]..data[length]
byte[] rlpData = new byte[strLen];
System.arraycopy(data, startPos + lenOfStrLen + 1, rlpData, 0, strLen);
//rlpList.getValues().add(RlpString.create(rlpData));
startPos += lenOfStrLen + strLen + 1;
} else if (prefix >= OFFSET_SHORT_LIST && prefix <= OFFSET_LONG_LIST) {
System.out.println("prefix >= OFFSET_SHORT_LIST && prefix <= OFFSET_LONG_LIST");
// 4. the data is a list if the range of the
// first byte is [0xc0, 0xf7], and the concatenation of
// the RLP encodings of all items of the list which the
// total payload is equal to the first byte minus 0xc0 follows the first byte;
byte listLen = (byte) (prefix - OFFSET_SHORT_LIST);
// Input validation
//if ( startPos + listLen + 1 > endPos ) {
// throw new RuntimeException("RLP length mismatch SHORT LIST");
//}
//RlpList newLevelList = new RlpList(new ArrayList<>());
traverse(data, startPos + 1, startPos + listLen + 1, listLen);
//rlpList.getValues().add(newLevelList);
startPos += 1 + listLen;
} else if (prefix > OFFSET_LONG_LIST) {
System.out.println("prefix > OFFSET_LONG_LIST");
// 5. the data is a list if the range of the
// first byte is [0xf8, 0xff], and the total payload of the
// list which length is equal to the
// first byte minus 0xf7 follows the first byte,
// and the concatenation of the RLP encodings of all items of
// the list follows the total payload of the list;
byte lenOfListLen = (byte) (prefix - OFFSET_LONG_LIST);
int listLen = calcLength(lenOfListLen, data, startPos);
System.out.println("startPos: " + startPos + " endPos: " + endPos + " listLen: " + listLen + " lenOfListLen: " + lenOfListLen);
//if ( startPos + lenOfListLen + listLen + 1 > endPos ) {
// throw new RuntimeException("RLP length mismatch");
//}
//RlpList newLevelList = new RlpList(new ArrayList<>());
traverse(
data,
startPos + lenOfListLen + 1,
startPos + lenOfListLen + listLen + 1,
listLen);
// newLevelList);
//rlpList.getValues().add(newLevelList);
startPos += lenOfListLen + listLen + 1;
}
}
} catch (Exception e) {
System.out.println(e.toString());
throw new RuntimeException("RLP wrong encoding", e);
}
}
private static int calcLength(int lengthOfLength, byte[] data, int pos) {
if( pos + lengthOfLength > data.length - 1 ){
throw new RuntimeException("RLP attempting to read outside array");
}
byte pow = (byte) (lengthOfLength - 1);
long length = 0;
for (int i = 1; i <= lengthOfLength; ++i) {
length += ((long) (data[pos + i] & 0xff)) << (8 * pow);
pow--;
}
if (length < 0 || length > Integer.MAX_VALUE) {
throw new RuntimeException("RLP too many bytes to decode");
}
return (int) length;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment