目录
- RLP序列化
- 什么是序列化?
- 为什么要序列化?
- RLP序列化处理的两项数据
- RLP序列化采取的5项规则:
- 利用python写的RLP
- 实际中的使用是个怎么样子?
- RLP分析
- 参考目录
@
RLP序列化
RLP:这是一种对任意结构的二进制数据(字节数组)进行编码的序列化方法
什么是序列化?
序列化将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
序列化机制的核心作用就是对象状态的保存与重建。
为什么要序列化?
1、以某种存储形式使自定义对象持久化。->便于对象持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里)
2、将对象从一个地方传递到另一个地方。->便于网络传输,利用序列化实现远程通信,即在网络上传送对象的字节序列
3、使程序更具维护性。->便于维护,程序员依照相同的序列化规则,进行序列化及反序列化。
序列化的方法:Json序列化、FastJson序列化、xml序列化..等等,RLP正是序列化方法的一种,以太坊中使用了大量的RLP序列化
RLP序列化处理的两项数据
区块、交易等数据结构在持久化时会先经过RLP编码后再存储到数据库中,RLP编码的定义只处理两类数据:
- 一类是byte数组。
- 一类byte数组的数组,称之为列表。(递归定义)
这里的递归定义就比较相似与JSON,可以很容易的表示出一个树的结构。
RLP序列化采取的5项规则:
- 对于值在[0, 127]之间的单个字节,其编码是其本身。
例1:a的编码是97。 - 如果byte数组长度l <= 55,编码的结果是数组本身,再加上128+l作为前缀。
例2:abc编码结果是131 97 98 99.其中131=128+len("abc"),97 98 99依次是a b c。 - 如果数组长度大于55,编码结果第一个是183加数组长度的编码的长度,然后是数组长度的本身的编码,最后是byte数组的编码。
例3:“The length of this sentence is more than 55 bytes, I know it because I pre-designed it” = [183 + 1,86, ‘T’, ‘h’, ‘e’, ‘ ’, ’l’, ‘e’, … , ‘d’, ‘ ’, ‘i’, ’t’]
这里一定要注意的是:加上的数组长度的编码,86是数组的长度,86编码之后占用1个字节(在1到128之间),所以才加上1 - 如果列表长度小于55,编码结果第一位是192加列表长度的编码的长度,然后依次连接各子列表的编码。
例4: ["abc", "def"]的编码结果是200 131 97 98 99 131 100 101 102。其中abc的编码为131 97 98 99,def的编码为131 100 101 102。两个子字符串的编码后总长度是8,因此编码结果第一位计算得出:192 + 8 = 200。 - 如果列表长度超过55,编码结果第一位是247加列表长度的编码长度,然后是列表长度本身的编码,最后依次连接各子列表的编码。
这里一定要注意的是:加上的是列表长度的编码长度!类似于规则3
ps:
- 列表长度是指子列表编码后的长度之和。
- 规则1~3定义了byte数组的编码方案(也就是第一种数据结构)下面介绍列表(第二种数据结构)的编码规则
现在我们看一个较复杂的例子:
例5:["abc",["The length of this sentence is more than 55 bytes, ", "I know it because I pre-designed it"]]
列表第一项字符串abc根据规则2,编码结果为131 97 98 99,长度为4。
列表第二项也是一个列表项,根据规则5,编码结果为
247+1 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+第一个列表编码+第二个列表编码详细解释:
其中前两个字节的计算方式如下:
248 = 247 +1
为什么加1? 列表长度为90,列表长度的编码为1(字节)
88 = 86 + 2
为什么加2?
列表长度是指子列表编码后的长度之和。
两种看法:
其一可以看为:在规则3的示例中,长度为86,而在此例中,由于有两个子字符串,每个子字符串本身的长度的编码各占1字节,因此总共占2字节。
(列表长度本身的编码)
其二可以看为: 后面的90-2就是88
第3个字节179依据规则2得出179 = 128 + 51
第55个字节163同样依据规则2得出163 = 128 + 35
(递归)因此,整个列表的编码结果第二位是90 + 4 = 94, 占用1个字节,第一位247 + 1 = 248
最后的结果为:248,94,第一个列表编码,第二个列表编码
最后,编码为:
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 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
利用python写的RLP
def rlp_encode(input):
if isinstance(input,str):
if len(input) == 1 and chr(input) < 128: return input #规则一
else: return encode_length(len(input),128) + input #规则二和规则三
elif isinstance(input,list):
output = ''
for item in input: output += rlp_encode(item) #递归的去遍历
return encode_length(len(output),192) + output #规则四和规则五
def encode_length(L,offset):
if L < 56:
return chr(L + offset)
elif L < 256**8:
BL = to_binary(L)
return chr(len(BL) + offset + 55) + BL
else:
raise Exception("input too long")
def to_binary(x):
return '' if x == 0 else to_binary(int(x / 256)) + chr(x % 256)
实际中的使用是个怎么样子?
在具体实现RLP编码时,首先需要将对像映射成byte数组或列表两种形式。以go语言编码struct为例,会将其映射为列表,例如Student这个对象处理成列表["icattlecoder","male"]
实际中的,不同,就是讲的没用16进制表示,正常来讲,是16进制表示。
RLP分析
RLP最大的优点是在充分利用字节的情况下,同时支持列表结构,也就是说可以很轻易的利用RLP存储一个树状结构。
以上我们可以看出RLP编码的设计思想,就是通过首字节快速判断一串编码的类型,充分利用了一个字节,两个字节的存储空间,将0x7f以后的值赋予了新的含义。
程序处理RLP编码时也非常容易。
根据首字节就可以判断出这段编码的类型,同时调用不同的方法进行解码,和JSON编码类似,支持嵌套的结构,通过递归调用可以将整个RLP快速还原成一颗树,或者转译成一个JSON结构,便于其他程序使用
所以理论上RLP可以编码任何数据。
RLP使用首字节存储长度的位数,再用后续的字节表明整体字符串的长度,根据规则二计算,RLP可以支持的单个最大字符串长度为2的64次方,这无疑是个天文数字,再加上嵌套规则.
参考目录
[1]. RLP编码和解码
[2]. 以太坊RLP用法-以太坊源码学习
[3]. 简单分析RLP编码原理
[4]. 以太坊源码学习—RLP编码
如果我的工作为您带来了少许帮助,帮忙点一波关注或者收藏吧~(#^.^#)