Skip to content

Latest commit

 

History

History
106 lines (77 loc) · 4.73 KB

File metadata and controls

106 lines (77 loc) · 4.73 KB

RLP编码

当设计网络拓扑以后就需要具体到每一条连接来发送数据,但是我们知道TCP协议是基于流的协议,也就意味着我们需要把编写的代码序列化成二进制的形式进行传输,当对端接收到这些流数据后,再进行反序列化,得到具体的数据结构进行后续的操作。

一般而言,序列化的协议有文本协议和二进制协议,两种协议各有优劣,比如像Json这种文本协议,编码后的体积比较大。

type Persion struct {
    Name string
    Age uint 
}
 p := &Persion{Name: "Tom", Age: 22}
 data, _ := json.Marshal(p)
 fmt.Println(string(data))
//  {"Name":"Tom","Age":22}

从编码后的结果可以看到,其实我们需要的数据是Name, Tom, Age, 22,其余的括号和引号都是描述这种格式的,也就是冗余数据,但是这种编码方式的可读性非常好。

二进制协议序列化后是一串二进制表示的数据,基本不可读,但是冗余信息少,传输效率高。在区块链场景下显然需要一种高性能,易解析,低冗余的传输协议,所以优先选择二进制协议。

在二进制协议里,比较出名的是google的protobuf和facebook的thrift,但是以太坊中并没有采用这两种序列化方式,主要是因为在以太坊这种区块链场景下要求序列化后的字节序要一致,protobuf和thrift和在一些场景序列化后得的字节序是不一致的,虽然对端依然可以解析,但是会导致对同一个数据结构内容的签名不一致的问题,这个问题会影响智能合约的部署时的验签操作。

为了解决这个问题,以太坊设计了新的编码方式RLP(Recursive Length Prefix)递归长度前缀编码,RLP除了用于以太坊的网络数据传输还用于持久化存储。

RLP编码定义

RLP简化了编码的类型,只定义了两种类型编码:

  • byte数组
  • byte数组的数组,也就是列表

以go语言编码struct为例,会将其映射为列表

type Student struct{
    Name    string
    Country string
}
s := Student{Name:"qyuan", Country:"china"}

例如Student这个对象处理成列表["qyuan","china"]

如果编码map类型,可以采用以下列表形式:

foo := make(map[string]string)
foo["name"]    = "qyuan"
foo["country"] = "china"

例如foo这个map处理成列表[["name","qyuan"],["country","china"]]

RLP编码规则

基于上面两种数据类型提出了5条编码规则;

规则一

对于值在[0, 127]之间的单个字节,其编码是其本身;

a的编码是97
规则二

如果byte数组的长度l<=55,编码的结果是数组本身,再加上128+l作为前缀。

空字符串的编码是`128`,即 `128=128+0`
`abc`的编码是`131 97 98 99`,其实`131=128+len("abc")`, `97 98 99`依次是`a b c`
规则三

如果数组长度大于55,编码结果第一个值是183(128+55)加数组长度的编码的长度,然后是数组长度本身的编码,最后是byte数组的编码。

编码一个重复1024次"a"的字符串,其结果是`185 4 0 97 97 97 ...` 

1024按照大端编码0000 0000 001转换为十进制是0 0 4 0,省略前面的0,长度为2, 因此185 = 183 + 2

规则四

如果列表长度小于55,编码结果第一位是192加列表长度的编码的长度,然后依次连接各个子列表的编码。

`["abc", "def"]`的编码结果是`200 131 97 98 99 131 100 101 102`

其中abc的编码是131 97 98 99, 131 = 128 + l长度是4,def的编码是131 100 101 102,长度是4,总长度为8,编码结果的第一位200 = 192 + 8

规则五

如果列表的长度超过55,编码结果第一位是247(192 + 55)加列表长度的编码长度,然后是列表本身的编码,最后依次连接子列表的编码

["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 110116 101 110 99 101 32 105 115 32 109 111 114 101 32 116 104 97 110 32 53 53 32 98 121 116 101115 44 32 163 73 32 107 110 111 119 32 105 116 32 98 101 99 97 117 115 101 32 73 32 112 114101 45 100 101 115 105 103 110 101 100 32 105 116

其中前两个字节的计算方式如下:

  • 248 = 247 + 1

  • 88 = 86 + 2, 在规则3的示例中,长度为86,而在此例中,由于有两个子字符串,每个子字符串本身的长度的编码各占1字节,因此总共占2字节。

  • 第3个字节179依据规则2得出

第55个字节163同样依据规则2得出163=128+35

其中规则三规则四规则5是递归定义的,可以允许嵌套