Module: epoching
Description
Babylon implements epoched staking↗ to reduce and parameterize the frequency of validator-set updates in Babylon. This reduces the frequency of Babylon sending checkpoints to Bitcoin, thereby lowering Babylon's operational costs and minimizing its footprint on Bitcoin.
In the epoched staking design, the blockchain is divided into epochs, each consisting of a fixed number of consecutive blocks. Messages that affect the validator set's stake distribution are delayed until the end of each epoch, ensuring that the validator set remains unchanged during the epoch. The epoching module is responsible for implementing this epoched staking design, which includes the following:
Tracking the current epoch number of the blockchain
Recording metadata for each epoch
Delaying the execution of messages that affect the validator set's stake distribution until the end of each epoch
Completing all unbonding requests for epochs that have a Bitcoin checkpoint with sufficient confirmations
Messages
MsgWrappedDelegate
The MsgWrappedDelegate
message wraps the MsgDelegate
message from the Cosmos SDK staking module. It is used to delegate tokens on the Babylon chain.
When a Babylon node receives MsgWrappedDelegate
, it checks the following conditions:
The specified validator exists and is valid within the staking module.
The asset denomination to be delegated is recognized by the staking module.
If these checks pass, MsgDelegate
is added to a queue that will be processed at the last block of the current epoch.
MsgWrappedUndelegate
The MsgWrappedUndelegate
message wraps the MsgUndelegate
message from the Cosmos SDK staking module. It is used to undelegate tokens on the Babylon chain.
When a Babylon node receives MsgWrappedUndelegate
, it checks the following conditions:
The specified validator exists and is valid within the staking module.
The asset denomination to be undelegated is recognized by the staking module.
There is an existing delegation record between the delegator and the validator.
The amount requested for undelegation does not exceed the current delegation amount.
If these checks pass, MsgUndelegate
is added to a queue that will be processed at the last block of the current epoch.
MsgWrappedBeginRedelegate
The MsgWrappedBeginRedelegate
message wraps the MsgBeginRedelegate
message from the Cosmos SDK staking module. It is used to redelegate tokens from one validator to another on the Babylon chain.
When a Babylon node receives MsgWrappedBeginRedelegate
, it checks the following conditions:
The validator addresses (source and destination) are valid within the staking module.
The asset denomination to be redelegated is recognized by the staking module.
There is an existing delegation record between the delegator and the source validator.
The amount requested for redelegation does not exceed the current delegation amount.
If these checks pass, MsgBeginRedelegate
is added to a queue that will be processed at the last block of the current epoch.
MsgWrappedCancelUnbondingDelegation
The MsgWrappedCancelUnbondingDelegation
message wraps the MsgCancelUnbondingDelegation
message from the Cosmos SDK staking module. It is used to cancel unbonding operations on the Babylon chain.
When a Babylon node receives MsgWrappedCancelUnbondingDelegation
, it checks the following conditions:
The provided
DelegatorAddress
andValidatorAddress
are valid within the staking module.The token amount to be removed from unbonding is greater than zero and uses the correct asset denomination.
The block height at which unbonding was initiated is greater than zero.
The asset denomination to be removed from unbonding is recognized by the staking module.
If these checks pass, MsgCancelUnbondingDelegation
is added to a queue that will be processed at the last block of the current epoch.
MsgUpdateParams
The MsgUpdateParams
message is used to update parameters of the epoching module. This message can only be executed through a governance proposal on the Babylon chain.
ABCI++ handler
In the Babylon chain, the EndBlocker
of the Cosmos SDK staking module is disabled to prevent frequent validator-set updates. Instead, the epoching module takes over the responsibilities that were originally handled by the staking module’s EndBlocker
.
At the last block of each epoch, all staking-module messages queued during the epoch are executed. At the beginning of the next epoch, the validator set is updated accordingly.
BeginBlock
The BeginBlock
function in the epoching module executes the following logic.
If the current block is the first block of the next epoch, it will do the following:
Create a new
Epoch
object and store it in the epoch metadata.Record the current
AppHash
as the sealerAppHash
of the previous epoch.Initialize the message queue for the new epoch.
Reset the counter that tracks total slashed voting power during the current epoch.
Store the top validators with the highest voting power (retrieved from the staking module) in the epoch validator set.
Execute the
AfterEpochBegins
hook and emit an event indicating that the chain has entered a new epoch.
If the current block is the last block of the current epoch, it will record the current BlockHash
as the sealer BlockHash of this epoch.
EndBlock
The EndBlock
function in the epoching module executes the following logic.
If the current block is the last block of the current epoch, it will do the following:
Retrieve all queued
staking
messages stored during this epoch.Forward each message to the corresponding handler in the staking module.
Emit events related to the execution results of these messages.
Call the
ApplyAndReturnValidatorSetUpdates
function from the staking module to update the validator set.Execute the
AfterEpochEnds
hook, which saves the relationship between this epoch and the corresponding Bitcoin block height in the state.
Hooks
AfterRawCheckpointFinalized
The epoching module subscribes to the AfterRawCheckpointFinalized
hook in the checkpointing module to manage Bitcoin-assisted unbonding.
This hook is triggered when a checkpoint becomes finalized, indicating that the checkpoint’s Bitcoin transaction has remained on the canonical Bitcoin chain for w
blocks (where w
is defined in the btccheckpoint module’s checkpoint_finalization_timeout
parameter).
Upon execution of AfterRawCheckpointFinalized
, the epoching module performs the following steps to finalize all unbonding related to that epoch:
Identify the
Epoch
metadata associated with the newly finalized checkpoint.Retrieve the timestamp of the last block in that epoch.
Notify the staking module to finalize unbonding operations (for validators and delegations) prior to that timestamp.
Test coverage
The x/epoching package has moderate test coverage (55.1%), with the keeper module slightly higher (56.1%), while the types module remains mostly untested (8.8%).
ok github.com/babylonlabs-io/babylon/x/epoching 1.759s coverage: 55.1% of statements
ok github.com/babylonlabs-io/babylon/x/epoching/keeper 23.463s coverage: 56.1% of statements
ok github.com/babylonlabs-io/babylon/x/epoching/types 1.066s coverage: 8.8% of statements
Attack surface
The messages exposed by the epoching module are delegation messages that are wrapped to eventually be sent to the x/staking module. The validations that affect regular delegation messages have to be checked against on the wrapped messages as well and their potential interactions with the epoching system. Other potential issues involve panics that could be reachable in ABCI methods that could stall the chain.