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 and ValidatorAddress 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:

  1. Create a new Epoch object and store it in the epoch metadata.

  2. Record the current AppHash as the sealer AppHash of the previous epoch.

  3. Initialize the message queue for the new epoch.

  4. Reset the counter that tracks total slashed voting power during the current epoch.

  5. Store the top validators with the highest voting power (retrieved from the staking module) in the epoch validator set.

  6. 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:

  1. Retrieve all queued staking messages stored during this epoch.

  2. Forward each message to the corresponding handler in the staking module.

  3. Emit events related to the execution results of these messages.

  4. Call the ApplyAndReturnValidatorSetUpdates function from the staking module to update the validator set.

  5. 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:

  1. Identify the Epoch metadata associated with the newly finalized checkpoint.

  2. Retrieve the timestamp of the last block in that epoch.

  3. 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.

Zellic © 2025Back to top ↑