21 个不稳定版本
0.25.7 | 2024年5月15日 |
---|---|
0.25.5 | 2024年2月22日 |
0.25.4 | 2023年11月24日 |
0.25.0 | 2023年7月13日 |
0.15.3 | 2021年8月31日 |
#5 in #expectation
617 个月下载量
410KB
8K SLoC
这个 crate 允许使用有限数量的支持 RPC 调用来模拟以太坊节点,使您能够模拟以太坊合约。
使用 Mock::deploy
函数创建一个新的部署。
使用 Contract::expect_transaction
和 Contract::expect_call
配置合约的行为。
最后,通过调用 Contract::instance
创建一个 ethcontract 的 实例
,然后在测试中使用该实例。
示例
让我们模拟 solidity 示例中的投票合约。
首先,我们创建一个模拟节点并部署一个新的模拟合约
let mock = Mock::new(/* chain_id = */ 1337);
let contract = mock.deploy(abi);
然后我们设置方法调用的期望
// We'll need to know method signatures and types.
let vote: Signature<(U256,), ()> = [1, 33, 185, 63].into();
let winning_proposal: Signature<(), U256> = [96, 159, 241, 189].into();
// We expect some transactions calling the `vote` method.
contract
.expect_transaction(vote);
// We also expect calls to `winning_proposal` that will return
// a value of `1`.
contract
.expect_call(winning_proposal)
.returns(1.into());
最后,我们创建一个动态实例并像往常一样使用它
let instance = contract.instance();
instance
.method(vote, (1.into(),))?
.from(account)
.send()
.await?;
let winning_proposal_index = instance
.view_method(winning_proposal, ())?
.call()
.await?;
assert_eq!(winning_proposal_index, 1.into());
描述期望
模拟合约具有与 mockall
crate 相似的外观。
对于测试期间期望调用的每个合约方法,调用 Contract::expect_transaction
或 Contract::expect_call
并使用诸如 returns
、times
、in_sequence
等函数设置创建的 期望
。为了提高灵活性,您可以为同一方法附加多个期望。
有关更多信息示例,请参阅 Expectation
。
与模拟合约交互
在合约行为编程完成后,您可以调用 Contract::instance
来创建 ethcontract 的 Instance
。
您也可以通过 web3
直接获取合约地址并发送 RPC 调用。
具体来说,模拟节点支持 eth_call
、eth_sendRawTransaction
和 eth_getTransactionReceipt
。
目前,模拟节点不能自行签名交易,因此不支持 eth_sendTransaction
。此外,通过 eth_sendRawTransaction
部署合约目前也不可行。
模拟生成的合约
总的来说,生成的合约与动态合约类似:它们通过 Mock::deploy
部署,并通过 Contract::expect_call
和 Contract::expect_transaction
进行配置。
您可以使用 raw_contract
函数获取生成的合约的 ABI。
生成的 方法签名 通过 signatures
函数可用。
最后,可以使用 at
方法创建类型安全的实例。
以下是一个模拟 ERC20 兼容合约的示例。
首先,我们创建一个模拟节点并部署一个新的模拟合约
ethcontract::contract!("ERC20.json");
let mock = Mock::new(/* chain_id = */ 1337);
let contract = mock.deploy(ERC20::raw_contract().abi.clone());
然后我们使用生成的方法签名设置预期
contract
.expect_transaction(ERC20::signatures().transfer())
.once()
.returns(true);
最后,我们使用模拟合约的地址与模拟节点交互
let instance = ERC20::at(&mock.web3(), contract.address());
instance
.transfer(recipient, 100.into())
.from(account)
.send()
.await?;
模拟 gas 和 gas 估算
模拟节点允许您自定义 eth_gasPrice
RPC 调用返回的值。使用 Mock::update_gas_price
设置新的 gas 价格。
目前不支持使用 eth_estimateGas
估算 gas 消耗。目前,对 eth_estimateGas
的调用始终返回 1
。
依赖关系
~15–22MB
~296K SLoC