#ethereum #eth #rlp #serialization #serde #serializer-deserializer

serlp

RLP (递归长度前缀) 编码的 serde 序列化和反序列化器

2 个版本

0.3.1 2022年6月10日
0.3.0 2022年1月22日
0.2.2 2022年1月21日
0.1.4 2022年1月19日

#9 in #rlp

GPL-3.0 许可证

59KB
1K SLoC

ETH 中 RLP 编码的 (反) 序列化器

Cargo.toml

serlp = "0.3.1"
serde = { version = "1.0", features = ['derive'] }

示例

此示例展示了如何使用 serlp 编码 ETH 主网上的真实交易。

该交易是 https://api.etherscan.io/api?module=proxy&action=eth_getBlockByNumber&tag=0xa1a489&boolean=true&apikey=YourApiKeyToken 的第 #0 交易。编码数据来自 https://github.com/zhangchiqing/merkle-patricia-trie 的 README。

fn test_bn() {
    #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
    struct LegacyTx {
        nonce: u64,
        #[serde(with = "biguint")]
        gas_price: BigUint,
        gas_limit: u64,
        #[serde(with = "byte_array")]
        to: [u8; 20],
        #[serde(with = "biguint")]
        value: BigUint,
        #[serde(with = "serde_bytes")]
        data: Vec<u8>,
        #[serde(with = "biguint")]
        v: BigUint,
        #[serde(with = "biguint")]
        r: BigUint,
        #[serde(with = "biguint")]
        s: BigUint
    }

    let mut to = [0; 20];
    to.copy_from_slice(&hex::decode("a3bed4e1c75d00fa6f4e5e6922db7261b5e9acd2").unwrap());
    let bn = |s| BigUint::from_bytes_be(&hex::decode(s).unwrap());
    
    let tx = LegacyTx {
        nonce: 0xa5,
        gas_price: bn("2e90edd000"),
        gas_limit: 0x12bc2,
        to,
        value: bn("00"),
        data: hex::decode("a9059cbb0000000000000000000000008bda8b9823b8490e8cf220dc7b91d97da1c54e250000000000000000000000000000000000000000000000056bc75e2d63100000").unwrap(),
        v: bn("26"),
        r: bn("6c89b57113cf7da8aed7911310e03d49be5e40de0bd73af4c9c54726c478691b"),
        s: bn("56223f039fab98d47c71f84190cf285ce8fc7d9181d6769387e5efd0a970e2e9")
    };

    let expected = "f8ab81a5852e90edd00083012bc294a3bed4e1c75d00fa6f4e5e6922db7261b5e9acd280b844a9059cbb0000000000000000000000008bda8b9823b8490e8cf220dc7b91d97da1c54e250000000000000000000000000000000000000000000000056bc75e2d6310000026a06c89b57113cf7da8aed7911310e03d49be5e40de0bd73af4c9c54726c478691ba056223f039fab98d47c71f84190cf285ce8fc7d9181d6769387e5efd0a970e2e9";
    let encoded = to_bytes(&tx).unwrap();
    let orig: LegacyTx = from_bytes(&encoded).unwrap();

    assert_eq!(orig, tx);
    assert_eq!(hex::encode(encoded), expected);
}

不支持类型

  • bool
  • 浮点数和有符号整数
  • map
  • enum (仅反序列化)

我们在反序列化时不支持 enum,因为在序列化过程中丢失了一些关于原始值的信息(例如,变体索引)。然而,在某些特定情况下,可以通过 RlpProxy 获取枚举的 Deserialize 特性,稍后会讨论。

我们必须选择这种方法,因为在 Go 编写的 ETH 中没有 enum,而 ETH 使用 Go。将枚举视为透明层可以使我们的未来实现与 ETH 兼容。

设计原则

根据 ETH 黄皮书,所有支持的数据结构都可以表示为递归字节数组列表 或字节数组 。因此,我们可以将所有 Rust 的复合类型(例如元组、结构和列表)转换为列表。然后按照论文中所述对其进行编码。

特性

RLP Proxy

我们有一个实现了 Deserialize 特性的 RlpProxy 结构体,它仅存储反序列化后的原始 RLP 编码数据(无论其类型如何)。您可以借助它更好地控制反序列化过程。

以下是一个示例

#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
#[serde(from = "RlpProxy")]
enum Classify {
    Zero(u8),
    One(u8),
    Ten((u8, u8))
}

impl From<RlpProxy> for Classify {
    fn from(proxy: RlpProxy) -> Self {
        let raw = proxy.raw();
        let mut tree = proxy.rlp_tree();
        if tree.value_count() == 2 {
            return Classify::Ten(from_bytes(raw).unwrap())
        }

        let val = tree.next().unwrap()[0];
        match val {
            0 => Classify::Zero(0),
            1 => Classify::One(1),
            _ => panic!("Value Error.")
        }
    }
}

常用类型的 (反) 序列化器

我们为区块链中的常用类型提供了两个 (反) 序列化器。

  • biguint for num_bigint::BigUint
  • byte_array 用于 [u8; N]

在您的结构体 字段 前面放置 #[serde(with = "biguint")]#[serde(with = "byte_array")] 以使用它们。

依赖项

~1–1.6MB
~36K SLoC