在以太坊生态系统中,无论是智能合约的部署与执行,还是节点间的数据通信,都离不开一种基础而又关键的技术——RLP(Recursive Length Prefix,递归长度前缀),RLP是以太坊中用于对任意嵌套的二维数组(字节数组或字符串)进行编码的主要方法,它以一种简洁、高效且递归的方式,确保了数据在以太坊网络中的可靠传输和存储,本文将深入探讨RLP的原理、规则及其在以太坊中的核心作用。
以太坊作为一个去中心化的平台,需要处理各种复杂的数据结构,如账户状态、交易数据、区块头、合约代码等,这些数据往往具有嵌套和变长的特点,为了确保这些数据能够在不同节点之间准确、高效地传递,并且能够被存储在区块链上,一种统一且可靠的数据序列化方案至关重要。
RLP应运而生,它的设计目标并非像JSON或Protocol Buffers那样追求通用性和强大的表达能力,而是极致的简洁和高效,RLP的核心思想是:只编码数据本身,而不编码数据类型(如整数、字符串等),通过长度前缀来标识数据的边界,从而实现对任意嵌套字节数组的编码。

RLP的编码规则相对简单,主要针对两类数据:单字节字符串(字节数组长度为0或1)以及长度大于1的字节数组或字符串列表(嵌套结构)。
编码单字节字符串(字节数组)
0x80(十六进制,即二进制的 10000000)。[0x00, 0x7f] 范围内(即最高位为0的ASCII字符或空字节),则其RLP编码就是该字节本身,字节数组 [0x48](字符 'H')的RLP编码就是 0x48。0x00 到 0x7f 之间的值,如果它代表的是一个数值(比如以太坊中的金额),通常也会被转换为字节数组后再进行RLP编码,而不是直接编码数值本身。编码长度大于1的字节数组
L。L 的大小,选择不同的前缀:
1 <= L <= 55:RLP编码由一个前缀字节(0x80 L)后跟原始字节数组组成,字节数组 [0x01, 0x02](长度为2),前缀为 0x80 2 = 0x82,所以RLP编码为 0x820102。L > 55:RLP编码由一个前缀字节(0xb7 长度L的字节长度)、长度 L 的本身(以大端序无符号整数形式编码)、以及原始字节数组组成,长度为 56(0x38)的字节数组,其长度 L 的字节长度为1,所以前缀为 0xb7 1 = 0xb8,然后是长度 0x38,最后是字节数组本身,若字节数组为 [0x01] * 56,则RLP编码为 0xb8380101...01(56个01)。L 的字节长度超过8(即 L > 2^56 - 1,这在以太坊中几乎不可能出现,但RLP规范理论上支持),则前缀为 0xb9 长度L的字节长度,依此类推。编码列表(嵌套结构)

L。L 的大小,选择与前述字节数组类似的前缀规则:
0 <= L <= 55:RLP编码由一个前缀字节(0xc0 L)后跟拼接后的各项RLP编码组成,列表 [ "dog", "cat" ],"dog" 的RLP编码是 0x646f67(长度3,0x80 3=0x83,但"dog"是3字节,0x83 'dog' -> 0x83646f67?不,等一下,"dog"是3字节,属于1<=L<=55,所以前缀是0x80 3=0x83是'dog',dog"的RLP是0x83646f67?不对,这里我之前规则描述有误,更正:对于1<=L<=55的字节数组,前缀是0x80 L,然后是字节数组本身,dog"(3字节)的RLP是0x83 0x646f67 = 0x83646f67,同理"cat"(3字节)是0x83636174,然后列表是这两项的拼接:0x83646f6783636174,这个拼接后的总长度是 1 (0x83) 3 (dog) 1 (0x83) 3 (cat) = 8 字节,因为L=8 <=55,所以列表前缀是0xc0 8 = 0xc8,所以整个列表的RLP编码是0xc883646f6783636174。L > 55:类似于长字节数组,前缀为 0xf7 拼接后总长度L的字节长度,然后是 L 本身(大端序),最后是拼接后的各项RLP编码,如果拼接后的总长度为 56,前缀就是 0xf7 1 = 0xf8,然后是 0x38,再然后是拼接内容。递归性:列表中的每一项都可以是字符串或另一个列表,从而实现对任意深度嵌套结构的编码。
RLP是以太坊数据层的基础,几乎所有需要序列化的地方都会用到它:
区块结构:以太坊的区块头、交易列表、叔块列表等都是通过RLP编码的,一个区块的RLP编码通常是 RLP(uncle_hash, beneficiary, state_root, transactions_root, receipts_root, logs_bloom, difficulty, number, gas_limit, gas_used, timestamp, extra_data, mix_hash, nonce, transactions, uncles)。
交易数据:每笔交易(无论是Legacy, EIP-1559还是Access List类型)的交易体(如nonce, gas price, gas limit, to, value, data, v, r, s等字段)都会被RLP编码,形成交易数据,节点间广播交易、将交易打包进区块都依赖RLP编码的交易数据。

状态存储:以太坊的状态树(State Trie)中,每个账户的存储(Storage Trie)和账户本身(包括nonce, balance, root code, storage_root)都需要通过RLP编码后才能作为树的节点值。
节点通信:以太坊节点之间通过RLPx协议进行通信,而在更上层的应用层协议(如 eth 协议)中,传输的各种数据结构(如区块、交易、状态查询等)也大量使用RLP进行编码和解码,确保数据在不同实现(如Geth, Nethermind等客户端)之间的一致性。
合约部署与调用:智能合约的字节码本身就是字节数组,其部署和调用时的参数也需要通过RLP等方式进行序列化处理。
优点: