Created
September 3, 2020 18:16
-
-
Save jrhea/28f679d5b6837f45242e810edd49b612 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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