【转载请标明出处】: https://blog.csdn.net/qq_25870633/article/details/82694270
本文章参考自:
https://segmentfault.com/a/1190000011763339
hello,大家好,今天呢,本low逼程序员来和大家说一说这个以太坊中所使用的RLP编码是个怎么回事。RLP 是“递归长度前缀编码” recursive的英文简称。主要用于编码具有嵌套结构的二进制数据,是以太坊数据序列化的主要方法。在以太坊中所有的Block、TX等数据都需要先经过RLP编码之后才存到DB中。RPL只处理两种类型数据:字符串 (byte数组)、列表;如果要存其他类型数据的话,则必须先转成这两种类型才可以进行编码,例如:对Map进行编码,需要把map的内容变为二维数组,如: [[k1, v1], [k2, v2], ..., [kn, vn]]然后才进行RLP编码,或者更高级的是把map转成 patricia trie 才进行编码。
在RLP中,字符串 (byte数组) 一般认为是一串二进制的数据,列表则认为是一个嵌套递归结构(里头的元素可以是 字符串或者列表)。所以,如要对其他类型数据进行编码则需要先转成以上两种类型。转换没有规则,全凭用户自行转,如:结构体可以转成列表,int可以转成二进制字符串。
RLP的编码规则:
【一】对于字符串 (btye数组):
- 【a】对于单个字节的 (即范围: [0, 127] 之间):编码就是自己本身,值范围: [0, 127] == [0x00, 0x7f]
- 【b】0 -> 55 长度的字符串:则为 前缀( 128 + len(字符串)) + 字符串,值范围:[128, 183] == [0x80, 0xb7] ([128, 128 + 55]);如: abc 编码为: 128 + len("abc") a b c == 131 97 98 99 (其中 a b c 的编码分别为 97 98 99)
- 【c】 长度大于55的字符串:则为 前缀(183 + len(byte(len(字符串)))) + len(字符串) + 字符串,即:【前缀】==183加上字符串⻓度所占⽤的字节数长度 + 字符串本身,值范围:[183, 191] == [0xb8, 0xbf] (因为任意字符串的长度的二进制表示绝逼超不过8个字节, 2^64);如: "The length of this sentence is more than 55 bytes, I know it because I pre-designed it" 我们看到该字符串的长度为,86字节,然后86的二进制标识为: 1010110 明显只占一个字节,所以是 183 + 1 == 前缀,+ 字符串本身,184 86 84 104 101 32 108 101 110 103 116 104 32 111 102 32 116 104 105 115 32 115 101 110 116 101 110 99 101 32 105 115 32 109 111 114 101 32 116 104 97 110 32 53 53 32 98 121 116 101 115 44 32 73 32 107 110 111 119 32 105 116 32 98 101 99 97 117 115 101 32 73 32 112 114 101 45 100 101 115 105 103 110 101 100 32 105 116 。
【二】对于列表:
- 【a】对于长度为 0 -> 55 的列表:前缀(192 + len(列表各项编码后的长度)) + 列表各项的 RLP 编码,值范围:[192, 247] == [0xc0, 0xf7] ;如:["abc", "def"] 的编码为,因为 “abc” 编码为,131 97 98 99,“def” 编码长度为,131 100 101 102,所以列表的编码长度为 8,故 前缀为, 192 + 8 = 200,所以该列表的编码结果为:200 131 97 98 99 131 100 101 102
- 【b】对于长度大于55的列表:前缀(247 + len(byte(列表各项编码后的长度))) + 列表的长度 + 列表各项的RLP编码,值范围:[248, 255] == [0xf8, 0xff] ,原理和字符串的【c】一致;如:["The length of this sentence is more than 55 bytes, ", "I
know it because I pre-designed it"] 我们分别对立面的两个大字符串进行编码,即:"The length of this sentence is more than 55 bytes, " 因为长度为 51 所以该字符串的RLP编码为:【规则二】 179(128 + 51) 84 104 101 32 108 101 110 103 116 104 32 111 102 32 116 104 105 115 32 115 101 110 116 101110 99 101 32 105 115 32 109 111 114 101 32 116 104 97 110 32 53 53 32 98 121 116 101 115 44 32;而"I know it because I pre-designed it" 的RLP编码为:163(128 + 35) 73 32 107 110 111 119 32 105 116 32 98 101 99 97 117 115 101 32 73 32 112 114 101 45 100 101 115 105 103110 101 100 32 105 116;然后因为编码后的字符串放到一起后,需要再根据【规则三】得到 51 + 35 = 86 (字符串的总长度),然后还要算上 51 和 35转换为二进制之后所占的长度即分别为1,所以连起来就是 :179 84 104 101 32 108 101 110 103 116 104 32 111 102 32 116 104 105 115 32 115 101 110 116 101110 99 101 32 105 115 32 109 111 114 101 32 116 104 97 110 32 53 53 32 98 121 116 101 115 44 32 163 7332 107 110 111 119 32 105 116 32 98 101 99 97 117 115 101 32 73 32 112 114 101 45 100 101 115 105 103110 101 100 32 105 116 占有了 86 + 2 = 88,然后又因为 88 的二进制长度为 1,所以前缀为:247 + 1 = 248,所以总的RLP编码为:248 88 179 84 104 101 32 108 101 110 103 116 104 32 111 102 32 116 104 105 115 32 115 101 110 116 101110 99 101 32 105 115 32 109 111 114 101 32 116 104 97 110 32 53 53 32 98 121 116 101 115 44 32 163 7332 107 110 111 119 32 105 116 32 98 101 99 97 117 115 101 32 73 32 112 114 101 45 100 101 115 105 103110 101 100 32 105 116;
下面我们再对复杂的列表做一下RLP编码,如:
["abc",["The length of this sentence is more than 55 bytes, ", "I know it because I pre-designed it"]] ;我们知道,该列表一看就是大于55字符的,然后对于列表我们都需要先分别对立面的元素项先做RLP编码,首先是"abc"根据【规则二】编码得到131 97 98 99,长度为4。而["The length of this sentence is more than 55 bytes, ", "I know it because I pre-designed it"] 根据上面的结果得到:248 88 179 84 104 101 32 108 101 110 103 116 104 32 111 102 32 116 104 105 115 32 115 101 110 116 101110 99 101 32 105 115 32 109 111 114 101 32 116 104 97 110 32 53 53 32 98 121 116 101 115 44 32 163 7332 107 110 111 119 32 105 116 32 98 101 99 97 117 115 101 32 73 32 112 114 101 45 100 101 115 105 103110 101 100 32 105 116,长度为90,然后整个列表的编码结果第二位是90 + 4 = 94, 占用1个字节,第一位247 + 1 = 248,所以为:248 94 131 97 98 99 248 88 179 84 104 101 32 108 101 110 103 116 104 32 111 102 32 116 104 105 115 32115 101 110 116 101 110 99 101 32 105 115 32 109 111 114 101 32 116 104 97 110 32 53 53 32 98 121 116101 115 44 32 163 73 32 107 110 111 119 32 105 116 32 98 101 99 97 117 115 101 32 73 32 112 114 101 45100 101 115 105 103 110 101 100 32 105 116。
到此为止,我们对RLP的编码已经基本了解,那么我们来说一说RLP的解码吧。
解码时,首先根据编码结果第一个字节f
的大小,执行以下的规则判断:
1. 如果f∈ [0,128), 那么它是一个字节本身。
2. 如果f∈[128,184),那么它是一个长度不超过55的byte数组,数组的长度为 l=f-128
3. 如果f∈[184,192),那么它是一个长度超过55的数组,长度本身的编码长度ll=f-183
,然后从第二个字节开始读取长度为ll的bytes,按照BigEndian编码成整数l,l即为数组的长度。
4. 如果f∈[192,248),那么它是一个编码后总长度不超过55的列表,列表长度为l=f-192
。递归使用规则1~4进行解码。
5. 如果f∈[248,256),那么它是编码后长度大于55的列表,其长度本身的编码长度ll=f-247
,然后从第二个字节读取长度为ll的bytes,按BigEndian编码成整数l,l即为子列表长度。然后递归根据解码规则进行解码。
之所以这么做是因为选择了更小的编码方式,及能够快速的解码(根据上面规则就能快速的区分原数据类型,并得到快速的解码)