说明
RLP (递归长度前缀)提供了一种适用于任意二进制数据数组的编码,RLP已经成为以太坊中对对象进行序列化的主要编码方式。
实现原理
RLP 编码会对字符串和列表进行序列化操作,具体的编码流程如下图:
当然,目前在Web3中的python库和Javascript库中已经集成了RLP的编码方法。
交易数据编码
根据how-to-build-a-simple-transaction的说明,以太坊中的交易数据的逻辑结构如下所示:
1 | ----------------------------- |
需要注意的是:这仅仅只是逻辑结构,实际上的交易数据都是经过RLP编码之后得到的数据,所以实际的数据会比这些逻辑数据更长(具体原因参考RLP的原理)
以一个简单的转账交易为例来做说明:0x14a298c1eea89f42285948b7d51eeac2876ca7406c9784b9b90dd3591d156d64
通过getRawTx,我们可以看到实际的交易数据是:
1 | 0xf86b80850ba43b7400825208947917bc33eea648809c285607579c9919fb864f8f8703baf82d03a0008025a0067940651530790861714b2e8fd8b080361d1ada048189000c07a66848afde46a069b041db7c29dbcc6becf42017ca7ac086b12bd53ec8ee494596f790fb6a0a69 |
通过ethereumdecoder, 解析得到对应的交易数据是:
1 | { |
对比在区块链浏览器中的数据:
两者是完全一致的。
得到这些原始的交易数据,我们尝试通过RLP还原为原来原始的交易数据:
1 | import rlp |
最终输出的结果是:
1 | 80850ba43b740082520894cce5fd90eabab3d5d35119eed7f2ac5796e3d06c8703baf82d03a0008025a0067940651530790861714b2e8fd8b080361d1ada048189000c07a66848afde46a069b041db7c29dbcc6becf42017ca7ac086b12bd53ec8ee494596f790fb6a0a69 |
和预期的一直,说明我们通过python编码最终和实际的交易数据一致,也说明我们的逻辑是正确的。
编解码交易数据
发送交易有两个步骤:
- 对交易元数据使用
RLP编码 - 用私钥对编码后的交易数据进行签名,签名之后数据的数据结构就会多出
r,s,v - 综合所有的交易元数据和r,s,v经过rlp编码就可以获得最终的raw_transaction
有关步骤1中的交易数据和步骤2中签名之后的交易数据,可以参考etherjs文档transactions
既然交易数据是通过RLP编码和解码的,那么我们就可以手动将交易数据编码或者是对已经编码后的交易数据进行解码。
编码交易数据
1 | let transaction = { |
得到编码后的交易数据是:
1 | 0x02f847827a690185012a05f2008504a817c8008255f09470997970c51812dc3a010c7d01b50e0d17dc79c8881bc16d674ec8000094e0a293e08f72454ced99e1769c3ebd21fd2c20a1c0 |
然后,我们使用私钥对这个交易数据进行签名和RLP编码:
1 | let wallet = new ethers.Wallet(privateKey) |
其中的signTransaction对编码后的交易数据(transaction)同时进行了签名和RLP编码,最终得到了签名之后的raw_transaction是:
1 | 0x02f88a827a690185012a05f2008504a817c8008255f09470997970c51812dc3a010c7d01b50e0d17dc79c8881bc16d674ec8000094e0a293e08f72454ced99e1769c3ebd21fd2c20a1c001a00d254c2662f6b1db272520fdb6b64d2402849058e89deab6c64d3b6cf2ebea4ca073460b644f90d5ccc59b3737f6e514b4ff91053756846bfbff16fa38d017a1b5 |
我们还可以严格按照先签名,后编码的方式获得raw_transaction:
参考
https://mirror.xyz/rbtree.eth/y2oMRSSKy3kI-fYL9P2nAmJUXhxV1P2x4vAy_7D9-MM