本文介绍了在Solidity中使用block.timestamp
和block.number
来跟踪时间和区块的编程方法,并提供了相关代码示例和最佳实践。
到目前为止,我们已经能够做一些很酷的事情,但我们还未能跟踪时间的流逝。
你可以使用 block.timestamp 获取区块的 Unix 时间戳。让我们一起试试。
contract WhatTimeIsIt {
function timestamp()
public
view
returns (uint256) {
return block.timestamp;
}
}
在 Remix 中试试。
返回的数字是自 1970 年 1 月 1 日 UTC 以来的秒数,这是传统的 Unix 时间。记住,这是秒,而不是毫秒,即你的 Linux 桌面或其他编程语言可能会返回的类型。
以太坊通过区块不断推进,你获取的时间戳是验证者在生产区块时放入的时间戳。由于每 12 秒生产一个区块,因此 block.timestamp 大致会以这个数值递增。你不应信任以秒为单位的 block.timestamp,存在太多的偏差。但经过几分钟的时间,它就开始非常可靠了。
如果你想确保某人每天不会多次调用一个函数,可以使用下面这个结构
contract ExampleContract {
uint256 public lastCall;
function hasCooldown()
public {
uint256 day = 60 * 60 * 24;
require(
block.timestamp > lastCall + day,
"隔天才能调用"
);
lastCall = block.timestamp;
}
}
Solidity 有一种更简洁的方式来表示时间,而不需要那样乘以秒数。
contract ExampleContract {
uint256 public lastCall;
function hasCooldown()
public {
require(
block.timestamp > lastCall + 1 days,
"隔天才能调用"
);
lastCall = block.timestamp; // 更新最后一次调用函数的时间
}
}
事实上,秒、分钟、小时、天和星期都是有效的时间单位,这些单位都是你所需秒数的便捷缩写。如果你想知道,seconds(秒)并不能改变数值,但如果你打算用秒作为度量的时间,它增加了代码的可读性。
block.number
你也可以通过变量了解自己目前在哪个区块。希望它的作用一目了然。有人错误地通过平均区块时间乘以 block.number 来度量的时间。不要这样做。
不要用 block.number(区块号)跟踪时间,只用于强制交易顺序。
何时需要强制交易顺序?并不常见。因此如果不确定,去用 block.timestamp。
Etherscan 显示当前的区块号,如果你想目前的区块号有多大,可以在 Etherscan 上查询。
contract ExampleContract {
function whatBlockIsIt()
external
view
returns (uint256) {
return block.number;
}
}
上述的代码将告诉你当前交易发生在哪个区块。在本例中,它将动态更新。
如果你想强制某个函数在另一个函数之后(在更晚的区块中)被调用,你可以使用以下构造。
contract ExampleContract {
// 默认值为零
uint256 private calledAt;
function callMeFirst()
external {
calledAt = block.number;
}
function callMeSecond()
external {
require(
calledAt != 0 && block.number > calledAt,
"必须先调用callMeFirst()"
);
}
}
练习题目
在 Solidity 训练营中学习更多关于智能合约开发和代币标准的知识。
- 原文链接: rareskills.io/learn-soli...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!