跳转至

Mandos结构

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

## 顶级

场景测试文件本质上是要在模拟区块链上执行的步骤的集合。最简单的文件如下所示:

{
    "name": "example scenario file",
    "comment": "comments are nice",
    "steps": [
    ]
} 

顶级字段如下:

  • name(可选)-可以给场景命名;这对测试执行没有任何影响
  • comment(可选)——可以有一些注释;这对测试执行没有任何影响
  • steps——场景的核心。运行一个场景意味着要经历许多不同的步骤。有几种步骤类型,我们将逐一介绍。注意,这个列表中的每一项都是一个 JSON 映射,带有一个区分步骤类型的step字段。

步进类型:externalSteps

{
    "steps": [
        {
            "step": "externalSteps",
            "path": "other.json"
        }
    ]
} 

这种步骤类型对于拆分、组合和重用场景步骤非常有用。场景分支是可能的,这样做只需在两个不同的测试中重用公共部分。

这里唯一的特定字段是path,它指示包含场景步骤的 JSON 文件的相对路径。被引用的文件不需要有.scen.json扩展名,因此不需要自己是一个有效的场景。

导入的步骤将在每次导入时运行或重新运行。没有缓存。

还要注意的是,目前没有针对循环导入的保护措施。

步进类型:setState

{
    "steps": [
        {
            "step": "setState",
            "comment": "not much to comment here, but we can",
            "accounts": {
                "address:user_account": {
                    "comment": "we can comment on individual account initializations",
                    "nonce": "0",
                    "balance": "123,000,000,000",
                    "esdt": {
                        "str:MYFUNGIBLE-0001": "400,000,000,000",
                        "str:MYSFT-123456": {
                            "instances": [
                                {
                                    "nonce": "24",
                                    "balance": "1"
                                },
                                {
                                    "nonce": "25",
                                    "balance": "1",
                                    "creator": "address:other_creator_address",
                                    "royalties": "5000",
                                    "hash": "keccak256:str:other_nft_hash",
                                    "uri": [
                                        "str:www.something.com/funny.jpeg"
                                    ],
                                    "attributes": "str:other_attributes"
                                }
                            ],
                            "lastNonce": "7",
                            "roles": [
                                "ESDTRoleLocalMint",
                                "ESDTRoleLocalBurn",
                                "ESDTRoleNFTCreate",
                                "ESDTRoleNFTAddQuantity",
                                "ESDTRoleNFTBurn"
                            ],
                            "frozen": "false"
                        }
                    },
                    "username": "str:myusername.elrond",
                    "storage": {},
                    "code": ""
                },
                "sc:smart_contract_address": {
                    "nonce": "0",
                    "balance": "23,000",
                    "esdt": {
                        "str:MYFUNGIBLE-0001": "100,000,000,000",
                    },
                    "storage": {
                        "str:storage-key-1": "-5",
                        "str:storage-key-2|u32:4": ["u32:1", "u32:2", "u32:3"]
                    },
                    "code": "file:smart-contract.wasm"
                }
            },
            "newAddresses": [
                {
                    "creatorAddress": "address:creator",
                    "creatorNonce": "1234",
                    "newAddress": "sc:future_sc"
                }
            ]
        },
        {
            "step": "setState",
            "comment": "only set block info this time",
            "previousBlockInfo": {
                "blockNonce": "222",
                "blockRound": "333",
                "blockEpoch": "444"
            },
            "currentBlockInfo": {
                "blockTimestamp": "511",
                "blockNonce": "522",
                "blockRound": "533",
                "blockEpoch": "544"
            }
        }
    ]
} 

这个步骤类型用于初始化区块链模拟,或者在执行过程中重新配置它。

在任何执行之前,至少需要一个这样的步骤,因为所有的交易都需要现有的帐户来处理。

并非每次都需要它的所有部分。这些部分是:

  • comment不影响执行
  • accounts可以指定任意数量的帐户,包括用户帐户和智能合约。该帐户包含几个字段,它们都是可选的:
    • comment不影响执行
    • nonce执行开始时的账户随机数
    • balance EGLD 天平
    • 此帐户拥有的 ESDT 代币列表
      • 拥有的 ESDTs 被表示为从代币标识符到代币数据的映射
      • Mandos不验证代币标识符(密钥)。
      • 有两种表达 ESDT 值的格式:
        • 紧凑:对于可替换的代币,一个包含 ESDT 余额的字符串就足够了。
        • 完整:作为包含几个字段的地图:
          • instances是包含主代币数据的列表。每个实例都有一个惟一的代币 nonce(尽管Mandos并不强制这种惟一性)。可替换代币只能有一个 nonce 为 0 的实例。半可替换代币具有非零随机数。每个实例都有以下字段:
            • nonce
            • balance
            • creator创建 NFT 的账户地址
            • 10000 分之一的比例,代表 NFT 售价中应该转让给创作者的百分比。协议或Mandos不以任何方式强制执行这一点。
            • hash NFT 哈希
            • uri与 NFT/SFT 有关联的 URIs 列表
            • attributes可以存储任何数据的原始字节
          • lastNonce为此代币标识符最后创建的实例随机数。下一个 NFT/SFT 将会有随机数lastNonce + 1
          • roles确定当前账户如何与 ESDT 代币互动
          • 如果 ESDT 代币被配置为可冻结,它们的创建者可以冻结它们
    • username直接存储在账户 trie 中的“herotag”
    • storage用给定的键值映射初始化存储器。键和值可以是任意长度。
    • code通常以格式"code": "file:path/to/binary"提供更多关于此此处。拥有一个code使账户成为一个聪明的合约。
  • newAddresses -部署期间模拟合约地址生成。我们基本上告诉区块链 mock 在部署新合约时要生成什么地址名称。如果没有这一点,就会产生一个在开发测试时难以预测的地址。它由一个三元组列表组成:
    • creatorAddress
    • creatorNonce
    • newAddress -每当具有给定地址和 nonce 的账户部署合约时,该账户将接收该地址。通过显式声明新地址,而不是在场景中的某个点突然出现一个神奇的新数字,这应该使测试更具可读性。
  • previousBlockInfocurrentBlockInfo -设置或更改区块链模拟通过钩子提供给智能合约的数据。Mandos不做积木模型,所以这是我们在场景中模拟时间流逝的方式。字段:
    • blockTimestamp
    • blockNonce
    • blockRound
    • blockEpoch

步进类型:checkState

这一步检查区块链模拟在某一点的状态。它可以检查整个状态或部分状态。

在任何地方都是允许的,而不仅仅是作为测试的结束,所以渐进的变化可以被验证。

{
    "steps": [
        {
            "step": "checkState",
            "comment": "check that previous tx did the right thing",
            "accounts": {
                "address:user_account": {
                    "comment": "we can comment on individual account initializations",
                    "nonce": "0",
                    "balance": "*",
                    "esdt": {
                        "str:MYFUNGIBLE-0001": "*",
                        "str:MYSFT-123456": {
                            "instances": [
                                {
                                    "nonce": "24",
                                    "balance": "*"
                                },
                                {
                                    "nonce": "25",
                                    "balance": "1",
                                    "creator": "address:other_creator_address",
                                    "royalties": "5000",
                                    "hash": "keccak256:str:other_nft_hash",
                                    "uri": [
                                        "str:www.something.com/funny.jpeg"
                                    ],
                                    "attributes": "str:other_attributes"
                                }
                            ],
                            "lastNonce": "7",
                            "roles": [
                                "ESDTRoleLocalMint",
                                "ESDTRoleLocalBurn",
                                "ESDTRoleNFTCreate",
                                "ESDTRoleNFTAddQuantity",
                                "ESDTRoleNFTBurn"
                            ],
                            "frozen": "false"
                        }
                    },
                    "username": "str:myusername.elrond",
                    "storage": {},
                    "code": ""
                },
                "sc:smart_contract_address": {
                    "nonce": "0",
                    "balance": "23,000",
                    "esdt": {
                        "str:MYFUNGIBLE-0001": "100,000,000,000",
                    },
                    "storage": {
                        "str:storage-key-1": "-5",
                        "str:storage-key-2|u32:4": "*",
                        "+": ""
                    },
                    "code": "file:smart-contract.wasm"
                }
            }
        }
    ] 

字段:

  • comment(可选)-不影响执行
  • 帐户-从帐户地址到预期帐户状态的映射。它还接受可选条目"+": "",这表明在区块链模拟中可能还有这里没有提到的其他帐户。如果没有该字段,意外记帐将导致错误。每个帐户状态都有以下字段:
    • nonce -预期的 nonce 值,或"*"跳过检查
    • balance -预期 EGLD 余额,或"*"跳过检查
    • esdt -代币值列表,或"*"完全跳过检查。
      • 注意:默认情况下,除了指定的代币之外,不允许使用其他代币。要允许比指定的代币更多的代币,请添加一个"+": ""条目。
    • username -期望的用户名值,或"*"跳过检查
    • storage所有键值对必须匹配,或者"*"完全跳过检查。
      • 注意:默认情况下,除了指定的条目之外,不允许其他条目。要允许比指定条目更多的存储条目,请添加一个"+": ""条目。
    • code -预期智能合约代码,或"*"跳过检查
    • asyncCallData -该字段由异步调用以及合约何时向账户发送资金来设置

步进类型:dumpState

简单地将区块链模拟的整个状态打印到控制台。

{
    "step": "dumpState",
    "comment": "print everything to console"
} 

步进类型:scCall

{
    "steps": [
        {
            "step": "scCall",
            "txId": "tx-name-or-id",
            "comment": "just an example",
            "tx": {
                "from": "address:sender",
                "to": "sc:contract",
                "egldValue": "0",
                "esdtValue": [
                    {
                        "tokenIdentifier": "str:MYFUNGIBLE-000001",
                        "value": "250,000,000,000"
                    },
                    {
                        "tokenIdentifier": "str:MYSFT-123456",
                        "nonce": "24",
                        "value": "1"
                    }
                ]
                "function": "contractEndpoint",
                "arguments": [
                    "str:argument-1",
                    "1234",
                    "",
                    "str:a message (as bytes)"
                ],
                "gasLimit": "5,000,000",
                "gasPrice": "0"
            },
            "expect": {
                "out": [
                    "5",
                    "*"
                ],
                "status": "",
                "logs": [
                    {
                        "address": "sc:contract",
                        "endpoint": "str:contractEndpoint",
                        "topics": [
                            "str:topic-1",
                            "str:topic-2"
                        ],
                        "data": "str:log-value"
                    }
                ],
                "gas": "*",
                "refund": "*"
            }
        }
    ]
} 

此步骤模拟现有智能合约的交易。字段:

  • txId(可选)——它显示在错误消息中,帮助开发者找到产生错误结果或失败的交易。它还用于生成模拟 tx 散列。
  • comment(可选)-开发者可以提供交易的注释或描述。不影响执行。
  • tx -指定交易的细节。
    • from -账户必须存在于区块链模拟账户中
    • to -账户必须存在于区块链模拟账户中,并且必须是智能合约
    • egldValue -作为通话的一部分,要转多少 EGLD。只有可支付的功能将接受这种付款。
    • esdtValue -作为通话的一部分要转移的 ESDT 代币列表。无法同时传输 EGLD 和 ESDT。每个转移的项目都有以下字段:
      • tokenIdentifier-ESDT 代币唯一标识符
      • nonce - NFT/SFT 代币现时。对于可替换代币,nonce 是 0,并且可以省略该字段。
      • value -转账金额
    • function -合约中要调用的函数名
    • arguments -提供给 SC 函数的参数列表
    • gasLimit-SC 执行中允许的最大气体量
    • gasPrice-ERD 每单位天然气的价格。通话前,将从呼叫者余额中扣除 gasLimit x gasPrice。正常情况下,未使用的气体(x gasPrice)在执行调用后会返回给调用方。在Mandos测试中不会发生这种情况,因为这会使最终的余额更难管理。提示:Mandos允许gasPrice为零,以避免记录燃气费用。
  • expect(可选)——每笔交易都会产生一张收据,它的散列最终会出现在区块链上。收据的内容可以在这里查看。
    • out -函数可以返回任意数量的结果。这是这些结果的有序列表。
    • status -表示执行是否成功完成。状态 0 表示成功。合约中发生的所有错误将产生状态 4(“用户错误”)。
    • message(可选)-如果出现错误,合约还可以提供错误消息。这是可以检查该消息的地方,以确保发生了正确的错误。万一成功了就空了。
    • logs -合约可以保存离线日志,以后可以研究这些日志来确定合约发生了什么。在合约中,它们被称为“事件”。要跳过检查日志,可以写"logs": "*"
      • address -生成日志的智能合约地址。如果该合约反过来调用另一个合约,则它实际上可以不同于 tx 接收者。
      • identifier -一个合约可以有多个事件类型,每个事件类型都有一个标识符。在 API 中,标识符是保存的第一个主题。在 Rust 框架中,事件标识符在合约中明确指定。
      • 这些是事件参数,由合约提供。它们被编入索引,所以用户可以通过这些主题进行搜索。目前所有主题的长度都是 32 字节,但是将来可能会取消这个限制。
      • data -与主题相同,但没有索引,无法对数据进行搜索。可以是任意长度(或者有时是空的)。
    • gas -表示交易剩余的气体(gasLimit -消耗的气体)。要忽略此检查,请设置为"*"
    • 一些操作,比如释放存储空间,实际上是把 EGLD 还给调用者。要忽略此检查,设置为"*"

步进类型:scQuery

{
    "steps": [
        {
            "step": "scQuery",
            "txId": "query-id",
            "comment": "query comment",
            "tx": {
                "to": "sc:contract",
                "function": "contractView",
                "arguments": [
                    "str:argument-1",
                    "1234",
                    "",
                    "str:a message (as bytes)"
                ],
            },
            "expect": {
                "out": [
                    "5",
                    "*"
                ],
                "status": ""
            }
        }
    ]
} 

此步骤模拟来自区块链外部的虚拟机查询。它与scCall非常相似,但有几点不同:

  • 没有发送者。作为一个链外查询,没有实际的交易发生,所以发送者的概念是不重要的。在实践中,就像在真实的区块链上一样,发送者等于合约地址,所以就好像合约在调用它自己。
  • 气体无关紧要。没有天然气消耗链外。
  • 任何更改(如果有)都不会被保留。尽管如此,查询非只读的端点被认为是不好的做法。
  • 不能在查询中传输代币(EGLD 和 ESDT 都不能)。
  • 查询不会增加任何帐户随机数。

字段:

  • txId(可选)——它显示在错误消息中,帮助开发者找到产生错误结果或失败的交易。它还用于生成模拟 tx 散列。
  • comment(可选)-开发者可以提供交易的注释或描述。不影响执行。
  • tx -指定交易的细节。
    • to -账户必须存在于区块链模拟账户中,并且必须是智能合约
    • function -合约中要调用的函数名
    • arguments -提供给 SC 函数的参数列表
  • expect(可选)——每笔交易都会产生一张收据,它的散列最终会出现在区块链上。收据的内容可以在这里查看。
    • out -函数可以返回任意数量的结果。这是这些结果的有序列表。
    • status -表示执行是否成功完成。状态 0 表示成功。合约中发生的所有错误将产生状态 4(“用户错误”)。
    • message(可选)-如果出现错误,合约还可以提供错误消息。这是可以检查该消息的地方,以确保发生了正确的错误。万一成功了就空了。
    • gas -在这里可以检查消耗的气体。要忽略此检查,设置为"*"
    • 一些操作,比如释放存储空间,实际上是把 EGLD 还给调用者。要忽略此检查,设置为"*"

步进类型:scDeploy

它与scCall非常相似,但它专门用于模拟新智能合约的部署。

{
    "steps": [
        {
            "step": "scDeploy",
            "txId": "2",
            "comment": "deploy example",
            "tx": {
                "from": "address:deployer",
                "value": "123,000",
                "contractCode": "str:new contract code here",
                "arguments": [
                    "str:init-arg-1",
                    "100",
                    "",
                    "str:a message (as bytes)"
                ],
                "gasLimit": "5,000,000",
                "gasPrice": "0"
            },
            "expect": {
                "out": [],
                "status": "",
                "logs": [],
                "gas": "*",
                "refund": "0"
            }
        }
    ]
} 

这些字段是:

  • txId(可选)-同scCall
  • comment(可选)-同scCall
  • tx -与scCall相似,但有一些不同。首先,没有to字段,因为合约还不存在。也不能指定函数,在部署时总是调用init函数。我们有:
    • contractCode -新合约的代码。通常以"file:<relative path to contract binary>"格式。
    • fromvalueargumentsgasLimitgasPrice——同scCall
  • expect(可选)-同scCall

请注意:在合约部署期间不能转移 ESDT。如果您需要在部署时将 ESDTs 提供给合约,请在部署后立即发送带有scCall的 ESDTs。

步进类型:transfer

较少使用的步骤类型。模拟 EGLD 在两个帐户之间的简单转移,不涉及 VM。请注意,智能合约也允许简单转移。他们将增加智能合约余额,而不从其中调用任何功能。

{
    "steps": [
        {
            "step": "transfer",
            "txId": "3",
            "comment": "simple transfer, no VM",
            "tx": {
                "from": "address:sender",
                "to": "address:receiver",
                "egldValue": "0",
                "esdtValue": [
                    {
                        "tokenIdentifier": "str:MYFUNGIBLE-000001",
                        "value": "250,000,000,000"
                    },
                    {
                        "tokenIdentifier": "str:MYSFT-123456",
                        "nonce": "24",
                        "value": "1"
                    }
                ]
            }
        }
    ]
} 

这些字段是:

  • txId(可选)-同scCall / scDeploy
  • comment(可选)-同scCall / scDeploy
  • tx
    • from -与scCall / scDeploy相同
    • to -与scCall相同
    • egldValue - EGLD 值
    • esdtValue -与scCall相同

步进类型:validatorReward

较少使用的步骤类型。模拟由协议发送的验证器奖励。该交易没有发送方,除了增加接收方余额之外,它还增加智能合约存储器中的ELRONDrewards字段。在建立委托或其他标记合约时很有用。

{
    "steps": [
        {
            "step": "validatorReward",
            "txId": "4",
            "comment": "system send out validator rewards",
            "tx": {
                "to": "sc:delegation_contract",
                "value": "555,000,000"
            }
        }
    ]
} 

这些字段是:

  • txId(可选)-同scCall / scDeploy
  • comment(可选)-同scCall / scDeploy
  • tx
    • to
    • value


回到顶部