以太坊:底层序列化编码方式RLP

转载请注明出处:https://www.cnblogs.com/zhizaixingzou/p/10122380.html

目录

1. RLP以太坊底层序列化编码方式

1.1. 简介

https://segmentfault.com/a/1190000011763339

https://github.com/ethereum/wiki/wiki/RLP

RLPRecursive Length Prefix,递归长度前缀。它是以太坊底层序列化采用的编码方式。RLP主要用于以太坊中数据的网络传输和持久化存储。它的设计目的就是编码任意嵌套的二进制数组或列表。

序列化对象的编码方式有很多种,为什么还要重复发明轮子呢?常见的JSON编码,有个明显的缺点,就是引入了太多冗余信息编码结果比较大。而其他的编码方式,要么不为以太坊设计者所知,要么看起来都不如自己设计的编码来的合适。

1.2. 原理

RLP编码只对3种数据类型编码:

类型1值在[0127]之间的单个字节。使用下面的规则1

类型2字节数组(元素数可为0)。使用下面的规则2和规则3

类型3列表(列表是以数组或列表为元素的数组,元素数不可为0)。使用下面的规则4和规则5

RLP编码的编码规则:

规则1对于值在[0127]之间的单个字节,其编码是字节自身。

9->9

 规则2对于长度len<=55的字节数组,其编码是128+len,紧接着字节数组自身。

[9]->[129,9]

len=1
129=128+len

规则3对于长度len>55的字节数组,其编码是183+len编码的长度,紧接着len的编码,紧接着字节数组自身。len的大小不能超过8字节能表示的值。

[97,97,...,97]->[185,4,0,97,97,...,97]

len=1024
[4,0]=len的编码(编码涉及多字节的数值表示时,使用大端模式)
185=183+[4,0]的长度

 规则4如果列表长度len<=55其编码是192+len紧接着各子列表的编码。列表长度是指子列表编码后的长度之和。这是递归定义。

[[97,98,99],[100,101,102]]->[200,131,97,98,99,131,100,101,102]

131=128+3
200=192+4+4

规则5如果列表长度len>55,其编码是247+len的编码的长度,紧接着len的编码,紧接着各子列表的编码。len的大小不能超过8字节能表示的值。这是递归定义。

["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 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 163 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]

179 = 128 + 51
163 = 128 + 35
88 = 51+35 + 2
248 = 247 +1

从编码规则可以看出:编码的结果是一个字节数组。编码结果的长度不能超过8字节能表示的值,也就是264次方,2ZB的数据,这是很大的数据了。

各种程序设计语言在实现RLP编码时,需要首先将对象转换为3种数据类型中的一种具体怎么转换则自己定义。

RLP编码的解码规则是编码规则的逆运算。首先根据编码结果的第一个字节f,执行以下的规则判断:

判断1如果f[0127],那么反序列化后是一个字节,就是f

判断2如果f[128183],那么反序列化后是一个长度len<=55的字节数组,字节数组的长度为len=f-128

判断3如果f[184192],那么反序列化后是一个长度len>55的字节数组,字节数组长度的编码的长度lenOfLen=f-183,然后从第二个字节开始读取lenOfLen个字节,按照大端模式转换成整数lenlen即为字节数组的长度。

判断4如果f[193247],那么反序列化后是一个编码后长度len<=55的列表,列表长度为len=f-192。递归使用判断1~4进行解码。

判断5如果f[247255],那么反序列化后是编码后长度len>55的列表,列表长度的编码的长度lenOfLen=f-247,然后从第二个字节开始读取lenOfLen个字节,按照大端模式转换成整数lenlen即为子列表总长度。然后递归使用判断1~5进行解码。

可以看到,接收到编码的数据1)就能根据第一个字节推断出数据的类型2)并且最多再读几个字节就能知道数据的大小,这就解释了“长度前缀”的意义。加之解码时使用了递归算法,因而此编码方式就叫递归长度前缀编码。

1.3. 源码实现

源代码见:org.ethereum.util.RLP

源码实现与原理描述有两点稍有不同:

1)实际上不只提供了3种数据类型,但其他类型都转换成这3种后才编码,且每种类型都对应了编码和解密方法。也就是说,收方知道收到的数据是用什么方法编码的,它会调用对应的方法解密。

2)实际使用的规则可能稍有出入,也更琐碎些。

原文地址:https://www.cnblogs.com/zhizaixingzou/p/10122380.html