Michael.W基于Foundry精读Openzeppelin第7期——Timers.sol
- 0. 版本
- 0.1 Timers.sol
- 1. 目标合约
- 2. 代码精读
- 2.1 区块链时间戳维度
- 2.1.1 Timestamp结构体
- 2.1.2 setDeadline(Timestamp storage, uint64) && getDeadline(Timestamp memory)
- 2.1.3 reset(Timestamp storage) && isUnset(Timestamp memory)
- 2.1.4 isStarted(Timestamp memory) && isPending(Timestamp memory) && isExpired(Timestamp memory)
- 2.2 区块链区块高度维度
- 2.2.1 BlockNumber结构体
- 2.2.2 setDeadline(BlockNumber storage, uint64) && getDeadline(BlockNumber memory)
- 2.2.3 reset(BlockNumber storage) && isUnset(BlockNumber memory)
- 2.2.4 isStarted(BlockNumber memory) && isPending(BlockNumber memory) && isExpired(BlockNumber memory)
0. 版本
[openzeppelin]:v4.8.3,[forge-std]:v1.5.6
0.1 Timers.sol
Github: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.3/contracts/utils/Timers.sol
Timers库是一个专门用于控制和管理有时间有效期窗口的工具库。时间有效期可以从区块链时间戳和区块高度两个维度进行管理。
1. 目标合约
封装Timers library成为一个可调用合约:
Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/src/utils/MockTimers.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "openzeppelin-contracts/contracts/utils/Timers.sol";
contract MockTimersTimestamp {
using Timers for Timers.Timestamp;
Timers.Timestamp _tt;
function getDeadline() external view returns (uint64){
return _tt.getDeadline();
}
function setDeadline(uint64 newTimestamp) external {
_tt.setDeadline(newTimestamp);
}
function reset() external {
_tt.reset();
}
function isUnset() external view returns (bool) {
return _tt.isUnset();
}
function isStarted() external view returns (bool) {
return _tt.isStarted();
}
function isPending() external view returns (bool) {
return _tt.isPending();
}
function isExpired() external view returns (bool) {
return _tt.isExpired();
}
}
contract MockTimersBlockNumber {
using Timers for Timers.BlockNumber;
Timers.BlockNumber _tb;
function getDeadline() external view returns (uint64){
return _tb.getDeadline();
}
function setDeadline(uint64 newBlockNumber) external {
_tb.setDeadline(newBlockNumber);
}
function reset() external {
_tb.reset();
}
function isUnset() external view returns (bool) {
return _tb.isUnset();
}
function isStarted() external view returns (bool) {
return _tb.isStarted();
}
function isPending() external view returns (bool) {
return _tb.isPending();
}
function isExpired() external view returns (bool) {
return _tb.isExpired();
}
}
全部foundry测试合约:
Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/test/utils/Timers.t.sol
2. 代码精读
2.1 区块链时间戳维度
2.1.1 Timestamp结构体
struct Timestamp {
// 主合约中设定的时间有效期窗口的截止时间戳,用uint64类型存储
uint64 _deadline;
}
2.1.2 setDeadline(Timestamp storage, uint64) && getDeadline(Timestamp memory)
设置和返回当前时间有效期窗口的截止时间戳。
function setDeadline(Timestamp storage timer, uint64 timestamp) internal {
// 修改Timestamp中的_deadline成员值
timer._deadline = timestamp;
}
function getDeadline(Timestamp memory timer) internal pure returns (uint64) {
// 返回Timestamp中的_deadline成员值
return timer._deadline;
}
foundry代码验证
contract TimersTest is Test {
MockTimersTimestamp mtt = new MockTimersTimestamp();
function test_SetDeadlineAndGetDeadline_ForTimestamp() external {
mtt.setDeadline(1024);
assertEq(1024, mtt.getDeadline());
}
}
2.1.3 reset(Timestamp storage) && isUnset(Timestamp memory)
-
reset(Timestamp storage)为重置截止时间戳;
-
isUnset(Timestamp memory) 为查询当前主合约的截止时间戳是否为未设置的状态,即截止时间戳是否为0。
function reset(Timestamp storage timer) internal {
// 将主合约的截止时间戳重置为0
timer._deadline = 0;
}
function isUnset(Timestamp memory timer) internal pure returns (bool) {
// 判断当前主合约的截止时间戳是否为0
return timer._deadline == 0;
}
foundry代码验证
contract TimersTest is Test {
MockTimersTimestamp mtt = new MockTimersTimestamp();
function test_ResetAndIsUnset_ForTimestamp() external {
mtt.setDeadline(1024);
assertFalse(mtt.isUnset());
mtt.reset();
assertTrue(mtt.isUnset());
assertEq(0, mtt.getDeadline());
}
}
2.1.4 isStarted(Timestamp memory) && isPending(Timestamp memory) && isExpired(Timestamp memory)
- isStarted(Timestamp memory)为该时间戳有效期管理系统是否开启。即判断当前主合约的截止时间戳是否大于0;
- isPending(Timestamp memory)为当前区块链时间是否处于有效状态;
- isExpired(Timestamp memory) 为当前区块链时间是否处于过期状态。
function isStarted(Timestamp memory timer) internal pure returns (bool) {
// 判断当前主合约的截止时间戳是否大于0
return timer._deadline > 0;
}
function isPending(Timestamp memory timer) internal view returns (bool) {
// 判断当前区块链时间戳是否小于主合约设置的截止时间戳
return timer._deadline > block.timestamp;
}
function isExpired(Timestamp memory timer) internal view returns (bool) {
// 只有当时间戳有效期管理系统处于开启状态 且 当前区块链时间戳大于等于主合约设置的截止时间戳时,才会被认作是expired。 有任何一点不满足,都会返回false。
return isStarted(timer) && timer._deadline <= block.timestamp;
}
foundry代码验证
contract TimersTest is Test {
MockTimersTimestamp mtt = new MockTimersTimestamp();
function test_IsStartedAndIsPendingAndIsExpired_ForTimestamp() external {
mtt.reset();
assertFalse(mtt.isStarted());
mtt.setDeadline(1024);
assertTrue(mtt.isStarted());
// check pending/expired status
vm.warp(1024 - 1);
assertTrue(mtt.isPending());
assertFalse(mtt.isExpired());
vm.warp(1024);
assertFalse(mtt.isPending());
assertTrue(mtt.isExpired());
vm.warp(1024 + 1);
assertFalse(mtt.isPending());
assertTrue(mtt.isExpired());
// isExpired() always returns false if unset
mtt.reset();
assertFalse(mtt.isExpired());
}
}
2.2 区块链区块高度维度
2.2.1 BlockNumber结构体
struct BlockNumber {
// 主合约中设定的时间有效期窗口的截止区块高度,用uint64类型存储
uint64 _deadline;
}
2.2.2 setDeadline(BlockNumber storage, uint64) && getDeadline(BlockNumber memory)
设置和返回当前时间有效期窗口的截止区块高度。
function getDeadline(BlockNumber memory timer) internal pure returns (uint64) {
// 返回BlockNumber中的_deadline成员值
return timer._deadline;
}
function setDeadline(BlockNumber storage timer, uint64 timestamp) internal {
// 修改BlockNumber中的_deadline成员值
timer._deadline = timestamp;
}
foundry代码验证
contract TimersTest is Test {
MockTimersBlockNumber mtb = new MockTimersBlockNumber();
function test_SetDeadlineAndGetDeadline_ForBlockNumber() external {
mtb.setDeadline(1024);
assertEq(1024, mtb.getDeadline());
}
}
2.2.3 reset(BlockNumber storage) && isUnset(BlockNumber memory)
-
reset(BlockNumber storage)为重置截止区块高度;
-
isUnset(BlockNumber memory) 为查询当前主合约的截止区块高度是否为未设置的状态,即截止区块高度是否为0。
function reset(BlockNumber storage timer) internal {
// 将主合约的截止区块高度重置为0
timer._deadline = 0;
}
function isUnset(BlockNumber memory timer) internal pure returns (bool) {
// 判断当前主合约的截止区块高度是否为0
return timer._deadline == 0;
}
foundry代码验证
contract TimersTest is Test {
MockTimersBlockNumber mtb = new MockTimersBlockNumber();
function test_ResetAndIsUnset_ForBlockNumber() external {
mtb.setDeadline(1024);
assertFalse(mtb.isUnset());
mtb.reset();
assertTrue(mtb.isUnset());
assertEq(0, mtb.getDeadline());
}
}
2.2.4 isStarted(BlockNumber memory) && isPending(BlockNumber memory) && isExpired(BlockNumber memory)
- isStarted(BlockNumber memory)为该区块高度有效期管理系统是否开启。即判断当前主合约的截止区块高度是否大于0;
- isPending(BlockNumber memory)为当前区块链区块高度是否处于有效状态;
- isExpired(BlockNumber memory) 为当前区块链区块高度是否处于过期状态。
function isStarted(BlockNumber memory timer) internal pure returns (bool) {
// 判断当前主合约的截止区块高度是否大于0
return timer._deadline > 0;
}
function isPending(BlockNumber memory timer) internal view returns (bool) {
// 判断当前区块链区块高度是否小于主合约设置的截止区块高度
return timer._deadline > block.number;
}
function isExpired(BlockNumber memory timer) internal view returns (bool) {
// 只有区块高度有效期管理系统处于开启状态 且 当前区块链区块高度大于等于主合约设置的截止区块高度时,才会被认作是expired。 有任何一点不满足,都会返回false。
return isStarted(timer) && timer._deadline <= block.number;
}
foundry代码验证
contract TimersTest is Test {
MockTimersBlockNumber mtb = new MockTimersBlockNumber();
function test_IsStartedAndIsPendingAndIsExpired_ForBlockNumber() external {
mtb.reset();
assertFalse(mtb.isStarted());
mtb.setDeadline(1024);
assertTrue(mtb.isStarted());
// check pending/expired status
vm.roll(1024 - 1);
assertTrue(mtb.isPending());
assertFalse(mtb.isExpired());
vm.roll(1024);
assertFalse(mtb.isPending());
assertTrue(mtb.isExpired());
vm.roll(1024 + 1);
assertFalse(mtb.isPending());
assertTrue(mtb.isExpired());
// isExpired() always returns false if unset
mtb.reset();
assertFalse(mtb.isExpired());
}
}
ps:
本人热爱图灵,热爱中本聪,热爱V神。
以下是我个人的公众号,如果有技术问题可以关注我的公众号来跟我交流。
同时我也会在这个公众号上每周更新我的原创文章,喜欢的小伙伴或者老伙计可以支持一下!
如果需要转发,麻烦注明作者。十分感谢!
公众号名称:后现代泼痞浪漫主义奠基人