Truffle-编写精准时间依赖测试
2019-08-13 10:57 栏目:经验之谈 来源: 查看()
当您在以太坊上构建工资单类型Dapp时,有必要编写准确的时间相关测试。
在开始之前,您需要构建的环境如下:
·您的测试框架是Truffle,Ganache + Mocha。
·尽可能准确地测试(<5秒误差范围)。
在为以太坊智能合约编写的测试中操纵时间可能会导致问题。
陷阱#1:RPC
虽然可以在Ganache中前进和后退,但有很多方法可以实现这一点。要获得准确的结果,必须使用evm_mine RPC方法,如下所示:
{
'jsonrpc':'2.0',
'method':'evm_mine',
'params': ['NUMBER_OF_SECONDS'],
'id': 1
}
advanceBlockAtTime.json
另外作为javascript的许可证:
Const advanceBlockAtTime=(time)=&gt; {
返回新的Promise((resolve,reject)=> {
web3.currentProvider.send(
{
Jsonrpc:'2.0',
方法:'evm_mine',
参数: [时间],
Id: new Date()。getTime(),
},
(错误,_)=&gt; {
如果(错误){
返回拒绝(错误);
}
Const newBlockHash=web3.eth.getBlock('latest')。hash;
返回解析(newBlockHash);
},
);
});
};
advanceBlockAtTime.js
笔记:
·如果没有NUMBER_OF_SECONDS参数,则RPC调用仅增加块高度,但不会及时跳转。
·“id”参数是可选的,但它很好。您在测试中输入的值无关紧要。还有evm_increaseTime,它添加了Ganache的“内部时钟”,以便在下一个块被挖掘时它具有时间戳偏移量。这增加了开销:
//不是你想要的
advanceTimeAndBlock=async(time)=&gt; {
等待提前时间(时间)
等待advanceBlock()
返回Promise.resolve(web3.eth.getBlock('latest'))
}
advanceTimeAndBlock.js
没错,你必须进行两次RPC调用,第一种方法只需要完成一次。
Jakub Wojciechowski提出道具并为ganache-core提供PR#13。如果没有确定性和原子方法在Ganache中及时跳跃,那么编写准确的测试将很困难。
陷阱#2:运行时间
代码本身需要时间来执行。具体来说,Javascript许可需要不可忽视的时间来解决问题。
这很明显,对吗?在为以太坊智能合约编写与时间相关的测试时,事情变得非常微妙。
考虑以下:
1.测试用例运行所需的时间
2.您希望将来跳转的秒数
3.在控制台中提交纱线运行测试时的Unix时间戳
根据这些变量,您的测试块可能会在一秒或多秒内被捕获,因此您的断言可能会被中断。
例如:
描述('流确实开始但不结束',function(){
beforeEach(async function(){
等待advanceBlockAtTime(
现在。再加(STANDARD_TIME_OFFSET)。再加(5)
.toNumber(),
);
});
描述('当提取金额在可用余额内时',function(){
Const amount=new BigNumber(5).multipliedBy(1e18).toString(10);
它('取消',async function(){
Const balance=等待this.token.balanceOf(收件人);
等待this.sablier.withdraw(streamId,amount,opts);
Const newBalance=await this.token.balanceOf(recipient);
Balance.should.be.bignumber.equal(newBalance.minus(量));
});
});
});
makeWithdrawal.js
这样做是因为它要求Sablier合同撤回先前存入的余额。 ERC-1620指定调用者可以退出的规则数。
我在块之前记录了mocha unix时间戳,并使用节点的性能时序api测量了运行测试所需的时间:
T0 1565455128964
调用sablier.withdraw取115.92673601210117毫秒。
1)退出
sablierWithdrawTest.txt
如果你添加115到156545128964,你最终得到一个以9079结尾的数字,所以秒数从8增加到9.这就是打破这个断言的原因,因为当我实际得到X + 1时我期望X的平衡。 (超过秒数=更多钱)
虽然编写可以计算另一个程序P2完成所需时间的程序P1是不可能的(参见图灵的暂停问题),但我们可以安全地假设你的beforeEach及其阻塞时间不应超过1秒。这假设您的节点实例和ganache之间的来回通信几乎是即时的,即使在运行覆盖时也是如此。
这是一个修复:
Balance.should.bignumber.satisfy(function(num){
回归(
num.isEqualTo(newBalance.minus(amount))|| num.isEqualTo(newBalance.minus(量)。再加(ONE_UNIT))
);
});
makeWithdrawalFix.js
其中ONE_UNIT是每秒分配的货币单位,根据Sablier模型。它并不完美,但它比使用“大于”或“小于”相等的检查要好。
最后,正如OpenZeppelin团队在这里所说的那样,你可能不需要这种精度。如果您的dapp与时间戳或块号没有直接关系,则容忍更大的时间偏移是完全正常的。
陷阱#3:BeforeEach和AfterEach
您的里程可能会有所不同,但您可能希望在“beforeEach”中向前跳跃并在“afterEach”中向后跳跃。这是因为您的合同可能在“describe”块的范围内定义了一些变量,并且您希望运行一系列“it”块,所有块都具有相同的状态。不回复“afterEach”只会永远增加时间戳。
例如:
描述('流确实开始但不结束',function(){
Const amount=new BigNumber(5).multipliedBy(1e18).toString(10);
beforeEach(async function(){
等待web3.utils.advanceBlockAtTime(
现在。再加(STANDARD_TIME_OFFSET)。再加(5)
.toNumber(),
);
});
它('test1',function(){});
它('test2',function(){});
它('test3',function(){});
afterEach(async function(){
等待web3.utils.advanceBlockAtTime(now.toNumber());
});
});
beforeAfterEach.js
正如你在上面的代码片段中看到的,我们有三个测试,我们假设提取的数量是5.在Sabilier的上下文中,在15秒内前进将产生15秒的可提取量,所以我们必须返回“aftereach”区块中的原始状态。
陷阱#4:快照
所有测试完成后返回原始状态。它可能对CI或其他外部环境有帮助。
takeSnapshot=async()=&gt; {
返回新的Promise((resolve,reject)=> {
web3.currentProvider.send(
{
Jsonrpc:'2.0',
方法:'evm_snapshot',
Id: new Date()。getTime(),
},
(错误,snapshotId)=> {
如果(错误){
返回拒绝(错误);
}
返回解析(snapshotId);
},
);
});
};
revertToSnapshot=async(id)=&gt; {
返回新的Promise((resolve,reject)=> {
web3.currentProvider.send(
{
Jsonrpc:'2.0',
方法:'evm_revert',
参数: [id],
Id: new Date()。getTime(),
},
(错误,结果)=> {
如果(错误){
返回拒绝(错误);
}
返回解决(结果);
},
);
});
};
snapshotFunctions.js
在代码库中定义这些函数并将它们插入根测试文件中:
让快照;
让snapshotId;
之前(async()=> {
Snapshot=等待takeSnapshot();
snapshotId=snapshot.result;
});
之后(async()=&gt; {
等待revertToSnapshot(snapshotId);
});
truffleSnapshots.js
现在,在所有神奇的时间跳跃之后,您的区块链将恢复到其原始时间戳。
本文中使用的一些零碎内容受到启发或从其他作品中获取,例如Ethan Wessel令人惊叹的“使用松露的测试时间”。本文中唯一的警告是使用evm_mine和evm_increaseTime,我们在上面解释了这是不理想的原因。
此外,这是一个非常好的StackExchange线程,具有block.timestamp和一些GitHub线程的固有安全性,它揭示了Ganache(1和2)中确定性跳时的历史。
售前客服二维码
文章均源于网络收集编辑侵删
提示:仅接受技术开发咨询!
郑重申明:资讯文章为网络收集整理,官方公告以外的资讯内容与本站无关!