以太坊 RLP

RLP(Recursive Length Prefix,递归长度前缀)编码算法,是以太坊中数据序列化/反序列化的主要方法。
以太坊区块链中的区块、交易等数据结构在持久化时会先经过 RLP 编码后再存储到数据库中。

与其他序列化方法相比,RLP编码的优点在于,当接收或者解码经过RLP编码后的数据时,根据第1个字节就能推断数据的类型、大概长度和数据本身等信息。
并且能编码相当大的数据。而其他的序列化方法, 不能根据第1个字节获得如此多的信息量。
RLP 编码只处理两类数据:
    字符串  e.g.  this is string
    列符表  e.g.  ["cat","horse",[[]],"pig",[""],"sheep"]

其他数据类型的数据需要转换成以上的两类,转换的规则不是 RLP 编码定义的,可以根据自己的规则转换。
例如struct可以转换成列表,int 可以转换成二进制(属于字符串一类),以太坊中整数都以大端形式存储。

RLP编码规则 1
    对于单个字节,如果它的值范围是[0x00,0x7f](ASCII码),它的 RLP 编码就是它本身。
如:
a [0x61] (字符)
100 [0x64](数字)

RLP编码规则 2
字符串长度是0-55字节,它的 RLP 编码包含一个单字节的前缀,后面跟着字符串的长度,再接着字符串本身。
这个前缀的值0x80加上字符串的长度。
由于被编码的字符串最大长度是55=0x37,因此单字节前缀的最大值是0x80+0x37=0xb7,即编码的第一个字节的取值范围是[0x80,0xb7]。

字符串长度小于55字节的RLP 编码例子:
“dog” [0x83, 'd', 'o', 'g']
其中0x83 = 0x80 + 3(“dog”字符串的长度)

RLP编码规则 3
字符串长度大于55个字节,它的 RLP 编码包含一个单字节的前缀,后面跟着字符串的长度,再接着字符串本身。
这个前缀的值是0xb7加上字符串长度的二进制形式的字节长度。
由于被编码的字符串长度的二进制长度最少是1个字节,最大是8个字节,前缀的取值范围是[0xb8,0xbf]。

字符串长度大于55字节的 RLP 编码例子:
字符串:
"Lorem ipsum dolor sit amet, consectetur adipisicing elit"
字符串长度:
56字节,其二进制形式为:00111000。其二进制形式的长度为8位,也就是1个字节长度。
前缀:0xb7 + 1 = 0xb8
字符串长度的16进制表示:56 à 0x38
该字符串的 RLP 编码形式为:
[0xb8, 0x38, 'L', 'o', 'r', 'e', 'm', ' ', ... , 'e', 'l', 'i', 't']


func TestRlp(t *testing.T) {
	addr := []byte("Hello")
	b := new(bytes.Buffer)
	err := rlp.Encode(b, addr)
	fmt.Println(b.Bytes(), err)
	fmt.Printf("%x\n", b.Bytes())

	var s []byte
	rlp.Decode(b, &s)
	fmt.Println(string(s))
}

运行结果
[133 72 101 108 108 111]
8548656c6c6f
Hello


func TestRlp(t *testing.T) {

	addr := []byte("abcdefghijklmnopqrstuvwxyz12345689mnbvcz")
	b := new(bytes.Buffer)
	err := rlp.Encode(b, addr)
	fmt.Println(b.Bytes(), err)
	fmt.Printf("%x\n", b.Bytes())

	var s []byte
	rlp.Decode(b, &s)
	fmt.Println(string(s))
}

运行结果
[168 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 49 50 51 52 53 54 56 57 109 110 98 118 99 122]
a86162636465666768696a6b6c6d6e6f707172737475767778797a31323334353638396d6e6276637a
abcdefghijklmnopqrstuvwxyz12345689mnbvcz


 

你可能感兴趣的:(ethereum)