README
¶
title: "Epochs" excerpt: "" category: 6392913957c533007128548e
Epochs
Abstract
While using the SDK, we often want to run certain code periodically. The epochs
module allows other modules to be configured such that they are 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 signalled upon such events.
Contents
Concepts
Epochs are on-chain timers that have timer ticks at specific time intervals, triggering the execution of certain logic that is constrained by a specific epoch. The purpose of the epochs
module is to provide a generalized epoch interface to other modules so that they can easily implement epochs without keeping their own code for epochs.
Every epoch has a unique identifier. Every epoch will have a start time, and an end time, where end_time = start_time + duration
.
When an epoch triggers the execution of code, that code is executed at the first block whose blocktime is greater than end_time
. It follows that the start_time
of the following epoch will be the end_time
of the previous epoch.
Stride uses three epoch identifiers as found in x/epochs/genesis.go
DAY_EPOCH
: this identifies an epoch that lasts 24 hours.STRIDE_EPOCH
: this identifies an epoch that lasts 5 minutes on local mode tesnet (although this may be changed) and longer on public testnet and mainnet, and is used in thex/stakeibc/
module as a time interval in accordance with which the Stride app chain performs certain functions, such as autocompound stakig rewards.
State
The epochs
module keeps EpochInfo
objects and modifies the information as epoch info changes.
Epochs are initialized as part of genesis initialization, and modified on begin blockers or end blockers.
Epoch information type
message EpochInfo {
string identifier = 1;
google.protobuf.Timestamp start_time = 2 [
(gogoproto.stdtime) = true,
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"start_time\""
];
google.protobuf.Duration duration = 3 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.jsontag) = "duration,omitempty",
(gogoproto.moretags) = "yaml:\"duration\""
];
int64 current_epoch = 4;
google.protobuf.Timestamp current_epoch_start_time = 5 [
(gogoproto.stdtime) = true,
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"current_epoch_start_time\""
];
bool epoch_counting_started = 6;
reserved 7;
int64 current_epoch_start_height = 8;
}
EpochInfo
keeps identifier
, start_time
,duration
, current_epoch
, current_epoch_start_time
, epoch_counting_started
, current_epoch_start_height
.
identifier
keeps epoch identification string.start_time
keeps epoch counting start time, if block time passesstart_time
,epoch_counting_started
is set.duration
keeps target epoch duration.current_epoch
keeps current active epoch number.current_epoch_start_time
keeps the start time of current epoch.epoch_number
is counted only whenepoch_counting_started
flag is set.current_epoch_start_height
keeps the start block height of current epoch.
Events
The epochs
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} |
Keeper
Keeper Functions
epochs/keeper/
module provides utility functions to manage epochs.
// Keeper is the interface for lockup module keeper
type Keeper interface {
// GetEpochInfo returns epoch info by identifier
GetEpochInfo(ctx sdk.Context, identifier string) types.EpochInfo
// SetEpochInfo set epoch info
SetEpochInfo(ctx sdk.Context, epoch types.EpochInfo)
// DeleteEpochInfo delete epoch info
DeleteEpochInfo(ctx sdk.Context, identifier string)
// IterateEpochInfo iterate through epochs
IterateEpochInfo(ctx sdk.Context, fn func(index int64, epochInfo types.EpochInfo) (stop bool))
// Get all epoch infos
AllEpochInfos(ctx sdk.Context) []types.EpochInfo
}
Hooks
// the first block whose timestamp is after the duration is counted as the end of the epoch
AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumber int64)
// new epoch is next block of epoch end block
BeforeEpochStart(ctx sdk.Context, epochIdentifier string, epochNumber int64)
The BeforeEpochStart
hook does different things depending on the identifier.
If in a day
identifier it:
- begins unbondings
- sweeps unbonded tokens to the redemption account
- cleans up old records
- creates empty epoch unbonding records for the next day
If in a stride_epoch
identifier it: 5. creates and deposits records on each host zone 6. sets withdrawal addresses 7. updates redemption rates (if the epoch coincides with the correct interval) 8. processes TRANSFER_QUEUE
deposit records to the delegation Interchain Account (if the epoch coincides with the correct interval) 9. processes DELEGATION_QUEUE
deposit records to the delegation Interchain Account (if the epoch coincides with the correct interval) 10. Query the rewards account using interchain queries, with the transfer callback to a delegation account as a staked record (if at proper interval)
How modules receive hooks
On the hook receiver functions of other modules, they need to filter epochIdentifier
and execute for only a specific epochIdentifier
.
Filtering epochIdentifier
could be in Params
of other modules so that they can be modified by governance.
Governance can change an epoch from week
to day
as needed.
Queries
epochs
module provides the below queries to check the module's state
service Query {
// EpochInfos provide running epochInfos
rpc EpochInfos(QueryEpochsInfoRequest) returns (QueryEpochsInfoResponse) {}
// CurrentEpoch provide current epoch of specified identifier
rpc CurrentEpoch(QueryCurrentEpochRequest) returns (QueryCurrentEpochResponse) {}
}
Future Improvements
Lack point using this module
In current design each epoch should be at least 2 blocks as start block should be different from endblock.
Because of this, each epoch time will be max(blocks_time x 2, epoch_duration)
.
If epoch_duration is set to 1s
, and block_time
is 5s
, actual epoch time should be 10s
.
We definitely recommend configure epoch_duration as more than 2x block_time, to use this module correctly.
If you enforce to set it to 1s, it's same as 10s - could make module logic invalid.
TODO for postlaunch: We should see if we can architect things such that the receiver doesn't have to do this filtering, and the epochs module would pre-filter for them.
Block-time drifts problem
This implementation has block time drift based on block time. For instance, we have an epoch of 100 units that ends at t=100, if we have a block at t=97 and a block at t=104 and t=110, this epoch ends at t=104. And new epoch start at t=110. There are time drifts here, for around 1-2 blocks time. It will slow down epochs.
It's going to slow down epoch by 10-20s per week when epoch duration is 1 week. This should be resolved after launch.
Documentation
¶
Index ¶
- func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState
- func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState)
- func NewHandler(k keeper.Keeper) sdk.Handler
- type AppModule
- func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock)
- func (AppModule) ConsensusVersion() uint64
- func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate
- func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage
- func (AppModule) GenerateGenesisState(simState *module.SimulationState)
- func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate
- func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier
- func (am AppModule) Name() string
- func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent
- func (AppModule) QuerierRoute() string
- func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange
- func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry)
- func (am AppModule) RegisterServices(cfg module.Configurator)
- func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry)
- func (am AppModule) Route() sdk.Route
- func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation
- type AppModuleBasic
- func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage
- func (AppModuleBasic) GetQueryCmd() *cobra.Command
- func (a AppModuleBasic) GetTxCmd() *cobra.Command
- func (AppModuleBasic) Name() string
- func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux)
- func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry)
- func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino)
- func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router)
- func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ExportGenesis ¶
ExportGenesis returns the capability module's exported genesis.
func InitGenesis ¶
InitGenesis initializes the capability module's state from a provided genesis state.
Types ¶
type AppModule ¶
type AppModule struct { AppModuleBasic // contains filtered or unexported fields }
AppModule implements the AppModule interface for the capability module.
func NewAppModule ¶
NewAppModule return a new AppModule
func (AppModule) BeginBlock ¶
func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock)
BeginBlock executes all ABCI BeginBlock logic respective to the capability module.
func (AppModule) ConsensusVersion ¶
ConsensusVersion implements AppModule/ConsensusVersion.
func (AppModule) EndBlock ¶
func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate
EndBlock executes all ABCI EndBlock logic respective to the capability module. It returns no validator updates.
func (AppModule) ExportGenesis ¶
ExportGenesis returns the capability module's exported genesis state as raw JSON bytes.
func (AppModule) GenerateGenesisState ¶
func (AppModule) GenerateGenesisState(simState *module.SimulationState)
GenerateGenesisState creates a randomized GenState of the pool-incentives module.
func (AppModule) InitGenesis ¶
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate
InitGenesis performs the capability module's genesis initialization It returns no validator updates.
func (AppModule) LegacyQuerierHandler ¶
func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier
LegacyQuerierHandler returns the capability module's Querier.
func (AppModule) ProposalContents ¶
func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent
ProposalContents doesn't return any content functions for governance proposals.
func (AppModule) QuerierRoute ¶
QuerierRoute returns the capability module's query routing key.
func (AppModule) RandomizedParams ¶
func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange
RandomizedParams creates randomized pool-incentives param changes for the simulator.
func (AppModule) RegisterInvariants ¶
func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry)
RegisterInvariants registers the capability module's invariants.
func (AppModule) RegisterServices ¶
func (am AppModule) RegisterServices(cfg module.Configurator)
RegisterServices registers a GRPC query service to respond to the module-specific GRPC queries.
func (AppModule) RegisterStoreDecoder ¶
func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry)
RegisterStoreDecoder registers a decoder for supply module's types
func (AppModule) WeightedOperations ¶
func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation
WeightedOperations returns the all the gov module operations with their respective weights.
type AppModuleBasic ¶
type AppModuleBasic struct {
// contains filtered or unexported fields
}
AppModuleBasic implements the AppModuleBasic interface for the capability module.
func NewAppModuleBasic ¶
func NewAppModuleBasic(cdc codec.Codec) AppModuleBasic
NewAppModuleBasic return a new AppModuleBasic
func (AppModuleBasic) DefaultGenesis ¶
func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage
DefaultGenesis returns the capability module's default genesis state.
func (AppModuleBasic) GetQueryCmd ¶
func (AppModuleBasic) GetQueryCmd() *cobra.Command
GetQueryCmd returns the capability module's root query command.
func (AppModuleBasic) GetTxCmd ¶
func (a AppModuleBasic) GetTxCmd() *cobra.Command
GetTxCmd returns the capability module's root tx command.
func (AppModuleBasic) Name ¶
func (AppModuleBasic) Name() string
Name returns the capability module's name.
func (AppModuleBasic) RegisterGRPCGatewayRoutes ¶
func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux)
RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module.
func (AppModuleBasic) RegisterInterfaces ¶
func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry)
RegisterInterfaces registers the module's interface types
func (AppModuleBasic) RegisterLegacyAminoCodec ¶
func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino)
RegisterLegacyAminoCodec registers a legacy amino codec
func (AppModuleBasic) RegisterRESTRoutes ¶
func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router)
RegisterRESTRoutes registers the capability module's REST service handlers.
func (AppModuleBasic) ValidateGenesis ¶
func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error
ValidateGenesis performs genesis state validation for the capability module.
Directories
¶
Path | Synopsis |
---|---|
client
|
|
Package types is a reverse proxy.
|
Package types is a reverse proxy. |