如何对链链的可验证随机函数进行本地单元测试?



上下文

在尝试建立一个基本的自托管单元测试环境(和CI)来测试Chainlink VRF随机数合约时,我在如何在本地模拟任何相关的区块链/测试网方面遇到了一些困难。

例如,我发现了这个测试Chainlinks VRF的存储库。然而,对于默认部署,它建议/需要例如来自Infura的站点的免费KOVAN_RPC_URL;"本地部署";它建议/需要来自例如Alchemy网站的免费CCD_ 2。

尝试/基线

我采用了华夫格框架中的单元测试环境,该环境被描述为:

文件结构

src____AmIRichAlready.sol
|____RandomNumberConsumer.sol
|
test____AmIRichAlready.test.ts
|____mocha.opts
package.json
tsconfig.json
waffle.json
yarn.lock

文件内容

AmIRichAlready.sol

pragma solidity ^0.6.2;
interface IERC20 {
function balanceOf(address account) external view returns (uint256);
}
contract AmIRichAlready {
IERC20 private tokenContract;
uint public richness = 1000000 * 10 ** 18;
constructor (IERC20 _tokenContract) public {
tokenContract = _tokenContract;
}
function check() public view returns (bool) {
uint balance = tokenContract.balanceOf(msg.sender);
return balance > richness;
}
// IS THIS NEEDED???
function setRichness(uint256 _richness) public {
richness = _richness;
}
}

RandomNumberConsumer.sol文件内容已经在这里的stackexange上了。

AmIRichAlready.test.ts

import {expect, use} from 'chai';
import {Contract, utils, Wallet} from 'ethers';
import {deployContract, deployMockContract, MockProvider, solidity} from 'ethereum-waffle';
import IERC20 from '../build/IERC20.json';
import AmIRichAlready from '../build/AmIRichAlready.json';
use(solidity);
describe('Am I Rich Already', () => {
let mockERC20: Contract;
let contract: Contract;
let vrfContract: Contract;
let wallet: Wallet;
beforeEach(async () => {
[wallet] = new MockProvider().getWallets();
mockERC20 = await deployMockContract(wallet, IERC20.abi);
contract = await deployContract(wallet, AmIRichAlready, [mockERC20.address]);
vrfContract = await deployContract(wallet, RandomNumberConsumer);
});
it('checks if contract called balanceOf with certain wallet on the ERC20 token', async () => {
await mockERC20.mock.balanceOf
.withArgs(wallet.address)
.returns(utils.parseEther('999999'));
await contract.check();
expect('balanceOf').to.be.calledOnContractWith(mockERC20, [wallet.address]);
});
it('returns false if the wallet has less than 1000000 coins', async () => {
await mockERC20.mock.balanceOf
.withArgs(wallet.address)
.returns(utils.parseEther('999999'));
expect(await contract.check()).to.be.equal(false);
});
it('returns true if the wallet has at least 1000000 coins', async () => {
await mockERC20.mock.balanceOf
.withArgs(wallet.address)
.returns(utils.parseEther('1000000'));
expect(await contract.check()).to.be.equal(false);
});
});

mocha.opts

-r ts-node/register/transpile-only
--timeout 50000
--no-warnings
test/**/*.test.{js,ts}

软件包.json

{
"name": "example-dynamic-mocking-and-testing-calls",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"test": "export NODE_ENV=test && mocha",
"build": "waffle",
"lint": "eslint '{src,test}/**/*.ts'",
"lint:fix": "eslint --fix '{src,test}/**/*.ts'"
},
"devDependencies": {
"@openzeppelin/contracts": "^4.3.1",
"@types/chai": "^4.2.3",
"@types/mocha": "^5.2.7",
"@typescript-eslint/eslint-plugin": "^2.30.0",
"@typescript-eslint/parser": "^2.30.0",
"chai": "^4.3.4",
"eslint": "^6.8.0",
"eslint-plugin-import": "^2.20.2",
"ethereum-waffle": "^3.4.0",
"ethers": "^5.0.17",
"mocha": "^7.2.0",
"ts-node": "^8.9.1",
"typescript": "^3.8.3"
}
}

tsconfig.json

{
"compilerOptions": {
"declaration": true,
"esModuleInterop": true,
"lib": [
"ES2018"
],
"module": "CommonJS",
"moduleResolution": "node",
"outDir": "dist",
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"target": "ES2018"
}
// custom test in vrfContract
it('Tests if a random number is returned', async () => {
expect(await vrfContract.getRandomNumber()).to.be.equal(7);
});
}

华夫饼.json

{
"compilerType": "solcjs",
"compilerVersion": "0.6.2",
"sourceDirectory": "./src",
"outputDirectory": "./build"
}

yarn.lock文件内容有点大,而且是自动生成的,所以您可以在Waffle框架存储库中找到它。类似地,package.json可以在这里的同一个存储库中找到。

命令

也可以在这里简单地克隆具有指定文件结构的repo,并使用以下命令运行测试:

git clone git@github.com:a-t-2/chainlink.git
git clone git@github.com:a-t-2/test_vrf3.git
cd test_vrf3
sudo apt install npm
npm install
npm audit fix
npm install --save-dev ethereum-waffle
npm install @openzeppelin/contracts -D
npm i chai -D
npm i mocha -D
rm -r build
npx waffle
npx mocha
npm test

测试输出

这将测试AmIRichAlready.sol文件并输出:

Am I Rich Already
✓ checks if contract called balanceOf with certain wallet on the ERC20 token (249ms)
✓ returns false if the wallet has less than 1000000 coins (190ms)
✓ returns true if the wallet has at least 1000000 coins (159ms)
Tests if a random number is returned:
Error: cannot estimate gas; transaction may fail or may require manual gas limit (error={"name":"RuntimeError","results":{"0x0a0b028de6cf6e8446853a300061305501136cefa5f5eb3e96afd95dbd73dd92":{"error":"revert","program_counter":609,"return":"0x"}},"hashes":["0x0a0b028de6cf6e8446853a300061305501136cefa5f5eb3e96afd95dbd73dd92"],"message":"VM Exception while processing transaction: revert"}, tx={"data":"0xdbdff2c1","to":{},"from":"0x17ec8597ff92C3F44523bDc65BF0f1bE632917ff","gasPrice":{"type":"BigNumber","hex":"0x77359400"},"type":0,"nonce":{},"gasLimit":{},"chainId":{}}, code=UNPREDICTABLE_GAS_LIMIT, version=abstract-signer/5.4.1)
at Logger.makeError (node_modules/@ethersproject/logger/src.ts/index.ts:225:28)
at Logger.throwError (node_modules/@ethersproject/logger/src.ts/index.ts:237:20)
at /home/name/git/trucol/tested/new_test/test_vrf3/node_modules/@ethersproject/abstract-signer/src.ts/index.ts:301:31
at process._tickCallback (internal/process/next_tick.js:68:7)

3 passing (4s)

问题

我需要哪一组文件、文件结构和命令来自动测试getRandomNumber()契约是否返回整数(如果足够);气体";是否提供了,否则会出现错误?

我也遇到了这个问题,并通过嘲讽解决了这个问题。这是我的MockVRF坐标:

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
contract MockVRFCoordinator {
uint256 internal counter = 0;
function requestRandomWords(
bytes32,
uint64,
uint16,
uint32,
uint32
) external returns (uint256 requestId) {
VRFConsumerBaseV2 consumer = VRFConsumerBaseV2(msg.sender);
uint256[] memory randomWords = new uint256[](1);
randomWords[0] = counter;
consumer.rawFulfillRandomWords(requestId, randomWords);
counter += 1;
}
}

您可以在我的存储库中看到测试示例

要在本地进行测试,需要使用模拟拥有oracle网络的mock。因为你在本地工作,Chainlink节点不知道你的本地区块链,所以你实际上无法执行正确的VRF请求。请注意,您可以尝试部署本地Chainlink节点和本地区块链,并让它们进行对话,但它还没有得到完全支持,因此您可能会得到喜忧参半的结果。无论如何,根据您链接的hardhat入门套件,您可以在hardhat.config.js文件中将defaultNetwork设置为"hardhat",然后当您部署和运行集成测试(纱线测试集成)时,它将使用mock来模拟VRF节点,并测试随机数的请求。在这里查看测试,模拟合约和链接令牌在这里部署

最新更新