以太坊 RLP 编码,数据序列化的基石
在以太坊的复杂世界中,数据的高效、可靠传输与存储至关重要,无论是交易、状态数据还是区块信息,都需要一种统一的方式来编码,以确保不同节点间能够准确无误地理解和交换这些数据,RLP(Recursive Length Prefix,递归长度前缀)编码正是以太坊为实现这一目标而设计的核心数据序列化方案,它以其简洁、高效和递归的特性,成为了以太坊数据结构得以在网络上传输和在区块链上存储的基石。
什么是 RLP 编码
RLP 编码是一种将任意嵌套的数组(或列表)和字节串(字符串)编码为线性字节的序列化方法,它的核心设计理念是“简单”和“递归”,简单意味着其编码规则相对直观,易于实现;递归则意味着它可以处理任意深度的嵌套数据结构,这正是区块链数据(如包含多个交易的区块)所需要的。
RLP 编码的目标不是对数据本身进行压缩(尽管它有时会减少数据大小),而是提供一个确定性的、无歧义的表示方式,使得解码方能够精确地重构出原始数据结构,确定性意味着相同的数据永远会被编码成相同的字节串,这对于区块链的共识至关重要。
RLP 编码的基本规则
RLP 编码主要针对两种数据类型进行编码:字符串(字节串,包括空字符串)和列表(其他 RLP 编码项的集合),其编码规则如下:
字符串(String)的编码
对于长度为 len 的字符串:
len == 0:编码为单字节0x80(二进制10000000)。1 <= len <= 55:编码为单字节0x80 + len(即b11000000 + len,其中前两位为11,后面 6 位表示长度)后紧跟字符串本身。- 字符串
"dog"(长度为 3)的编码为0x83 0x64 0x6f 0x67(83是80 + 3,64、6f、67分别是d、o、g的十六进制)。
- 字符串
len > 55:编码为单字节0xb7(10110111)后跟字符串长度的字节表示(使用最少的字节,大端序),然后是字符串本身。- 一个长度为 60 的字符串,其长度
60的十六进制为0x3c,需要 1 字节表示,编码为0xb7 0x3c后跟字符串本身。 - 一个长度为 1024 的字符串,其长度
1024的十六进制为0x0400,需要 2 字节表示,编码为0xb8 0x02 0x04(b8表示长度占 2 字节)后跟字符串本身。
- 一个长度为 60 的字符串,其长度
列表(List)的编码
列表是 RLP 编码的强大之处,它可以包含其他字符串或列表,形成任意深度的嵌套,列表的编码步骤如下:
- 计算列表中所有项(字符串或列表)的 RLP 编码后的总字节数,记为
total_len。 - 根据
total_len的长度决定前缀:total_len <= 55:编码为单字节0xc0 + total_len(即b11000000 + total_len,前两位为11,后面 6 位表示总长度)后跟所有项的 RLP 编码串联。- 列表
["dog", "cat"]:"dog"编码为0x83 0x64 0x6f 0x67(长度 4)"cat"编码为0x83 0x63 0x61 0x74(长度 4)total_len = 4 + 4 = 8- 列表编码为
0xc8 0x83 0x64 0x6f 0x67 0x83 0x63 0x61 0x74(c8是c0 + 8)
total_len > 55:编码为单字节0xf7(11110111)后跟total_len的字节表示(使用最少的字节,大端序),然后是所有项的 RLP 编码串联。- 一个包含两个较长字符串的列表,其编码后总长度为 1000。
1000的十六进制为0x03e8,需要 2 字节表示,列表编码为0xf8 0x03 0xe8后跟所有项的 RLP 编码。
- 一个包含两个较长字符串的列表,其编码后总长度为 1000。
RLP 编码在以太坊中的应用
RLP 编码几乎贯穿了以太坊的每一个角落,是构建区块链数据结构的基础:
- 区块(Block):区块头中的
transactionsRoot、stateRoot、receiptsRoot等都是通过 RLP 编码交易列表、状态、收据列表后计算出的哈希,区块本身也是一个包含区块头和交易列表的 RLP 列表。 - 交易(Transaction):每一笔以太坊交易(无论是 EOA 签名交易还是合约创建/调用交易)都被编码为 RLP 字符串,然后打包进区块的交易列表中。
- 状态存储(State Storage):以太坊的状态树(State Trie)的每个节点(包括账户状态、合约存储)的值都是通过 RLP 编码的,账户对象(nonce, balance, storageRoot, codeHash)本身就是一个 RLP 列表。

- 收据(Receipt):交易执行后产生的收据,包含了执行结果(成功/失败、日志、消耗的 gas 等),也是通过 RLP 编码后存储在收据树中。
- 区块头(Block Header):虽然区块头的大部分字段(如 number, timestamp, parentHash, difficulty 等)是直接编码的,但某些字段或其计算过程涉及 RLP 编码的数据结构。
RLP 编码的优缺点
优点:
- 简洁高效:编码规则简单,实现起来不复杂,且对于大多数常见数据结构,编码后的大小相对合理。
- 递归性:能够优雅地处理任意深度的嵌套数据结构,非常适合区块链这种层级分明的数据组织方式。
- 确定性:相同输入总是产生相同的输出,这是区块链共识的必要条件。
- 无需模式定义:与一些需要预先定义数据模式的序列化方案(如 Protocol Buffers, Avro)不同,RLP 不需要模式信息,解码方可以根据编码规则自动推断数据结构。
缺点:
- 非人类可读:RLP 编码后的字节串是二进制格式,无法直接阅读,通常需要借助工具进行解码。
- 压缩效率有限:它并非专门的压缩算法,对于某些重复性高的数据,压缩效果不如专门的压缩算法。
- 缺乏类型信息:RLP 本身不显式区分数据类型(如整数、浮点数),所有数据都被视为字符串或列表,数据的语义通常由上层协议约定,一个 RLP 编码的字符串
0x01可以被解释为整数 1 或字节0x01。
RLP 编码以其简洁、递归和确定性的特性,成为了以太坊数据序列化的标准选择,它像一条无形的纽带,将区块、交易、状态等核心数据元素紧密地连接在一起,确保了以太坊网络中数据的一致性和可靠性,虽然它并非完美,但其设计哲学很好地契合了区块链对简单、高效和可验证性的核心需求,对于任何想要深入理解以太坊底层实现的人来说,掌握 RLP 编码都是必不可少的一步,它不仅仅是一种技术细节,更是支撑起整个以太坊大厦的基石之一。