跳转至

Mandos复合值

原文:https://docs.elrond.com/developers/mandos-reference/values-complex

我们已经在这里讨论了简单类型的表示。对于像usizeBigUint&[u8]这样的类型的参数来说,这已经足够了,但是我们还需要以某种方式指定复杂的类型,比如定制结构或项目列表。

串联

可以使用管道运算符(|)连接多个表达式。管道操作符优先于所有操作,因此目前不可能将一个函数连接起来然后应用于整个结果。

这是短列表或小结构的理想选择。

举例
  • 一个Vec<u32>可以表示为"u32:1|u32:2|u32:3"
  • 一个(BigUint, BigUint)元组可以表示为"biguint:1|biguint:2"
  • a SimpleStruct { a: u8, b: BoxedBytes }可以表示为"u8:4|nested:str:value-b"

请注意,管道操作符只负责连接本身。你负责确保在适当的地方使用了嵌套编码。

使用 JSON 列表作为值

Mandos允许使用 JSON 列表来表达更长的值。当所表示的值本身是智能合约中的列表时,这尤其有意义。

举例
  • a Vec<u32>也可以表示为["u32:1", "u32:2", "u32:3"]
  • 一个(BigUint, BigUint)元组也可以表示为["biguint:1", "biguint:2"]
  • 一个SimpleStruct { a: u8, b: BoxedBytes }也可以表示为["u8:4", "nested:str:value-b"],虽然在这种情况下一个 JSON 映射可能更合适。

确保不要将表示为 JSON 列表的值与Mandos语法的其他元素混淆。

举例
{
            "step": "scCall",
            "txId": "echo_managed_vec_of_managed_vec",
            "tx": {
                "from": "address:an_account",
                "to": "sc:basic-features",
                "value": "0",
                "function": "echo_managed_vec_of_managed_vec",
                "arguments": [
                    [
                        "u32:3",
                        ["u32:1", "u32:2", "u32:3"],
                        "u32:0",
                        "u32:2",
                        ["u32:5", "u32:6"]
                    ]
                ],
                "gasLimit": "50,000,000",
                "gasPrice": "0"
            }
        }, 

在上面的例子中,实际上只有一个参数要传递给端点。"arguments": [ ... ]中的外括号是参数列表的Mandos语法。直接嵌套的括号表示 JSON 列表值。注意列表本身是如何包含更多列表的。它们最终都会连接成一个值。

在这个例子中,唯一的参数是0x0000000300000001000000020000000300000000000000020000000500000006

提示

我们在上面提到了开发者需要如何处理嵌套项的序列化。这实际上是一个很好的例子。端点echo_managed_vec_of_managed_vec接受一个列表列表,所以我们需要在第二层序列化列表的长度。注意长度是如何作为 JSON 字符串给出的,内容是如何作为 JSON 列表给出的;第一个"u32:3"是第一个项目的序列化长度,即["u32:1", "u32:2", "u32:3"],以此类推。

使用 JSON 地图作为值

JSON 列表对于表示一系列项目很有意义,但是对于结构来说,JSON 映射更有表现力。

规则如下:

  • Mandos将连接所有的 JSON 映射值,并去掉键。
  • 这些键需要按字母数字顺序排列,所以我们习惯用数字作为它们的前缀。JSON 中的映射键基本上是无序的,这是对值实施确定性排序的最简单方法。
  • 映射值可以是 JSON 字符串、列表或其他映射,所有Mandos值规则都以相同的方式向下应用。
举例

这是示例中实际彩票合约的节略部分。

{
    "step": "checkState",
    "accounts": {
        "sc:lottery": {
            "storage": {
                "str:lotteryInfo|nested:str:lottery_name": {
                    "0-token_identifier": "nested:str:LOTTERY-123456",
                    "1-ticket_price": "biguint:100",
                    "2-tickets-left": "u32:0",
                    "3-deadline": "u64:123,456",
                    "4-max_entries_per_user": "u32:1",
                    "5-prize_distribution": ["u32:2", "u8:75", "u8:25"],
                    "6-whitelist": ["u32:3", "address:acc1", "address:acc2", "address:acc3"],
                    "7-prize_pool": "biguint:500"
                }
            },
            "code": "file:../output/lottery-esdt.wasm"
        }
    }
} 

这转化成的 Rust 结构是:

#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)]
pub struct LotteryInfo<M: ManagedTypeApi> {
    pub token_identifier: TokenIdentifier<M>,
    pub ticket_price: BigUint<M>,
    pub tickets_left: u32,
    pub deadline: u64,
    pub max_entries_per_user: u32,
    pub prize_distribution: Vec<u8>,
    pub whitelist: Vec<Address>,
    pub prize_pool: BigUint<M>,
} 
提示

再次注意,所有包含的值都采用了嵌套编码格式:

  • 代币标识符的长度自动加上前缀nested:
  • 大整数用biguint:语法给出,它预先考虑了它们的字节长度,
  • 小整数以完整长度给出,
  • 列表的长度在开始时被显式编码,总是 4 字节(如u32)。

关于列举的一个说明

我们在 Rust 中使用两种类型的枚举:

  • 简单枚举简单编码为u8
  • 复杂枚举的编码就像结构一样,在开头添加了一个u8判别式。

Rust 代码中没有明确的判别式,它们是自动生成的。鉴别从0开始。

举例

这是 Multisig 合约测试的节略部分。

{
    "step": "checkState",
    "accounts": {
        "sc:multisig": {
            "storage": {
                "str:action_data.item|u32:3": {
                    "1-discriminant": "0x06",
                    "2-amount": "u32:0",
                    "3-code": "nested:file:../test-contracts/adder.wasm",
                    "4-code_metadata": "0x0000",
                    "5-arguments": [
                        "u32:1",
                        "u32:2|1234"
                    ]
                },
                "+": ""
            },
            "code": "file:../output/multisig.wasm"
        },
        "+": ""
    }
} 

在这个例子中,我们有一个SCDeploy:

#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)]
pub enum Action<M: ManagedTypeApi> {
    Nothing,
    AddBoardMember(ManagedAddress<M>),
    AddProposer(ManagedAddress<M>),
    RemoveUser(ManagedAddress<M>),
    ChangeQuorum(usize),
    SendEgld {
        to: ManagedAddress<M>,
        amount: BigUint<M>,
        data: BoxedBytes,
    },
    SCDeploy {
        amount: BigUint<M>,
        code: ManagedBuffer<M>,
        code_metadata: CodeMetadata,
        arguments: Vec<BoxedBytes>,
    },
    SCCall {
        to: ManagedAddress<M>,
        egld_payment: BigUint<M>,
        endpoint_name: BoxedBytes,
        arguments: Vec<BoxedBytes>,
    },
} 


回到顶部