摘要
在 SDK 中,我们经常希望按固定时间间隔运行某些代码。epochs 模块的目的,是让其他模块可以声明自己希望在每个周期收到一次信号。这样,另一个模块就可以指定它希望从 UTC 时间 x 开始,每周执行一次代码。epochs 为其他模块提供了一个通用的 epoch 接口,使它们能够在这类事件发生时轻松收到通知。
目录
概念
epochs 模块定义了按固定时间间隔执行的链上计时器。
其他 SDK 模块随后可以注册逻辑,在计时器触发时执行。
我们将两次计时器触发之间的这段时间称为一个“epoch”。
每个计时器都有唯一标识符。
每个 epoch 都会有开始时间和结束时间,其中 结束时间 = 开始时间 + 计时器间隔。
在主网上,我们目前只使用一个标识符,时间间隔为 一天。
计时器会在区块时间首次大于计时器结束时间的那个区块触发,
并将开始时间设置为上一个计时器的结束时间。(特别注意,不会设置为当前区块时间!)
这意味着,如果链停机了一段时间,你会在每个区块获得一次计时器触发,
直到计时器追赶上当前时间为止。
状态
Epochs 模块会为每个标识符保存一个EpochInfo。
其中包含对应标识符下计时器的当前状态。
它的字段会在每次计时器触发时被修改。
EpochInfo 会在创世初始化或升级逻辑中完成初始化,
并且只会在 begin blocker 中被修改。
事件
epochs 模块会发出以下事件:
BeginBlocker
| 类型 | 属性键 | 属性值 |
|---|---|---|
| epoch_start | epoch_number | {epoch\_number} |
| epoch_start | start_time | {start\_time} |
EndBlocker
| 类型 | 属性键 | 属性值 |
|---|---|---|
| epoch_end | epoch_number | {epoch\_number} |
Keepers
Keeper 函数
Epochs keeper 模块提供了一些用于管理 epoch 的工具函数。Hooks
模块如何接收 hooks
在其他模块的 hook 接收函数中,它们需要对epochIdentifier 进行过滤,只对特定的
epochIdentifier 执行逻辑。对 epochIdentifier 的过滤可以放在其他
模块的 Params 中,以便通过治理进行修改。
这是标准的开发体验示例:
Panic 隔离
如果某个 epoch hook 发生 panic,它的状态更新会被回滚,但我们仍然会继续执行剩余的 hooks。这使得可以使用更复杂的 epoch 逻辑,而不必担心状态机停止,或者导致后续模块停止执行。 这也意味着,如果你期望某个先前的 epoch hook 产生某种行为,而该 epoch hook 已经回滚,那么你的 hook 也可能出现问题。因此,在为新的 epoch hook 设计安全检查时,请务必考虑“如果前一个 hook 没有执行会怎样”。查询
Epochs 模块提供以下查询,用于检查模块状态。Epoch Infos
查询当前正在运行的 epochInfos示例示例输出:
当前 Epoch
按指定标识符查询当前 epoch示例查询当前的 在此示例中,输出为:
day epoch:Abstract
Often in the SDK, we would like to run certain code every-so often. The purpose ofepochs module is to allow other modules to set that they
would like to be signaled once every period. So another module can
specify it wants to execute code once a week, starting at UTC-time = x.
epochs creates a generalized epoch interface to other modules so that
they can easily be signaled upon such events.
Contents
Concepts
The epochs module defines on-chain timers that execute at fixed time intervals. Other SDK modules can then register logic to be executed at the timer ticks. We refer to the period in between two timer ticks as an “epoch”. Every timer has a unique identifier. Every epoch will have a start time, and an end time, whereend time = start time + timer interval.
On mainnet, we only utilize one identifier, with a time interval of one day.
The timer will tick at the first block whose block time is greater than the timer end time,
and set the start as the prior timer end time. (Notably, it’s not set to the block time!)
This means that if the chain has been down for a while, you will get one timer tick per block,
until the timer has caught up.
State
The Epochs module keeps a singleEpochInfo per identifier.
This contains the current state of the timer with the corresponding identifier.
Its fields are modified at every timer tick.
EpochInfos are initialized as part of genesis initialization or upgrade logic,
and are only modified on begin blockers.
Events
Theepochs module emits the following events:
BeginBlocker
| Type | Attribute Key | Attribute Value |
|---|---|---|
| epoch_start | epoch_number | {epoch\_number} |
| epoch_start | start_time | {start\_time} |
EndBlocker
| Type | Attribute Key | Attribute Value |
|---|---|---|
| epoch_end | epoch_number | {epoch\_number} |
Keepers
Keeper functions
Epochs keeper module provides utility functions to manage epochs.Hooks
How modules receive hooks
On hook receiver function of other modules, they need to filterepochIdentifier and only do executions for only specific
epochIdentifier. Filtering epochIdentifier could be in Params of other
modules so that they can be modified by governance.
This is the standard dev UX of this:
Panic isolation
If a given epoch hook panics, its state update is reverted, but we keep proceeding through the remaining hooks. This allows more advanced epoch logic to be used, without concern over state machine halting, or halting subsequent modules. This does mean that if there is behavior you expect from a prior epoch hook, and that epoch hook reverted, your hook may also have an issue. So do keep in mind “what if a prior hook didn’t get executed” in the safety checks you consider for a new epoch hook.Queries
The Epochs module provides the following queries to check the module’s state.Epoch Infos
Query the currently running epochInfosExampleAn example output:
Current Epoch
Query the current epoch by the specified identifierExampleQuery the current Which in this example outputs:
day epoch: