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 的账户部署合约时,该账户将接收该地址。通过显式声明新地址,而不是在场景中的某个点突然出现一个神奇的新数字,这应该使测试更具可读性。
previousBlockInfo
和currentBlockInfo
-设置或更改区块链模拟通过钩子提供给智能合约的数据。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>"
格式。from
、value
、arguments
、gasLimit
、gasPrice
——同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