Solidity 时间旅行测试失败

Solidity Time-Travel Test Failing

我正在学习 CryptoZombies 教程,但无法通过其中一项测试。测试如下:

it("zombies should be able to attack another zombie", async () => {
        let result;
        result = await contractInstance.createRandomZombie(zombieNames[0], {from: alice});
        const firstZombieId = result.logs[0].args.zombieId.toNumber();
        result = await contractInstance.createRandomZombie(zombieNames[1], {from: bob});
        const secondZombieId = result.logs[0].args.zombieId.toNumber();
        await time.increase(time.duration.days(1));
        await contractInstance.attack(firstZombieId, secondZombieId, {from: alice});
        expect(result.receipt.status).to.equal(true);
    })

基本上,创建僵尸 1,创建僵尸 2,快进一天,让僵尸 1 攻击僵尸 2(因为在僵尸创建和允许附加之间有一个冷却时间)最后断言智能合约能够被执行。

测试失败,并显示一团无用的错误消息:

  1) Contract: CryptoZombies
       zombies should be able to attack another zombie:
     Uncaught TypeError: callback is not a function
      at /home/deepsports/.nvm/versions/node/v14.18.0/lib/node_modules/truffle/build/webpack:/packages/provider/wrapper.js:107:1
      at XMLHttpRequest.request.onreadystatechange (/home/deepsports/.nvm/versions/node/v14.18.0/lib/node_modules/truffle/build/webpack:/node_modules/web3/node_modules/web3-providers-http/lib/index.js:98:1)
      at XMLHttpRequestEventTarget.dispatchEvent (/home/deepsports/.nvm/versions/node/v14.18.0/lib/node_modules/truffle/build/webpack:/node_modules/xhr2-cookies/dist/xml-http-request-event-target.js:34:1)
      at XMLHttpRequest.exports.modules.996763.XMLHttpRequest._setReadyState (/home/deepsports/.nvm/versions/node/v14.18.0/lib/node_modules/truffle/build/webpack:/node_modules/xhr2-cookies/dist/xml-http-request.js:208:1)
      at XMLHttpRequest.exports.modules.996763.XMLHttpRequest._onHttpResponseEnd (/home/deepsports/.nvm/versions/node/v14.18.0/lib/node_modules/truffle/build/webpack:/node_modules/xhr2-cookies/dist/xml-http-request.js:318:1)
      at IncomingMessage.<anonymous> (/home/deepsports/.nvm/versions/node/v14.18.0/lib/node_modules/truffle/build/webpack:/node_modules/xhr2-cookies/dist/xml-http-request.js:289:47)
      at endReadableNT (internal/streams/readable.js:1334:12)
      at processTicksAndRejections (internal/process/task_queues.js:82:21)

对于背景,我使用的是:

堆栈跟踪有点难以解析,因为在我的实际代码中没有任何行被引用。通过排除的过程,可以确认是这行代码导致了失败: await time.increase(time.duration.days(1));

调用此代码(作为教程的一部分创建):

async function increase(duration) {

    //first, let's increase time
    await web3.currentProvider.send({
        jsonrpc: "2.0",
        method: "evm_increaseTime",
        params: [duration], // there are 86400 seconds in a day
        id: new Date().getTime()
    });

    //next, let's mine a new block
    web3.currentProvider.send({
        jsonrpc: '2.0',
        method: 'evm_mine',
        params: [],
        id: new Date().getTime()
    })

}

CryptoZombies 似乎正在模拟 web3 的弃用版本(我猜他们还使用了 sendAsync - 它在 CZ tutorial,而不是在您的代码中),这可能有效。

但是,如本 GitHub issue 中所述,web3.currentProvider.send() 现在需要一个回调参数,并且无法使用 await 解析。

// no callback, fails
await web3.currentProvider.send({
    jsonrpc: "2.0",
    method: "evm_increaseTime",
    params: [duration],
    id: new Date().getTime()
});

工作解决方案:

async function increase(duration) {
    return new Promise((resolve, reject) => {
        web3.currentProvider.send({
            jsonrpc: "2.0",
            method: "evm_increaseTime",
            params: [duration],
            id: new Date().getTime()
        }, (err, result) => {
            // second call within the callback
            web3.currentProvider.send({
                jsonrpc: '2.0',
                method: 'evm_mine',
                params: [],
                id: new Date().getTime()
            }, (err, result) => {
                // need to resolve the Promise in the second callback
                resolve();
            });
        });
    });
}

注意:不要将此与其他 web3 send() 方法混淆,例如 contract.methods.foo().send(),它们可以使用 await 解析。