RLP编码和解码

RLP编码和解码GitHub 上英文介绍 解码部分为本人所编辑 https github com ethereum wiki wiki RLPRLP RecursiveLen 递归的长度前缀 是一种编码规则 可用于编码任意嵌套的二进制数组数据 RLP 编码的结果也是二进制序列 RLP 主要用来序列化 反序列化数据 目录 1 RLP 数据定义 2 RLP 编码规则 3

GitHub上英文介绍(解码部分为本人所编辑):https://github.com/ethereum/wiki/wiki/RLP

RLP(Recursive Length Prefix,递归的长度前缀)是一种编码规则,可用于编码任意嵌套的二进制数组数据。RLP编码的结果也是二进制序列。RLP主要用来序列化/反序列化数据。

目录

1. RLP数据定义

RLP编码的定义只处理以下2类底层数据:

  • 字符串(string)是指字节数组。例如,空串”“,再如单词”cat”,以及句子”Lorem ipsum dolor sit amet, consectetur adipisicing elit”等。
  • 列表(list)是一个可嵌套结构,里面可包含字符串和列表。例如,空列表[],再如一个包含两个字符串的列表[“cat”,”dog”],再比如嵌套列表的复杂列表[“cat”, [“puppy”, “cow”], “horse”, [[]], “pig”, [“”], “sheep”]。

所有上层类型的数据需要转成以上的2类数据,才能进行RLP编码。转换的规则RLP编码不统一规定,可以自定义转换规则。例如struct可以转成列表;int可以转成二进制序列(属于字符串这一类, 必须去掉首部0,必须用大端模式表示);map类型可以转换为由k和v组成的结构体、k按字典顺序排列的列表:[[k1,v1],[k2,v2]…] 等。

从上面的数据类型定义中可以看出,RLP编码的数据是可嵌套的。从RLP编码的名字可以看出,RLP编码是递归的,这一点从下面的规则和代码可以看出。

2. RLP编码规则

RLP编码的重点是给原始数据前面添加若干字节的前缀,而且这个前缀是和数据的长度相关的,并且是递归的。

RLP编码中的长度是数据的实际存储空间的字节大小,去掉首位0的正整数,用大端模式表示的二进制格式表示。

RLP编码规定数据(字符串或列表)的长度的长度不得大于8字节。因为超过8字节后,一个字节的前缀就不能存储了。

  1. 如果字符串的长度是1个字节,并且它的值在[0x00, 0x7f] 范围之间,那么其RLP编码就是字符串本身。即前缀为空,用前缀代表字符串本身;
  2. 否则,如果一个字符串的长度是0-55字节,其RLP编码是前缀跟上(拼接)字符串本身,前缀的值是0x80加上字符串的长度。由于在该规则下,字符串的最大长度是55,因此前缀的最大值是0x80+55=0xb7,所以在本规则下前缀(第一个字节)的取值范围是[0x80, 0xb7];
  3. 如果字符串的长度大于55个字节,其RLP编码是前缀跟上字符串的长度再跟上字符串本身。前缀的值是0xb7加上字符串长度的二进制形式的字节长度(即字符串长度的存储长度)。即用额外的空间存储字符串的长度,而前缀中只存字符串的长度的长度。例如一个长度是1024的字符串,字符串长度的二进制形式是\x04\x00,因此字符串长度的长度是2个字节,所以前缀应该是0xb7+2=0xb9,由此得到该字符串的RLP编码是\xb9\x04\x00再跟上字符串本身。因为字符串长度的长度最少需要1个字节存储,因此前缀的最小值是0xb7+1=0xb8;又由于长度的最大值是8个字节,因此前缀的最大值是0xb7+8=0xbf,因此在本规则下前缀的取值范围是[0xb8, 0xbf];
  4. 以上3个规则是针对字符串的,接下来的两个规则针对列表的。由于列表的任意嵌套的,因此列表的编码是递归的,先编码最里层列表,再逐步往外层列表编码。如果一个列表的总长度(payload,列表的所有项经过编码后拼接在一起的字节大小)是0-55字节,其RLP编码是前缀依次跟上列表中各项的RLP编码。前缀的值是0xc0加上列表的总长度。在本规则下前缀的取值范围是[0xc0, 0xf7]。本规则与规则2类似;
  5. 如果一个列表的总长度大于55字节,它的RLP编码是前缀跟上列表的长度再依次跟上列表中各元素项的RLP编码。前缀的值是0xf7加上列表总长度的长度。编码的第一个字节的取值范围是[0xf8, 0xff]。本规则与规则3类似;

代码如下:

def rlp_encode(input): if isinstance(input,str): if len(input) == 1 and ord(input) <= 0x7f: return input else: return encode_length(len(input), 0x80) + input elif isinstance(input,list): output = '' for item in input: output += rlp_encode(item) return encode_length(len(output), 0xc0) + output def encode_length(L,offset): if L < 56: return chr(L + offset) elif L < 2568: BL = to_binary(L) return chr(len(BL) + offset + 55) + BL else: raise Exception("input too long") def to_binary(x): if x == 0return '' else: return to_binary(int(x / 256)) + chr(x % 256)

3. RLP编码举例

  • 整数 0(‘\x00’) = [0x00] (规则一)
  • 整数 1024(‘\x04\00’) = [0x82, 0x04, 0x00] (规则二)
  • 空字符串(‘null’) = [0x80] (规则二)
  • 字符串 “dog” = [0x83, ‘d’, ‘o’, ‘g’ ] (规则二)
  • 字符串 “Lorem ipsum dolor sit amet, consectetur adipisicing elit” = [0xb8, 0x38, ‘L’, ‘o’, ‘r’, ‘e’, ‘m’, ’ ‘, … , ‘e’, ‘l’, ‘i’, ‘t’] (规则三)
  • 空列表 [] = [0xc0] (规则四)
  • 列表 [“cat”,”dog”] = [0xc8, 0x83, ‘c’, ‘a’, ‘t’, 0x83, ‘d’, ‘o’, ‘g’ ] (规则四)
  • 嵌套列表 [ [], [[]], [ [], [[]] ] ] = [0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0] (规则四)

4. RLP解码规则

根据RLP编码规则和过程,RLP解码的输入一律视为二进制字符数组,其过程如下:

  1. 根据输入首字节数据,解码数据类型、实际数据长度和位置;
  2. 根据类型和实际数据,解码不同类型的数据;
  3. 继续解码剩余的数据;

其中,解码数据类型、实际数据类型和位置的规则如下:

  1. 如果首字节(prefix)的值在[0x00, 0x7f]范围之间,那么该数据是字符串,且字符串就是首字节本身;
  2. 如果首字节的值在[0x80, 0xb7]范围之间,那么该数据是字符串,且字符串的长度等于首字节减去0x80,且字符串位于首字节之后;
  3. 如果首字节的值在[0xb8, 0xbf]范围之间,那么该数据是字符串,且字符串的长度的字节长度等于首字节减去0xb7,数据的长度位于首字节之后,且字符串位于数据的长度之后;
  4. 如果首字节的值在[0xc0, 0xf7]范围之间,那么该数据是列表,在这种情况下,需要对列表各项的数据进行递归解码。列表的总长度(列表各项编码后的长度之和)等于首字节减去0xc0,且列表各项位于首字节之后;
  5. 如果首字节的值在[0xf8, 0xff]范围之间,那么该数据为列表,列表的总长度的字节长度等于首字节减去0xf7,列表的总长度位于首字节之后,且列表各项位于列表的总长度之后;

代码如下:

def rlp_decode(input): if len(input) == 0: return output = '' (offset, dataLen, type) = decode_length(input) if type is str: output = instantiate_str(substr(input, offset, dataLen)) elif type is list: output = instantiate_list(substr(input, offset, dataLen)) output + rlp_decode(substr(input, offset + dataLen)) return output def decode_length(input): length = len(input) if length == 0: raise Exception("input is null") prefix = ord(input[0]) if prefix <= 0x7f: return (0, 1, str) elif prefix <= 0xb7 and length > prefix - 0x80: strLen = prefix - 0x80 return (1, strLen, str) elif prefix <= 0xbf and length > prefix - 0xb7 and length > prefix - 0xb7 + to_integer(substr(input, 1, prefix - 0xb7)): lenOfStrLen = prefix - 0xb7 strLen = to_integer(substr(input, 1, lenOfStrLen)) return (1 + lenOfStrLen, strLen, str) elif prefix <= 0xf7 and length > prefix - 0xc0: listLen = prefix - 0xc0; return (1, listLen, list) elif prefix <= 0xff and length > prefix - 0xf7 and length > prefix - 0xf7 + to_integer(substr(input, 1, prefix - 0xf7)): lenOfListLen = prefix - 0xf7 listLen = to_integer(substr(input, 1, lenOfListLen)) return (1 + lenOfListLen, listLen, list) else: raise Exception("input don't conform RLP encoding form") def to_integer(b) length = len(b) if length == 0: raise Exception("input is null") elif length == 1: return ord(b[0]) else: return ord(substr(b, -1)) + to_integer(substr(b, 0, -1)) * 256

5. 总结

与其他序列化方法相比,RLP编码的优点在于使用了灵活的长度前缀来表示数据的实际长度,并且使用递归的方式能编码相当大的数据。

当接收或者解码经过RLP编码后的数据时,根据第1个字节就能推断数据的类型、大概长度和数据本身等信息。而其他的序列化方法, 不能根据第1个字节获得如此多的信息量。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/204967.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午7:07
下一篇 2026年3月19日 下午7:07


相关推荐

  • pca主要成分分析_通俗易懂的俗语

    pca主要成分分析_通俗易懂的俗语转载自:http://blog.codinglabs.org/articles/pca-tutorial.html文章分析脉络梳理: 1.向量A和B的内积表示的是向量A在B上的投影长度。那么将一个向量与新的基做内积,结果则表示该向量在新的基下的坐标。2.将新选定的基表示成矩阵形式,与原向量相乘,就得到了原向量在新选定的基所表示的空间(或坐标系)中的坐标表示了。3.怎样选定这组基用于数据降维?(目标…

    2022年10月16日
    5
  • 我学MSMQ(二)

    我学MSMQ(二)

    2021年8月28日
    62
  • 静态路由命令配置_配置静态路由的命令格式为

    静态路由命令配置_配置静态路由的命令格式为前话之前发表了相关路由协议简单配置命令,RIP、OSPF等都是动态路由协议。这次我简单写一下静态理由简单配置命令,的确很简单一行命令就可以了。静态路由介绍静态路由是指由用户或网络管理员手工配

    2022年8月1日
    9
  • 查看Vue版本 node.js版本vue-cli版本

    查看Vue版本 node.js版本vue-cli版本查看node.js版本node-v查看vue版本npmlistvue或者进入项目中package.json文件直接查看查看Vue-cli版本vue-V或者vue–version

    2022年5月10日
    229
  • apache安装教程详解_Apache安装

    apache安装教程详解_Apache安装1.Apache安装1.下载apache下载链接2.将解压文件移动到目标目录(整个文件目录最好用英文不要有空格)3.命令行注册apache服务(不同于exe文件的安装)(以管理员身份打开cmdwin10)(管理员身份和普通用户身份区别)(在命令行中找到目标httpd.exe文件目录输入cdC:\wamp\Apache24\bin…

    2026年2月11日
    7
  • ajax回调地狱解决方案

    ajax回调地狱解决方案ajax 回调地狱解决方案

    2026年3月17日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号