访问链上时间
在需要访问基于网络的时间以进行交易时,你有多种选择。如果你需要准实时测量(在几秒内),请使用 Move 中的 Clock
模块提供的不可变时间参考。此模块的参考值会随每个网络检查点更新。如果你不需要当前时间片,可以使用 epoch_timestamp_ms
函数捕获当前时代开始的精确时刻。
sui::clock::Clock 模块
要访问提示时间戳,你必须将 sui::clock::Clock
的只读引用作为入口函数参数传递给你的交易。Clock 的实例提供在地址 0x6
,不允许创建新实例。
从 Clock
实例中使用以毫秒为单位的 Unix 时间戳
module sui::clock {
public fun timestamp_ms(clock: &Clock): u64;
}
以下示例演示了一个入口函数,该函数触发一个包含来自 Clock
的时间戳的事件:
module example::clock {
use sui::clock::{Self, Clock};
use sui::event;
struct TimeEvent has copy, drop, store {
timestamp_ms: u64
}
entry fun access(clock: &Clock) {
event::emit(TimeEvent {
timestamp_ms: clock::timestamp_ms(clock),
});
}
}
对前述入口函数的调用采用以下形式,将 0x6
作为 Clock
参数的地址传递:
sui client call --package <EXAMPLE> --module 'clock' --function 'access' --args '0x6' --gas-budget <GAS-AMOUNT>
预计 Clock
时间戳将以每 2 到 3 秒的速度更改,这是网络提交检查点的速率。
在同一交易中对 sui::clock::timestamp_ms
的连续调用始终产生相同的结果(交易被认为立即生效),但来自 Clock
的时间戳在接触相同共享对象的跨交易中是单调递增的:连续的交易看到比它们的前任时间戳大或相等。
任何需要访问 Clock
的交易都必须经过共识,因为唯一可用的实例是一个共享对象。因此,这种技术不适用于必须使用单一所有者快速路径的交易(请参阅 Epoch 时间戳,了解时间戳的单一所有者兼容源)。
使用时钟的交易必须将其视为不可变引用(而不是可变引用或值)。这可以防止争用,因为访问 Clock
的交易只能读取它,因此不需要相对于彼此进行排序。验证器拒绝签署不符合此要求的交易,包括接受 Clock
或 &mut Clock
的入口函数的软件包将无法发布。
以下函数通过手动创建 Clock
对象并操纵其时间戳来测试与 Clock
相关的代码。这仅在测试代码中才可能:
module sui::clock {
#[test_only]
public fun create_for_testing(ctx: &mut TxContext);
#[test_only]
public fun share_for_testing(clock: Clock);
#[test_only]
public fun increment_for_testing(clock: &mut Clock, tick: u64);
#[test_only]
public fun set_for_testing(clock: &mut Clock, timestamp_ms: u64);
#[test_only]
public fun destroy_for_testing(clock: Clock);
}
下一个示例呈现了一个简单的测试,创建一个 Clock,增加它,然后检查它的值:
module example::clock_tests {
use sui::clock::{Self, Clock};
use sui::tx_context;
#[test]
fun creating_a_clock_and_incrementing_it() {
let ctx = tx_context::dummy();
let clock = clock::create_for_testing(&mut ctx);
clock::increment_for_testing(&mut clock, 42);
assert!(clock::timestamp_ms(&clock) == 42, 1);
clock::set_for_testing(&mut clock, 50);
assert!(clock::timestamp_ms(&clock) == 50, 1);
clock::destroy_for_testing(clock);
}
}
时代时间戳
你可以使用以下函数访问所有交易(包括不经过共识的交易)的当前时代开始的时间戳:
module sui::tx_context {
public fun epoch_timestamp_ms(ctx: &TxContext): u64;
}
前述函数返回当前时代开始的时间点,以毫秒粒度的 Unix 时间戳形式为 u64。此值大约每 24 小时更改一次,即时代更改时。
基于 sui::test_scenario
的测试可以使用 later_epoch
(以下代码)来测试使用 epoch_timestamp_ms
(前述代码)的依赖于时间的代码:
module sui::test_scenario {
public fun later_epoch(
scenario: &mut Scenario,
delta_ms: u64,
sender: address,
): TransactionEffects;
}
later_epoch
的行为类似于 sui::test_scenario::next_epoch
(完成测试方案中的当前事务和时代),但还将时间戳增加 delta_ms
毫秒,以模拟时间的流逝。