Module: checkpointing
Description
Babylon checkpoints record the state of the Babylon chain at the end of a specific epoch. These checkpoints are created to be included in the BTC Network as a measure to protect the Babylon chain and connected chains from long-range attacks. If blocks in the BTC Network with sufficient resistance to reorg include data related to the checkpoint, it provides an immutable record of the Babylon state up to the epoch in which the checkpoint was created. This also helps determine the valid main branch of the Babylon chain.
A checkpoint contains a unique committed identifier and the BLS signatures of the validator set corresponding to that state. BLS signatures were chosen for their ability to aggregate signatures, allowing checkpoints to remain verifiable and compact. To enable this, each validator must maintain a BLS key pair and register their BLS public key on the Babylon chain. Validators use their BLS private keys to sign the last block ID of the epoch and submit their signatures via the ABCI++ vote-extension interface. Valid BLS signatures are aggregated into the checkpoint included in the next block proposal. Prior to , BLS private keys were stored unencrypted at rest; subsequently, they are stored in a passphrase-protected ERC-2335 keystore file, with the migrate-bls-key
command added to convert to the new format.
Once a valid checkpoint is created, it is committed to the Bitcoin ledger via an off-chain program called the vigilante submitter. This program constructs Bitcoin transactions with outputs using OP_RETURN
script codes to include checkpoint data in the Bitcoin ledger. Due to OP_RETURN
's data-size limitations, two transactions are generated to include the entire checkpoint data. Once included, another off-chain program, the vigilante reporter, submits inclusion proofs to the btccheckpoint module, which monitors confirmation status and reports it to the checkpointing module. If two conflicting checkpoints with valid BLS multi-signatures are observed, it indicates a fork, and a warning is raised. In such cases, the checkpoint included first in the Bitcoin ledger determines the valid main branch of the Babylon chain.
Messages
MsgWrappedCreateValidator
This message wraps the Cosmos SDK MsgCreateValidator
with a BLS public key. It is used to register new validators on the Babylon chain and store their BLS public keys.
When a Babylon node receives MsgWrappedCreateValidator
, it checks the following conditions:
The signer of the
MsgWrappedCreateValidator
is verified.The ownership of the BLS public key included in the message is verified.
The same BLS public key cannot be registered by multiple validators, and a single validator cannot register more than one BLS public key.
If all conditions are met, the message performs the following steps:
Extract and validate the underlying
MsgCreateValidator
.Extract the BLS public key and store it in both the address-to-key and key-to-address mappings.
Add the
MsgCreateValidator
to a designated queue in the epoching module.The epoching module processes the messages in the queue during the last block of the current epoch, effectively blocking the default Cosmos SDK staking-module messages (such as
MsgCreateValidator
,MsgDelegate
,MsgUndelegate
,MsgBeginRedelegate
, andMsgCancelUnbondingDelegation
) from executing normally via the AnteHandler.
ABCI++ handler
These handlers support the voting process for Babylon checkpoints and are called in the following sequence:
ExtendVote
(executed in the last block of the previous epoch)VerifyVoteExtension
(executed in the last block of the previous epoch)PrepareProposal
(executed in the first block of the current epoch)ProcessProposal
(executed in the first block of the current epoch)PreBlock
(executed in the first block of the current epoch)BeginBlock
(executed in the first block of the current epoch)
ExtendVote
The ExtendVote
function is invoked during the final voting phase of CometBFT consensus in the last block of the epoch. It checks 1) whether the signer of the vote is part of the current epoch's validator set and 2) whether the validator can correctly sign the block ID and epoch number using its BLS key.
If these checks succeed, ExtendVote
generates a vote extension containing the BLS signature, attaching it to the validator's precommit vote.
VerifyVoteExtension
The VerifyVoteExtension
function validates the vote extensions created by other validators. It checks the following:
The epoch number in the vote extension matches the current epoch.
The validator address sending the vote extension matches the address embedded in the BLS signature.
The current block hash in
VerifyVoteExtension
matches the block hash referenced by the BLS signature in the vote extension.The BLS signature itself is valid.
If all checks pass, the vote extension is considered valid and is included in the list passed to the PrepareProposal
function of the subsequent block.
PrepareProposal
When the proposed block is the first block of the next epoch, the validator chosen as the proposer by CometBFT gathers the valid vote extensions from the previous block, constructs a checkpoint, and includes it as the first transaction in the block.
ProcessProposal
The ProcessProposal
function evaluates the integrity of the block that includes the checkpoint transaction created in PrepareProposal
. If the block is the first block of the next epoch, it checks the following:
Whether the first transaction in the block corresponds to a checkpoint
Whether the vote extensions within the checkpoint match the data collected from the previous epoch
Whether each BLS signature is valid when referencing the block ID from the prior epoch
Whether the cumulative voting power of the validators who signed the vote extensions exceeds two-thirds of the total epoch voting power
If these conditions are satisfied, the checkpoint is considered valid.
PreBlock
The PreBlock
function records the checkpoint from the special transaction injected into the first block of the epoch. Since ProcessProposal
already verifies the checkpoint, PreBlock
simply persists the data to the application state without additional checks.
BeginBlock
The BeginBlock
function initializes the validator set with their BLS public keys if the proposed block is the first block of a new epoch. It is invoked immediately after PreBlock
during block finalization. This step retrieves the validator set for the epoch from the epoching module and associates each validator with its corresponding BLS public key.
Test coverage
The x/checkpointing package has high test coverage (75.0%), with the keeper module slightly lower (68.2%), while the types module remains mostly untested (7.1%).
ok github.com/babylonlabs-io/babylon/x/checkpointing 9.132s coverage: 75.0% of statements
ok github.com/babylonlabs-io/babylon/x/checkpointing/keeper 3.953s coverage: 68.2% of statements
ok github.com/babylonlabs-io/babylon/x/checkpointing/types 2.298s coverage: 7.1% of statements
Attack surface
The attack surface exposed by the checkpointing module are the wrapped x/staking validator messages — any issues in the wrapped messages that would allow an arbitrary creation of validators. Other issues include the proposal preparation/processing and the vote-extension process, which could result in nondeterminism and/or DOS in the consensus process.