RLP(Recursive Length Prefix,递归长度前缀)是一种编码算法,用于编码任意的嵌套结构的二进制数据,它是以太坊中数据序列化/反序列化的主要方法,区块、交易等数据结构在持久化时会先通过RLP编码后再存储到数据库中。git
RLP编码的定义只处理两类数据:一类是字符串(例如字节数组),一类是列表。字符串指的是一串二进制数据,列表是一个嵌套递归的结构,里面能够包含字符串和列表,例如["cat",["puppy","cow"],"horse",[[]],"pig",[""],"sheep"]
就是一个复杂的列表。其余类型的数据须要转成以上的两类,转换的规则不是RLP编码定义的,能够根据本身的规则转换,例如struct
能够转成列表,int
能够转成二进制(属于字符串一类),以太坊中整数都以大端形式存储。github
从RLP编码的名字能够看出它的特色:一个是递归,被编码的数据是递归的结构,编码算法也是递归进行处理的;二是长度前缀,也就是RLP编码都带有一个前缀,这个前缀是跟被编码数据的长度相关的,从下面的编码规则中能够看出这一点。算法
[0x00, 0x7f]
,它的RLP编码就是它自己。0x80
**加上字符串的长度。因为被编码的字符串最大长度是55=0x37
,所以单字节前缀的最大值是0x80+0x37=0xb7
,即编码的第一个字节的取值范围是[0x80, 0xb7]
。0xb7
**加上字符串长度的二进制形式的字节长度,说的有点绕,举个例子就明白了,例如一个字符串的长度是1024,它的二进制形式是10000000000
,这个二进制形式的长度是2个字节,因此前缀应该是0xb7+2=0xb9
,字符串长度1024=0x400
,所以整个RLP编码应该是\xb9\x04\x00
再跟上字符串自己。编码的第一个字节即前缀的取值范围是[0xb8, 0xbf]
,由于字符串长度二进制形式最少是1个字节,所以最小值是0xb7+1=0xb8
,字符串长度二进制最大是8个字节,所以最大值是0xb7+8=0xbf
。0xc0
**加上列表的总长度。编码的第一个字节的取值范围是[0xc0, 0xf7]
。0xf7
**加上列表总长度的二进制形式的字节长度。编码的第一个字节的取值范围是[0xf8, 0xff]
。"dog" = [0x83, 'd', 'o', 'g' ]
(规则二)["cat","dog"] = [0xc8, 0x83, 'c', 'a', 't', 0x83, 'd', 'o', 'g' ]
(规则四)"" = 0x80
(规则二)[] = [0xc0]
(规则四)15('\x0f') = 0x0f
(规则一)1024('\x04\00') = [0x82, 0x04, 0x00]
(规则二)[ [], [[]], [ [], [[]] ] ] = [0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0]
(规则四)"Lorem ipsum dolor sit amet, consectetur adipisicing elit" = [0xb8, 0x38, 'L', 'o', 'r', 'e', 'm', ' ', ... , 'e', 'l', 'i', 't']
(规则三)本文大部分翻译自以太坊github wiki文档,并加入本身的理解。数据库
参考资料:https://github.com/ethereum/wiki/wiki/%5BEnglish%5D-RLP数组