The BTC staking module is responsible for maintaining the set of finality providers and BTC delegations under them. This includes:
- handling requests for creating finality providers,
- handling requests for creating BTC delegations,
- handlilng requests for submitting signatures of covenant emulators,
- handling requests for unbonding BTC delegations, and
- proactively refreshing the active set of finality providers and BTC delegations.
Babylon's Bitcoin Staking protocol allows bitcoin holders to trustlessly stake their bitcoins for providing economic security to the Babylon chain and other Proof-of-Stake (PoS) blockchains, without bridging their bitcoins elsewhere. The protocol consists of the following participants:
- BTC staker (aka delegator) who delegates their bitcoins to a finality provider in order to obtain staking reward.
- Finality provider who receives bitcoin delegations and participates in the finality vote round on top of the CometBFT consensus.
- Covenant emulation committee who serves as the covenants to enforce spending conditions on bitcoins staked on Babylon.
The BTC Staking module is a major component in Babylon's BTC Staking protocol. At a high level, the participants interact with the BTC Staking module as follows:
- A finality provider registers itself on the BTC Staking module.
- A BTC staker delegates some bitcoins to the finality provider. This involves
the following steps:
- The BTC staker submits a staking transaction to Bitcoin. The staking transaction locks its bitcoins for a long period of time and specifies slashing conditions.
- The BTC staker constructs the following transactions (whose specifications
can be found here):
- a slashing transaction that can spend the staking transaction once the finality provider is slashed,
- an unbonding transaction that spends the staking transaction to start the early unbonding process, and
- an unbonding slashing transaction that can spend the unbonding transaction once the finality provider is slashed. The BTC staker pre-signs the slashing transaction and unbonding slashing transaction.
- Once the staking transaction is confirmed on Bitcoin, the BTC staker sends the staking transaction, its inclusion proof, slashing transaction, unbonding transaction, and unbonding slashing transaction to Babylon.
- The covenant committee verifies spending conditions of the staking transaction, and submits its signatures on the BTC staker's transactions. At this point, the finality provider receives bitcoins and thus voting power from the BTC delegation.
- Upon each new block, the BTC Staking module will record the voting power table of finality providers.
Babylon's Finality module will make use of the voting power table maintained in the BTC Staking module to determine the finalization status of each block, identify equivocations of finality providers, and slash BTC delegations under culpable finality providers.
A BTC staker can unbond early by signing the unbonding transaction and submitting it to Bitcoin. The BTC Staking module identifies unbonding requests through this signature reported by the BTC staking tracker daemon, and will consider the BTC delegation unbonded immediately upon such a signature.
The BTC Staking module maintains the following KV stores.
The parameter storage maintains the BTC Staking module's
parameters. The BTC Staking module's parameters are represented as a Params
object defined as follows:
// Params defines the parameters for the module.
message Params {
option (gogoproto.goproto_stringer) = false;
// covenant_pks is the list of public keys held by the covenant committee
// each PK follows encoding in BIP-340 spec on Bitcoin
repeated bytes covenant_pks = 1 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// covenant_quorum is the minimum number of signatures needed for the covenant
// multisignature
uint32 covenant_quorum = 2;
// slashing address is the address that the slashed BTC goes to
// the address is in string on Bitcoin
string slashing_address = 3;
// min_slashing_tx_fee_sat is the minimum amount of tx fee (quantified
// in Satoshi) needed for the pre-signed slashing tx
int64 min_slashing_tx_fee_sat = 4;
// min_commission_rate is the chain-wide minimum commission rate that a finality provider can charge their delegators
string min_commission_rate = 5 [
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
// slashing_rate determines the portion of the staked amount to be slashed,
// expressed as a decimal (e.g., 0.5 for 50%).
string slashing_rate = 6 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
// max_active_finality_providers is the maximum number of active finality providers in the BTC staking protocol
uint32 max_active_finality_providers = 7;
// min_unbonding_time is the minimum time for unbonding transaction timelock in BTC blocks
uint32 min_unbonding_time = 8;
}
The finality provider storage maintains all
finality providers. The key is the finality provider's Bitcoin Secp256k1 public
key in BIP-340
format, and the value is a FinalityProvider
object representing a
finality provider.
// FinalityProvider defines a finality provider
message FinalityProvider {
// description defines the description terms for the finality provider.
cosmos.staking.v1beta1.Description description = 1;
// commission defines the commission rate of the finality provider.
string commission = 2 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec"
];
// babylon_pk is the Babylon secp256k1 PK of this finality provider
cosmos.crypto.secp256k1.PubKey babylon_pk = 3;
// btc_pk is the Bitcoin secp256k1 PK of this finality provider
// the PK follows encoding in BIP-340 spec
bytes btc_pk = 4 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// pop is the proof of possession of babylon_pk and btc_pk
ProofOfPossession pop = 5;
// slashed_babylon_height indicates the Babylon height when
// the finality provider is slashed.
// if it's 0 then the finality provider is not slashed
uint64 slashed_babylon_height = 6;
// slashed_btc_height indicates the BTC height when
// the finality provider is slashed.
// if it's 0 then the finality provider is not slashed
uint64 slashed_btc_height = 7;
}
The BTC delegation storage maintains all BTC
delegations. The key is the staking transaction hash corresponding to the BTC
delegation, and the value is a BTCDelegation
object. The BTCDelegation
structure includes
information of a BTC delegation and a structure BTCUndelegation
that includes
information of its early unbonding path. The staking transaction's hash uniquely
identifies a BTCDelegation
as creating a BTC delegation requires the staker to
submit a staking transaction to Bitcoin.
// BTCDelegation defines a BTC delegation
message BTCDelegation {
// babylon_pk is the Babylon secp256k1 PK of this BTC delegation
cosmos.crypto.secp256k1.PubKey babylon_pk = 1;
// btc_pk is the Bitcoin secp256k1 PK of this BTC delegation
// the PK follows encoding in BIP-340 spec
bytes btc_pk = 2 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// pop is the proof of possession of babylon_pk and btc_pk
ProofOfPossession pop = 3;
// fp_btc_pk_list is the list of BIP-340 PKs of the finality providers that
// this BTC delegation delegates to
// If there is more than 1 PKs, then this means the delegation is restaked
// to multiple finality providers
repeated bytes fp_btc_pk_list = 4 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// start_height is the start BTC height of the BTC delegation
// it is the start BTC height of the timelock
uint64 start_height = 5;
// end_height is the end height of the BTC delegation
// it is the end BTC height of the timelock - w
uint64 end_height = 6;
// total_sat is the total amount of BTC stakes in this delegation
// quantified in satoshi
uint64 total_sat = 7;
// staking_tx is the staking tx
bytes staking_tx = 8;
// staking_output_idx is the index of the staking output in the staking tx
uint32 staking_output_idx = 9;
// slashing_tx is the slashing tx
// It is partially signed by SK corresponding to btc_pk, but not signed by
// finality provider or covenant yet.
bytes slashing_tx = 10 [ (gogoproto.customtype) = "BTCSlashingTx" ];
// delegator_sig is the signature on the slashing tx
// by the delegator (i.e., SK corresponding to btc_pk).
// It will be a part of the witness for the staking tx output.
bytes delegator_sig = 11 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340Signature" ];
// covenant_sigs is a list of adaptor signatures on the slashing tx
// by each covenant member
// It will be a part of the witness for the staking tx output.
repeated CovenantAdaptorSignatures covenant_sigs = 12;
// unbonding_time describes how long the funds will be locked either in unbonding output
// or slashing change output
uint32 unbonding_time = 13;
// btc_undelegation is the information about the early unbonding path of the BTC delegation
BTCUndelegation btc_undelegation = 14;
}
// BTCUndelegation contains the information about the early unbonding path of the BTC delegation
message BTCUndelegation {
// unbonding_tx is the transaction which will transfer the funds from staking
// output to unbonding output. Unbonding output will usually have lower timelock
// than staking output.
bytes unbonding_tx = 1;
// slashing_tx is the slashing tx for unbonding transactions
// It is partially signed by SK corresponding to btc_pk, but not signed by
// finality provider or covenant yet.
bytes slashing_tx = 2 [ (gogoproto.customtype) = "BTCSlashingTx" ];
// delegator_unbonding_sig is the signature on the unbonding tx
// by the delegator (i.e., SK corresponding to btc_pk).
// It effectively proves that the delegator wants to unbond and thus
// Babylon will consider this BTC delegation unbonded. Delegator's BTC
// on Bitcoin will be unbonded after timelock
bytes delegator_unbonding_sig = 3 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340Signature" ];
// delegator_slashing_sig is the signature on the slashing tx
// by the delegator (i.e., SK corresponding to btc_pk).
// It will be a part of the witness for the unbonding tx output.
bytes delegator_slashing_sig = 4 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340Signature" ];
// covenant_slashing_sigs is a list of adaptor signatures on the slashing tx
// by each covenant member
// It will be a part of the witness for the staking tx output.
repeated CovenantAdaptorSignatures covenant_slashing_sigs = 5;
// covenant_unbonding_sig_list is the list of signatures on the unbonding tx
// by covenant members
// It must be provided after processing undelagate message by Babylon
repeated SignatureInfo covenant_unbonding_sig_list = 6;
}
The BTC delegation index storage maintains an
index between the BTC delegator and its BTC delegations. The key is the BTC
delegator's Bitcoin secp256k1 public key in BIP-340 format, and the value is a
BTCDelegatorDelegationIndex
object that contains
staking transaction hashes of the delegator's BTC delegations.
// BTCDelegatorDelegationIndex is a list of staking tx hashes of BTC delegations from the same delegator.
message BTCDelegatorDelegationIndex {
repeated bytes staking_tx_hash_list = 1;
}
The voting power table storage maintains the voting power table of all finality providers at each height of the Babylon chain. The key is the block height concatenated with the finality provider's Bitcoin secp256k1 public key in BIP-340 format, and the value is the finality provider's voting power quantified in Satoshis.
The parameter storage maintains the parameters for the BTC staking module.
// Params defines the parameters for the module.
message Params {
option (gogoproto.goproto_stringer) = false;
// covenant_pks is the list of public keys held by the covenant committee
// each PK follows encoding in BIP-340 spec on Bitcoin
repeated bytes covenant_pks = 1 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// covenant_quorum is the minimum number of signatures needed for the covenant
// multisignature
uint32 covenant_quorum = 2;
// slashing address is the address that the slashed BTC goes to
// the address is in string on Bitcoin
string slashing_address = 3;
// min_slashing_tx_fee_sat is the minimum amount of tx fee (quantified
// in Satoshi) needed for the pre-signed slashing tx
int64 min_slashing_tx_fee_sat = 4;
// min_commission_rate is the chain-wide minimum commission rate that a finality provider can charge their delegators
string min_commission_rate = 5 [
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
// slashing_rate determines the portion of the staked amount to be slashed,
// expressed as a decimal (e.g., 0.5 for 50%).
string slashing_rate = 6 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
// max_active_finality_providers is the maximum number of active finality providers in the BTC staking protocol
uint32 max_active_finality_providers = 7;
// min_unbonding_time is the minimum time for unbonding transaction timelock in BTC blocks
uint32 min_unbonding_time = 8;
}
The BTC Staking module handles the following messages from finality providers, BTC stakers (aka delegators), and covenant emulators. The message formats are defined at proto/babylon/btcstaking/v1/tx.proto. The message handlers are defined at x/btcstaking/keeper/msg_server.go.
The MsgCreateFinalityProvider
message is used for creating a finality
provider. It is typically submitted by a finality provider via the finality
provider program.
message MsgCreateFinalityProvider {
option (cosmos.msg.v1.signer) = "signer";
string signer = 1;
// description defines the description terms for the finality provider.
cosmos.staking.v1beta1.Description description = 2;
// commission defines the commission rate of finality provider.
string commission = 3 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec"
];
// babylon_pk is the Babylon secp256k1 PK of this finality provider
cosmos.crypto.secp256k1.PubKey babylon_pk = 4;
// btc_pk is the Bitcoin secp256k1 PK of this finality provider
// the PK follows encoding in BIP-340 spec
bytes btc_pk = 5 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// pop is the proof of possession of babylon_pk and btc_pk
ProofOfPossession pop = 6;
}
where Description
is adapted from Cosmos SDK's staking module and is defined
as follows:
// Description defines a validator description.
message Description {
option (gogoproto.equal) = true;
// moniker defines a human-readable name for the validator.
string moniker = 1;
// identity defines an optional identity signature (ex. UPort or Keybase).
string identity = 2;
// website defines an optional website link.
string website = 3;
// security_contact defines an optional email for security contact.
string security_contact = 4;
// details define other optional details.
string details = 5;
}
Upon MsgCreateFinalityProvider
, a Babylon node will execute as follows:
- Verify a proof of possession indicating the ownership of both the Babylon and Bitcoin secret keys.
- Ensure the given commission rate is at least the
MinCommissionRate
in the parameters and at most 100%. - Ensure the finality provider does not exist already.
- Create a
FinalityProvider
object and save it to finality provider storage.
The MsgEditFinalityProvider
message is used for editing the information of an
existing finality provider, including the commission and the description. It
needs to be submitted by using the Babylon account registered in the finality
provider.
// MsgEditFinalityProvider is the message for editing an existing finality provider
message MsgEditFinalityProvider {
option (cosmos.msg.v1.signer) = "signer";
// NOTE: this signer needs to correspond to babylon_pk of the finality provider
string signer = 1;
// btc_pk is the Bitcoin secp256k1 PK of the finality provider to be edited
bytes btc_pk = 2;
// description defines the updated description terms for the finality provider
cosmos.staking.v1beta1.Description description = 3;
// commission defines the updated commission rate of the finality provider
string commission = 4 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec"
];
}
Upon MsgEditFinalityProvider
, a Babylon node will execute as follows:
- Validate the formats of the description.
- Ensure the given commission rate is at least the
MinCommissionRate
in the parameters and at most 100%. - Get the finality provider with the given
btc_pk
from the finality provider storage. - Ensure the address
signer
corresponds to the Babylon public keybabylon_pk
in the finality provider. - Change the
description
andcommission
in the finality provider to the values supplied in the message, and write back the finlaity provider to the finality provider storage.
The MsgCreateBTCDelegation
message is used for delegating some bitcoins to a
finality provider. It is typically submitted by a BTC delegator via the BTC
staker program.
// MsgCreateBTCDelegation is the message for creating a BTC delegation
message MsgCreateBTCDelegation {
option (cosmos.msg.v1.signer) = "signer";
string signer = 1;
// babylon_pk is the Babylon secp256k1 PK of this BTC delegation
cosmos.crypto.secp256k1.PubKey babylon_pk = 2;
// pop is the proof of possession of babylon_pk and btc_pk
ProofOfPossession pop = 3;
// btc_pk is the Bitcoin secp256k1 PK of the BTC delegator
bytes btc_pk = 4 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// fp_btc_pk_list is the list of Bitcoin secp256k1 PKs of the finality providers, if there is more than one
// finality provider pk it means that delegation is re-staked
repeated bytes fp_btc_pk_list = 5 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// staking_time is the time lock used in staking transaction
uint32 staking_time = 6;
// staking_value is the amount of satoshis locked in staking output
int64 staking_value = 7;
// staking_tx is the staking tx along with the merkle proof of inclusion in btc block
babylon.btccheckpoint.v1.TransactionInfo staking_tx = 8;
// slashing_tx is the slashing tx
// Note that the tx itself does not contain signatures, which are off-chain.
bytes slashing_tx = 9 [ (gogoproto.customtype) = "BTCSlashingTx" ];
// delegator_slashing_sig is the signature on the slashing tx by the delegator (i.e., SK corresponding to btc_pk).
// It will be a part of the witness for the staking tx output.
// The staking tx output further needs signatures from covenant and finality provider in
// order to be spendable.
bytes delegator_slashing_sig = 10 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340Signature" ];
// unbonding_time is the time lock used when funds are being unbonded. It is be used in:
// - unbonding transaction, time lock spending path
// - staking slashing transaction, change output
// - unbonding slashing transaction, change output
// It must be smaller than math.MaxUInt16 and larger that max(MinUnbondingTime, CheckpointFinalizationTimeout)
uint32 unbonding_time = 11;
// fields related to unbonding transaction
// unbonding_tx is a bitcoin unbonding transaction i.e transaction that spends
// staking output and sends it to the unbonding output
bytes unbonding_tx = 12;
// unbonding_value is amount of satoshis locked in unbonding output.
// NOTE: staking_value and unbonding_value could be different because of the difference between the fee for staking tx and that for unbonding
int64 unbonding_value = 13;
// unbonding_slashing_tx is the slashing tx which slash unbonding contract
// Note that the tx itself does not contain signatures, which are off-chain.
bytes unbonding_slashing_tx = 14 [ (gogoproto.customtype) = "BTCSlashingTx" ];
// delegator_unbonding_slashing_sig is the signature on the slashing tx by the delegator (i.e., SK corresponding to btc_pk).
bytes delegator_unbonding_slashing_sig = 15 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340Signature" ];
}
Upon MsgCreateBTCDelegation
, a Babylon node will execute as follows:
- Ensure the given unbonding time is larger than
max(MinUnbondingTime, CheckpointFinalizationTimeout)
, whereMinUnbondingTime
andCheckpointFinalizationTimeout
are module parameters from BTC Staking module and BTC Checkpoint module, respectively. - Verify a proof of possession indicating the ownership of both the Babylon and Bitcoin secret keys.
- Ensure the finality providers that the bitcoins are delegated to are known to Babylon.
- Verify the staking transaction and slashing transaction, including
- Ensure the staking transaction is not duplicated with an existing BTC delegation known to Babylon.
- Ensure the information provided in the request is consistent with the staking transaction's BTC script.
- Ensure the staking transaction is
BTCConfirmationDepth
-deep in Bitcoin, whereBTCConfirmationDepth
is a module parameter specified in the BTC Checkpoint module. - Ensure the staking transaction's timelock has more than
CheckpointFinalizationTimeout
BTC blocks left. - Verify the Merkle proof of inclusion of the staking transaction against the BTC light client.
- Ensure the staking transaction and slashing transaction are valid and consistent, as per the specification of their formats.
- Verify the Schnorr signature on the slashing transaction signed by the BTC delegator.
- Verify the unbonding transaction and unbonding slashing transaction,
including
- Ensure the unbonding transaction's input points to the staking transaction.
- Verify the Schnorr signature on the slashing path of the unbonding transaction by the BTC delegator.
- Verify the unbonding transaction and the unbonding path's slashing transaction are valid and consistent, as per the specification of their formats.
- Create a
BTCDelegation
object and save it to the BTC delegation storage and the BTC delegation index storage.
The MsgAddCovenantSigs
message is used for submitting signatures on a BTC
delegation signed by a covenant committee member. It is typically submitted by a
covenant committee member via the covenant
emulator program.
// MsgAddCovenantSigs is the message for handling signatures from a covenant member
message MsgAddCovenantSigs {
option (cosmos.msg.v1.signer) = "signer";
string signer = 1;
// pk is the BTC public key of the covenant member
bytes pk = 2 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// staking_tx_hash is the hash of the staking tx.
// It uniquely identifies a BTC delegation
string staking_tx_hash = 3;
// sigs is a list of adaptor signatures of the covenant
// the order of sigs should respect the order of finality providers
// of the corresponding delegation
repeated bytes slashing_tx_sigs = 4;
// unbonding_tx_sig is the signature of the covenant on the unbonding tx submitted to babylon
// the signature follows encoding in BIP-340 spec
bytes unbonding_tx_sig = 5 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340Signature" ];
// slashing_unbonding_tx_sigs is a list of adaptor signatures of the covenant
// on slashing tx corresponding to unbonding tx submitted to babylon
// the order of sigs should respect the order of finality providers
// of the corresponding delegation
repeated bytes slashing_unbonding_tx_sigs = 6;
}
Upon AddCovenantSigs
, a Babylon node will execute as follows:
- Ensure the given BTC delegation is known to Babylon.
- Ensure the given covenant public key is in the covenant committee.
- Verify each covenant adaptor signature on the slashing transaction. Note that each covenant adaptor signature is encrypted by a finality provider's BTC public key.
- Verify the covenant Schnorr signature on the unbonding transactions.
- Verify each covenant adaptor signature on the slashing transaction of the unbonding path.
- Add the covenant signatures to the given
BTCDelegation
in the BTC delegation storage.
The MsgBTCUndelegate
message is used for unbonding bitcoins from a given
finality provider. It is typically reported by the BTC staking
tracker
program which proactively monitors unbonding transactions on Bitcoin.
// MsgBTCUndelegate is the message for handling signature on unbonding tx
// from its delegator. This signature effectively proves that the delegator
// wants to unbond this BTC delegation
message MsgBTCUndelegate {
option (cosmos.msg.v1.signer) = "signer";
string signer = 1;
// staking_tx_hash is the hash of the staking tx.
// It uniquely identifies a BTC delegation
string staking_tx_hash = 2;
// unbonding_tx_sig is the signature of the staker on the unbonding tx submitted to babylon
// the signature follows encoding in BIP-340 spec
bytes unbonding_tx_sig = 3 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340Signature" ];
}
Upon BTCUndelegate
, a Babylon node will execute as follows:
- Ensure the given BTC delegation is still active.
- Verify the Schnorr signature on the unbonding transaction from the BTC delegator. If valid, this signature effectively proves that the BTC delegator wants to unbond this BTC delegation from Babylon.
- Add the Schnorr signature to the
BTCDelegation
in the BTC delegation storage. Babylon will consider this BTC delegation to be unbonded from now on.
The MsgUpdateParams
message is used for updating the module parameters for the
BTC Staking module. It can only be executed via a govenance proposal.
// MsgUpdateParams defines a message for updating btcstaking module parameters.
message MsgUpdateParams {
option (cosmos.msg.v1.signer) = "authority";
// authority is the address of the governance account.
// just FYI: cosmos.AddressString marks that this field should use type alias
// for AddressString instead of string, but the functionality is not yet implemented
// in cosmos-proto
string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// params defines the finality parameters to update.
//
// NOTE: All parameters must be supplied.
Params params = 2 [(gogoproto.nullable) = false];
}
The MsgSelectiveSlashingEvidence
message is used for submitting evidences for
selective slashing offences. In a selective slashing offence, the adversarial
finality provider chooses a victim BTC delegation, signs its slashing
transaction, and decrypts covenant adaptor signatures to the Schnorr signatures
using its secret key, before submitting this slashing transaction to Bitcoin. By
observing a pair of a Schnorr
signature and
an adaptor signature
from the covenant committee, anyone can extract the finality provider's secret
key due to the adaptor signature
properties.
// MsgSelectiveSlashingEvidence is the message for handling evidence of selective slashing
// launched by a finality provider
message MsgSelectiveSlashingEvidence {
option (cosmos.msg.v1.signer) = "signer";
string signer = 1;
// staking_tx_hash is the hash of the staking tx.
// It uniquely identifies a BTC delegation
string staking_tx_hash = 2;
// recovered_fp_btc_sk is the BTC SK of the finality provider who
// launches the selective slashing offence. The SK is recovered by
// using a covenant adaptor signature and the corresponding Schnorr
// signature
bytes recovered_fp_btc_sk = 3;
}
Upon MsgSelectiveSlashingEvidence
, a Babylon node will execute as follows:
- Find the BTC delegation with the given staking transaction hash.
- Ensure the BTC delegation is active or unbonding.
- Ensure the given secret key corresponds to the finality provider's public key.
- At this point, the finality provider must have done selective slashing. Thus,
slash the finality provider and emit an event
EventSelectiveSlashing
about this.
The MsgSelectiveSlashingEvidence
is typically reported by the BTC staking
tracker
program. It keeps monitoring for slashing transactions on Bitcoin. Upon each
slashing transaction, it will try to extract the finality provider's secret key.
If successful, it will construct a MsgSelectiveSlashingEvidence
message and
submit it to Babylon.
Upon BeginBlock
, the BTC Staking module will execute the following:
- Index the current BTC tip height. This will be used for determining the status of BTC delegations.
- Record the voting power table at the current height, by iterating all BTC delegations.
- If the BTC Staking protocol is activated, i.e., there exists at least 1 active BTC delegation, then record the reward distribution w.r.t. the active finality providers and active BTC delegations.
The logic is defined at x/btcstaking/abci.go.
The BTC staking module emits a set of events as follows. The events are defined
at proto/babylon/btcstaking/v1/events.proto
.
// EventNewFinalityProvider is the event emitted when a finality provider is created
message EventNewFinalityProvider { FinalityProvider fp = 1; }
// EventNewBTCDelegation is the event emitted when a BTC delegation is created
// NOTE: the BTC delegation is not active thus does not have voting power yet
// only after it receives a covenant signature it becomes activated and has voting power
message EventNewBTCDelegation { BTCDelegation btc_del = 1; }
// EventActivateBTCDelegation is the event emitted when covenant activates a BTC delegation
// such that the BTC delegation starts to have voting power in its timelock period
message EventActivateBTCDelegation { BTCDelegation btc_del = 1; }
// EventUnbondingBTCDelegation is the event emitted when an unbonding BTC delegation
// receives all signatures needed for becoming unbonded
message EventUnbondedBTCDelegation {
// btc_pk is the Bitcoin secp256k1 PK of this BTC delegation
// the PK follows encoding in BIP-340 spec
bytes btc_pk = 1 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// fp_btc_pk_list is the list of BIP-340 PKs of the finality providers that
// this BTC delegation delegates to
// If there is more than 1 PKs, then this means the delegation is restaked
// to multiple finality providers
repeated bytes fp_btc_pk_list = 2 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// staking_tx_hash is the hash of the staking tx.
// (fp_pks..., del_pk, staking_tx_hash) uniquely identifies a BTC delegation
string staking_tx_hash = 3;
// unbonding_tx_hash is the hash of the unbonding tx.
string unbonding_tx_hash = 4;
// from_state is the last state the BTC delegation was at
BTCDelegationStatus from_state = 5;
}
// EventSelectiveSlashing is the event emitted when an adversarial
// finality provider selectively slashes a BTC delegation. This will
// result in slashing of all BTC delegations under this finality provider.
message EventSelectiveSlashing {
// evidence is the evidence of selective slashing
SelectiveSlashingEvidence evidence = 1;
}
// SelectiveSlashingEvidence is the evidence that the finality provider
// selectively slashed a BTC delegation
// NOTE: it's possible that a slashed finality provider exploits the
// SelectiveSlashingEvidence endpoint while it is actually slashed due to
// equivocation. But such behaviour does not affect the system's security
// or gives any benefit for the adversary
message SelectiveSlashingEvidence {
// staking_tx_hash is the hash of the staking tx.
// It uniquely identifies a BTC delegation
string staking_tx_hash = 1;
// fp_btc_pk is the BTC PK of the finality provider who
// launches the selective slashing offence
bytes fp_btc_pk = 2 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// recovered_fp_btc_sk is the finality provider's BTC SK recovered from
// the covenant adaptor/Schnorr signature pair. It is the consequence
// of selective slashing.
bytes recovered_fp_btc_sk = 3;
}
The BTC staking module provides a set of queries about the status of finality providers and BTC delegations, listed at docs.babylonchain.io.