Skip to content

Commit

Permalink
BTCStaking: generalise KVStore schema and parameters for restaking an…
Browse files Browse the repository at this point in the history
…d multisig covenant (#108)
  • Loading branch information
SebastianElvis authored Nov 20, 2023
1 parent 5d43225 commit 421a3be
Show file tree
Hide file tree
Showing 24 changed files with 829 additions and 452 deletions.
4 changes: 2 additions & 2 deletions cmd/babylond/cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const (
flagBlocksPerYear = "blocks-per-year"
flagGenesisTime = "genesis-time"
flagBlockGasLimit = "block-gas-limit"
flagCovenantPk = "covenant-pk"
flagCovenantPk = "covenant-pk" // TODO: multisig covenant
flagSlashingAddress = "slashing-address"
flagMinSlashingFee = "min-slashing-fee-sat"
flagSlashingRate = "slashing-rate"
Expand Down Expand Up @@ -75,7 +75,7 @@ func addGenesisFlags(cmd *cobra.Command) {
cmd.Flags().String(flagBaseBtcHeaderHex, "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a45068653ffff7f2002000000", "Hex of the base Bitcoin header.")
cmd.Flags().Uint64(flagBaseBtcHeaderHeight, 0, "Height of the base Bitcoin header.")
// btcstaking args
cmd.Flags().String(flagCovenantPk, btcstypes.DefaultParams().CovenantPk.MarshalHex(), "Bitcoin staking covenant public key")
cmd.Flags().String(flagCovenantPk, btcstypes.DefaultParams().CovenantPks[0].MarshalHex(), "Bitcoin staking covenant public key")
cmd.Flags().String(flagSlashingAddress, btcstypes.DefaultParams().SlashingAddress, "Bitcoin staking slashing address")
cmd.Flags().Int64(flagMinSlashingFee, 1000, "Bitcoin staking minimum slashing fee")
cmd.Flags().String(flagMinCommissionRate, "0", "Bitcoin staking validator minimum commission rate")
Expand Down
4 changes: 3 additions & 1 deletion cmd/babylond/cmd/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,10 +305,12 @@ func TestnetGenesisParams(maxActiveValidators uint32, btcConfirmationDepth uint6
genParams.BtclightclientBaseBtcHeader = *baseBtcHeaderInfo

genParams.BtcstakingParams = btcstakingtypes.DefaultParams()
genParams.BtcstakingParams.CovenantPk, err = bbn.NewBIP340PubKeyFromHex(covenantPk)
covenantPK, err := bbn.NewBIP340PubKeyFromHex(covenantPk)
if err != nil {
panic(err)
}
genParams.BtcstakingParams.CovenantPks = []bbn.BIP340PubKey{*covenantPK}
genParams.BtcstakingParams.CovenantQuorum = 1 // TODO: multisig covenant
genParams.BtcstakingParams.SlashingAddress = slashingAddress
genParams.BtcstakingParams.MinSlashingTxFeeSat = minSlashingFee
genParams.BtcstakingParams.MinCommissionRate = minCommissionRate
Expand Down
18 changes: 15 additions & 3 deletions proto/babylon/btcstaking/v1/btcstaking.proto
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,11 @@ message BTCDelegation {
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;
// val_btc_pk is the Bitcoin secp256k1 PK of the BTC validator that
// val_btc_pk_list is the list of BIP-340 PKs of the BTC validators that
// this BTC delegation delegates to
// the PK follows encoding in BIP-340 spec
bytes val_btc_pk = 4 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// If there is more than 1 PKs, then this means the delegation is restaked
// to multiple BTC validators
repeated bytes val_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;
Expand All @@ -89,6 +90,7 @@ message BTCDelegation {
// covenant_sig is the signature signature on the slashing tx
// by the covenant (i.e., SK corresponding to covenant_pk in params)
// It will be a part of the witness for the staking tx output.
// TODO: change to a set of (covenant PK, covenant adaptor signature) tuples
bytes covenant_sig = 11 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340Signature" ];

// if this object is present it menans that staker requested undelegation, and whole
Expand All @@ -115,15 +117,18 @@ message BTCUndelegation {
// covenant_slashing_sig is the signature on the slashing tx
// by the covenant (i.e., SK corresponding to covenant_pk in params)
// It must be provided after processing undelagate message by Babylon
// TODO: change to a set of (covenant PK, covenant adaptor signature) tuples
bytes covenant_slashing_sig = 4 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340Signature" ];
// covenant_unbonding_sig is the signature on the unbonding tx
// by the covenant (i.e., SK corresponding to covenant_pk in params)
// It must be provided after processing undelagate message by Babylon and after
// validator sig will be provided by validator
// TODO: change to a set of (covenant PK, covenant Schnorr signature) tuples
bytes covenant_unbonding_sig = 5 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340Signature" ];
// validator_unbonding_sig is the signature on the unbonding tx
// by the validator (i.e., SK corresponding to covenant_pk in params)
// It must be provided after processing undelagate message by Babylon
// TODO: this is no longer needed
bytes validator_unbonding_sig = 6 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340Signature" ];
}

Expand All @@ -139,11 +144,13 @@ message BTCUndelegationInfo {
// by the validator (i.e., SK corresponding to the pk of the validator that the staker delegates to)
// It must be provided after processing undelagate message by Babylon
// It will be nil if validator didn't sign it yet
// TODO: this is no longer needed
bytes validator_unbonding_sig = 2 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340Signature" ];

// covenant_unbonding_sig is the signature on the unbonding tx
// by the covenant (i.e., SK corresponding to covenant_pk in params)
// it will be nil if covenant didn't sign it yet
// TODO: change to a set of (covenant PK, covenant Schnorr signature) tuples
bytes covenant_unbonding_sig = 3 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340Signature" ];
}

Expand Down Expand Up @@ -190,3 +197,8 @@ enum BTCDelegationStatus {
ANY = 4;
}

// SignatureInfo is a BIP-340 signature together with its signer's BIP-340 PK
message SignatureInfo {
bytes pk = 1 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
bytes sig = 2 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340Signature" ];
}
14 changes: 8 additions & 6 deletions proto/babylon/btcstaking/v1/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ message EventUnbondingBTCDelegation {
// 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" ];
// val_btc_pk is the Bitcoin secp256k1 PK of the BTC validator that
// val_btc_pk_list is the list of BIP-340 PKs of the BTC validators that
// this BTC delegation delegates to
// the PK follows encoding in BIP-340 spec
bytes val_btc_pk = 2 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// If there is more than 1 PKs, then this means the delegation is restaked
// to multiple BTC validators
repeated bytes val_btc_pk_list = 2 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// staking_tx_hash is the hash of the staking tx.
// (val_pk, del_pk, staking_tx_hash) uniquely identifies a BTC delegation
string staking_tx_hash = 3;
Expand All @@ -41,10 +42,11 @@ 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" ];
// val_btc_pk is the Bitcoin secp256k1 PK of the BTC validator that
// val_btc_pk_list is the list of BIP-340 PKs of the BTC validators that
// this BTC delegation delegates to
// the PK follows encoding in BIP-340 spec
bytes val_btc_pk = 2 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// If there is more than 1 PKs, then this means the delegation is restaked
// to multiple BTC validators
repeated bytes val_btc_pk_list = 2 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// staking_tx_hash is the hash of the staking tx.
// (val_pk, del_pk, staking_tx_hash) uniquely identifies a BTC delegation
string staking_tx_hash = 3;
Expand Down
19 changes: 11 additions & 8 deletions proto/babylon/btcstaking/v1/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,31 @@ option go_package = "github.com/babylonchain/babylon/x/btcstaking/types";
message Params {
option (gogoproto.goproto_stringer) = false;

// covenant_pk is the public key of covenant
// the PK follows encoding in BIP-340 spec on Bitcoin
bytes covenant_pk = 1 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
// 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 = 2;
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
// TODO: change to satoshi per byte?
int64 min_slashing_tx_fee_sat = 3;
int64 min_slashing_tx_fee_sat = 4;
// min_commission_rate is the chain-wide minimum commission rate that a validator can charge their delegators
string min_commission_rate = 4 [
string min_commission_rate = 5 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(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 = 5 [
string slashing_rate = 6 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
// max_active_btc_validators is the maximum number of active BTC validators in the BTC staking protocol
uint32 max_active_btc_validators = 6;
uint32 max_active_btc_validators = 7;
}
5 changes: 2 additions & 3 deletions proto/babylon/btcstaking/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,9 @@ message QueryBTCDelegationResponse {
// 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" ];
// val_btc_pk is the Bitcoin secp256k1 PK of the BTC validator that
// val_btc_pk_list is the list of BIP-340 PKs of the BTC validators that
// this BTC delegation delegates to
// the PK follows encoding in BIP-340 spec
bytes val_btc_pk = 2 [ (gogoproto.customtype) = "github.com/babylonchain/babylon/types.BIP340PubKey" ];
repeated bytes val_btc_pk_list = 2 [ (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 = 3;
Expand Down
18 changes: 14 additions & 4 deletions test/e2e/btc_staking_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ func (s *BTCStakingTestSuite) Test1CreateBTCValidatorAndDelegation() {
*/
// BTC staking params, BTC delegation key pairs and PoP
params := nonValidatorNode.QueryBTCStakingParams()
// get covenant BTC PKs
covenantBTCPKs := []*btcec.PublicKey{}
for _, covenantPK := range params.CovenantPks {
covenantBTCPKs = append(covenantBTCPKs, covenantPK.MustToBTCPK())
}
// NOTE: we use the node's secret key as Babylon secret key for the BTC delegation
delBabylonSK := nonValidatorNode.SecretKey
pop, err := bstypes.NewPoP(delBabylonSK, delBTCSK)
Expand All @@ -110,8 +115,8 @@ func (s *BTCStakingTestSuite) Test1CreateBTCValidatorAndDelegation() {
r,
net,
delBTCSK,
btcVal.BtcPk.MustToBTCPK(),
params.CovenantPk.MustToBTCPK(),
[]*btcec.PublicKey{btcVal.BtcPk.MustToBTCPK()},
covenantBTCPKs,
stakingTimeBlocks,
stakingValue,
params.SlashingAddress, changeAddress.String(),
Expand Down Expand Up @@ -386,6 +391,11 @@ func (s *BTCStakingTestSuite) Test5SubmitStakerUnbonding() {

// params for covenantPk and slashing address
params := nonValidatorNode.QueryBTCStakingParams()
// get covenant BTC PKs
covenantBTCPKs := []*btcec.PublicKey{}
for _, covenantPK := range params.CovenantPks {
covenantBTCPKs = append(covenantBTCPKs, covenantPK.MustToBTCPK())
}

stakingTx := activeDel.StakingTx
stakingMsgTx, err := stakingTx.ToMsgTx()
Expand All @@ -404,8 +414,8 @@ func (s *BTCStakingTestSuite) Test5SubmitStakerUnbonding() {
r,
net,
delBTCSK,
btcVal.BtcPk.MustToBTCPK(),
params.CovenantPk.MustToBTCPK(),
[]*btcec.PublicKey{btcVal.BtcPk.MustToBTCPK()},
covenantBTCPKs,
wire.NewOutPoint(stakingTxChainHash, uint32(stakingOutputIdx)),
initialization.BabylonBtcFinalizationPeriod+1,
stakingValue-fee,
Expand Down
55 changes: 33 additions & 22 deletions testutil/datagen/btcstaking.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,29 @@ func GenRandomBTCValidatorWithBTCBabylonSKs(r *rand.Rand, btcSK *btcec.PrivateKe

func GenRandomBTCDelegation(
r *rand.Rand,
valBTCPK *bbn.BIP340PubKey,
valBTCPKs []bbn.BIP340PubKey,
delSK *btcec.PrivateKey,
covenantSK *btcec.PrivateKey,
covenantSKs []*btcec.PrivateKey,
slashingAddress, changeAddress string,
startHeight, endHeight, totalSat uint64,
slashingRate sdk.Dec,
) (*bstypes.BTCDelegation, error) {
net := &chaincfg.SimNetParams
delPK := delSK.PubKey()
delBTCPK := bbn.NewBIP340PubKeyFromBTCPK(delPK)
covenantBTCPK := covenantSK.PubKey()
valPK, err := valBTCPK.ToBTCPK()
if err != nil {
return nil, err
// list of covenant PKs
covenantBTCPKs := []*btcec.PublicKey{}
for _, covenantSK := range covenantSKs {
covenantBTCPKs = append(covenantBTCPKs, covenantSK.PubKey())
}
// list of validator PKs
valPKs := []*btcec.PublicKey{}
for _, valBTCPK := range valBTCPKs {
valPK, err := valBTCPK.ToBTCPK()
if err != nil {
return nil, err
}
valPKs = append(valPKs, valPK)
}

// BTC delegation Babylon key pairs
Expand All @@ -100,8 +109,8 @@ func GenRandomBTCDelegation(
r,
net,
delSK,
valPK,
covenantBTCPK,
valPKs,
covenantBTCPKs,
uint16(endHeight-startHeight),
int64(totalSat),
slashingAddress, changeAddress,
Expand All @@ -115,7 +124,8 @@ func GenRandomBTCDelegation(
if err != nil {
return nil, err
}
covenantSig, err := slashingTx.Sign(stakingMsgTx, stakingTx.Script, covenantSK, net)
// TODO: covenant multisig
covenantSig, err := slashingTx.Sign(stakingMsgTx, stakingTx.Script, covenantSKs[0], net)
if err != nil {
return nil, err
}
Expand All @@ -128,7 +138,7 @@ func GenRandomBTCDelegation(
BabylonPk: secp256k1PK,
BtcPk: delBTCPK,
Pop: pop,
ValBtcPk: valBTCPK,
ValBtcPkList: valBTCPKs,
StartHeight: startHeight,
EndHeight: endHeight,
TotalSat: totalSat,
Expand All @@ -144,18 +154,19 @@ func GenBTCStakingSlashingTxWithOutPoint(
btcNet *chaincfg.Params,
outPoint *wire.OutPoint,
stakerSK *btcec.PrivateKey,
validatorPK *btcec.PublicKey,
covenantPK *btcec.PublicKey,
validatorPKs []*btcec.PublicKey,
covenantPKs []*btcec.PublicKey,
stakingTimeBlocks uint16,
stakingValue int64,
slashingAddress, changeAddress string,
slashingRate sdk.Dec,
withChange bool,
) (*bstypes.BabylonBTCTaprootTx, *bstypes.BTCSlashingTx, error) {
// TODO: covenant multisig
stakingOutput, stakingScript, err := btcstaking.BuildStakingOutput(
stakerSK.PubKey(),
validatorPK,
covenantPK,
validatorPKs[0],
covenantPKs[0],
stakingTimeBlocks,
btcutil.Amount(stakingValue),
btcNet,
Expand Down Expand Up @@ -226,8 +237,8 @@ func GenBTCStakingSlashingTx(
r *rand.Rand,
btcNet *chaincfg.Params,
stakerSK *btcec.PrivateKey,
validatorPK *btcec.PublicKey,
covenantPK *btcec.PublicKey,
validatorPKs []*btcec.PublicKey,
covenantPKs []*btcec.PublicKey,
stakingTimeBlocks uint16,
stakingValue int64,
slashingAddress, changeAddress string,
Expand All @@ -241,8 +252,8 @@ func GenBTCStakingSlashingTx(
btcNet,
outPoint,
stakerSK,
validatorPK,
covenantPK,
validatorPKs,
covenantPKs,
stakingTimeBlocks,
stakingValue,
slashingAddress, changeAddress,
Expand All @@ -254,8 +265,8 @@ func GenBTCUnbondingSlashingTx(
r *rand.Rand,
btcNet *chaincfg.Params,
stakerSK *btcec.PrivateKey,
validatorPK *btcec.PublicKey,
covenantPK *btcec.PublicKey,
validatorPKs []*btcec.PublicKey,
covenantPKs []*btcec.PublicKey,
stakingTransactionOutpoint *wire.OutPoint,
stakingTimeBlocks uint16,
stakingValue int64,
Expand All @@ -267,8 +278,8 @@ func GenBTCUnbondingSlashingTx(
btcNet,
stakingTransactionOutpoint,
stakerSK,
validatorPK,
covenantPK,
validatorPKs,
covenantPKs,
stakingTimeBlocks,
stakingValue,
slashingAddress, changeAddress,
Expand Down
Loading

0 comments on commit 421a3be

Please sign in to comment.