Skip to content

Commit

Permalink
feat: ADR-23 Update staking parameters structure (#45)
Browse files Browse the repository at this point in the history
ref: babylonlabs-io/pm#19
Implement ADR-23 to make babylon chain parameters compatible with
[phase-1](https://github.com/babylonlabs-io/pm/blob/main/adr/adr-023-update-btcstaking-params.md)
  • Loading branch information
KonradStaniec authored Sep 4, 2024
1 parent 1d2155e commit b1e255a
Show file tree
Hide file tree
Showing 30 changed files with 1,604 additions and 420 deletions.
26 changes: 26 additions & 0 deletions app/upgrades/signetlaunch/btcstaking_params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package signetlaunch

// TODO Some default parameters. Consider how to switch those depending on network:
// mainnet, testnet, devnet etc.
const BtcStakingParamStr = `
{
"covenant_pks": [
"43311589af63c2adda04fcd7792c038a05c12a4fe40351b3eb1612ff6b2e5a0e",
"d415b187c6e7ce9da46ac888d20df20737d6f16a41639e68ea055311e1535dd9",
"d27cd27dbff481bc6fc4aa39dd19405eb6010237784ecba13bab130a4a62df5d",
"a3e107fee8879f5cf901161dbf4ff61c252ba5fec6f6407fe81b9453d244c02c",
"c45753e856ad0abb06f68947604f11476c157d13b7efd54499eaa0f6918cf716"
],
"covenant_quorum": 3,
"min_staking_value_sat": "1000",
"max_staking_value_sat": "10000000000",
"min_staking_time_blocks": 10,
"max_staking_time_blocks": 65535,
"slashing_pk_script": "dqkUAQEBAQEBAQEBAQEBAQEBAQEBAQGIrA==",
"min_slashing_tx_fee_sat": "1000",
"slashing_rate": "0.100000000000000000",
"min_unbonding_time_blocks": 0,
"unbonding_fee_sat": "1000",
"min_commission_rate": "0.03",
"max_active_finality_providers": 100
}`
16 changes: 16 additions & 0 deletions app/upgrades/signetlaunch/btcstaking_params_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package signetlaunch_test

import (
"testing"

"github.com/babylonlabs-io/babylon/app"
v1 "github.com/babylonlabs-io/babylon/app/upgrades/signetlaunch"
"github.com/stretchr/testify/require"
)

func TestHardCodedParamsAreValid(t *testing.T) {
bbnApp := app.NewTmpBabylonApp()
loadedParamas, err := v1.LoadBtcStakingParamsFromData(bbnApp.AppCodec())
require.NoError(t, err)
require.NoError(t, loadedParamas.Validate())
}
36 changes: 36 additions & 0 deletions app/upgrades/signetlaunch/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ func CreateUpgradeHandler(
return nil, err
}

// Upgrade the staking parameters as first, as other upgrades depend on it.
if err := upgradeBtcStakingParameters(ctx, keepers.EncCfg, &keepers.BTCStakingKeeper); err != nil {
panic(err)
}

if err := propLaunch(ctx, keepers.EncCfg, &keepers.BTCLightClientKeeper, &keepers.BTCStakingKeeper); err != nil {
panic(err)
}
Expand All @@ -61,6 +66,37 @@ func CreateUpgradeHandler(
}
}

func LoadBtcStakingParamsFromData(cdc codec.Codec) (btcstktypes.Params, error) {
buff := bytes.NewBufferString(BtcStakingParamStr)

var params btcstktypes.Params
err := cdc.UnmarshalJSON(buff.Bytes(), &params)
if err != nil {
return btcstktypes.Params{}, err
}

return params, nil
}

func upgradeBtcStakingParameters(
ctx sdk.Context,
e *appparams.EncodingConfig,
k *btcstkkeeper.Keeper,
) error {

cdc := e.Codec

params, err := LoadBtcStakingParamsFromData(cdc)

if err != nil {
return err
}

// We are overwriting the params at version 0, as the upgrade is happening from
// TGE chain so there should be only one version of the params
return k.OverwriteParamsAtVersion(ctx, 0, params)
}

// propLaunch runs the proposal of launch that is meant to insert new BTC Headers.
func propLaunch(
ctx sdk.Context,
Expand Down
12 changes: 12 additions & 0 deletions app/upgrades/signetlaunch/upgrades_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ func (s *UpgradeTestSuite) TestUpgrade() {
resp, err := s.app.BTCStakingKeeper.FinalityProviders(s.ctx, &types.QueryFinalityProvidersRequest{})
s.NoError(err)
oldFPsLen = len(resp.FinalityProviders)

// Before upgrade, the params should be different
paramsFromUpgrade, err := v1.LoadBtcStakingParamsFromData(s.app.AppCodec())
s.NoError(err)
moduleParams := s.app.BTCStakingKeeper.GetParams(s.ctx)
s.NotEqualValues(moduleParams, paramsFromUpgrade)
},
func() {
// inject upgrade plan
Expand Down Expand Up @@ -128,6 +134,12 @@ func (s *UpgradeTestSuite) TestUpgrade() {
s.EqualValues(fpFromKeeper.Commission.String(), fpInserted.Commission.String())
s.EqualValues(fpFromKeeper.Pop.String(), fpInserted.Pop.String())
}

// Afer upgrade, the params should be the same
paramsFromUpgrade, err := v1.LoadBtcStakingParamsFromData(s.app.AppCodec())
s.NoError(err)
moduleParams := s.app.BTCStakingKeeper.GetParams(s.ctx)
s.EqualValues(moduleParams, paramsFromUpgrade)
},
},
}
Expand Down
29 changes: 12 additions & 17 deletions btcstaking/staking.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ import (
func buildSlashingTxFromOutpoint(
stakingOutput wire.OutPoint,
stakingAmount, fee int64,
slashingAddress, changeAddress btcutil.Address,
slashingPkScript []byte,
changeAddress btcutil.Address,
slashingRate sdkmath.LegacyDec,
) (*wire.MsgTx, error) {
// Validate staking amount
Expand All @@ -49,6 +50,10 @@ func buildSlashingTxFromOutpoint(
return nil, ErrInvalidSlashingRate
}

if len(slashingPkScript) == 0 {
return nil, fmt.Errorf("slashing pk script must not be empty")
}

// Calculate the amount to be slashed
slashingRateFloat64, err := slashingRate.Float64()
if err != nil {
Expand All @@ -58,11 +63,6 @@ func buildSlashingTxFromOutpoint(
if slashingAmount <= 0 {
return nil, ErrInsufficientSlashingAmount
}
// Generate script for slashing address
slashingAddrScript, err := txscript.PayToAddrScript(slashingAddress)
if err != nil {
return nil, err
}

// Calculate the change amount
changeAmount := btcutil.Amount(stakingAmount) - slashingAmount - btcutil.Amount(fee)
Expand All @@ -81,7 +81,7 @@ func buildSlashingTxFromOutpoint(
// means this tx is not replacable.
input := wire.NewTxIn(&stakingOutput, nil, nil)
tx.AddTxIn(input)
tx.AddTxOut(wire.NewTxOut(int64(slashingAmount), slashingAddrScript))
tx.AddTxOut(wire.NewTxOut(int64(slashingAmount), slashingPkScript))
tx.AddTxOut(wire.NewTxOut(int64(changeAmount), changeAddrScript))

// Verify that the none of the outputs is a dust output.
Expand Down Expand Up @@ -140,7 +140,7 @@ func getPossibleStakingOutput(
func BuildSlashingTxFromStakingTxStrict(
stakingTx *wire.MsgTx,
stakingOutputIdx uint32,
slashingAddress btcutil.Address,
slashingPkScript []byte,
stakerPk *btcec.PublicKey,
slashChangeLockTime uint16,
fee int64,
Expand Down Expand Up @@ -172,7 +172,7 @@ func BuildSlashingTxFromStakingTxStrict(
return buildSlashingTxFromOutpoint(
*stakingOutpoint,
stakingOutput.Value, fee,
slashingAddress, si.TapAddress,
slashingPkScript, si.TapAddress,
slashingRate)
}

Expand Down Expand Up @@ -228,7 +228,7 @@ func IsSimpleTransfer(tx *wire.MsgTx) error {
// - the min fee for slashing tx is preserved
func validateSlashingTx(
slashingTx *wire.MsgTx,
slashingAddress btcutil.Address,
slashingPkScript []byte,
slashingRate sdkmath.LegacyDec,
slashingTxMinFee, stakingOutputValue int64,
stakerPk *btcec.PublicKey,
Expand Down Expand Up @@ -270,11 +270,6 @@ func validateSlashingTx(
return fmt.Errorf("slashing transaction must slash at least staking output value * slashing rate")
}

// Verify that the first output pays to the provided slashing address.
slashingPkScript, err := txscript.PayToAddrScript(slashingAddress)
if err != nil {
return fmt.Errorf("error creating slashing pk script: %w", err)
}
if !bytes.Equal(slashingTx.TxOut[0].PkScript, slashingPkScript) {
return fmt.Errorf("slashing transaction must pay to the provided slashing address")
}
Expand Down Expand Up @@ -341,7 +336,7 @@ func CheckTransactions(
fundingOutputIdx uint32,
slashingTxMinFee int64,
slashingRate sdkmath.LegacyDec,
slashingAddress btcutil.Address,
slashingPkScript []byte,
stakerPk *btcec.PublicKey,
slashingChangeLockTime uint16,
net *chaincfg.Params,
Expand Down Expand Up @@ -376,7 +371,7 @@ func CheckTransactions(
// 3. Check if slashing transaction is valid
if err := validateSlashingTx(
slashingTx,
slashingAddress,
slashingPkScript,
slashingRate,
slashingTxMinFee,
stakingOutput.Value,
Expand Down
14 changes: 10 additions & 4 deletions btcstaking/staking_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,14 @@ func testSlashingTx(
slashingAddress, err := genRandomBTCAddress(r)
require.NoError(t, err)

slashingPkScript, err := txscript.PayToAddrScript(slashingAddress)
require.NoError(t, err)

// Construct slashing transaction using the provided parameters
slashingTx, err := btcstaking.BuildSlashingTxFromStakingTxStrict(
stakingTx,
uint32(stakingOutputIdx),
slashingAddress,
slashingPkScript,
stakerPk,
slashingChangeLockTime,
fee,
Expand Down Expand Up @@ -196,7 +199,7 @@ func testSlashingTx(
uint32(stakingOutputIdx),
fee,
slashingRate,
slashingAddress,
slashingPkScript,
stakerPk,
slashingChangeLockTime,
&chaincfg.MainNetParams,
Expand Down Expand Up @@ -280,11 +283,14 @@ func TestSlashingTxWithOverflowMustNotAccepted(t *testing.T) {
slashingAddress, err := genRandomBTCAddress(r)
require.NoError(t, err)

slashingPkScript, err := txscript.PayToAddrScript(slashingAddress)
require.NoError(t, err)

// Construct slashing transaction using the provided parameters
slashingTx, err := btcstaking.BuildSlashingTxFromStakingTxStrict(
stakingTx,
uint32(0),
slashingAddress,
slashingPkScript,
sd.StakerKey,
slashingLockTime,
int64(minFee),
Expand All @@ -303,7 +309,7 @@ func TestSlashingTxWithOverflowMustNotAccepted(t *testing.T) {
uint32(0),
int64(minFee),
slashingRate,
slashingAddress,
slashingPkScript,
sd.StakerKey,
slashingLockTime,
&chaincfg.MainNetParams,
Expand Down
41 changes: 31 additions & 10 deletions cmd/babylond/cmd/flags.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"encoding/hex"
"strings"
"time"

Expand Down Expand Up @@ -35,10 +36,14 @@ const (
flagVoteExtensionEnableHeight = "vote-extension-enable-height"
flagCovenantPks = "covenant-pks"
flagCovenantQuorum = "covenant-quorum"
flagMinStakingAmtSat = "min-staking-amount-sat"
flagMaxStakingAmtSat = "max-staking-amount-sat"
flagMinStakingTimeBlocks = "min-staking-time-blocks"
flagMaxStakingTimeBlocks = "max-staking-time-blocks"
flagMaxActiveFinalityProviders = "max-active-finality-providers"
flagMinUnbondingTime = "min-unbonding-time"
flagMinUnbondingRate = "min-unbonding-rate"
flagSlashingAddress = "slashing-address"
flagUnbondingFeeSat = "unbonding-fee-sat"
flagSlashingPkScript = "slashing-pk-script"
flagMinSlashingFee = "min-slashing-fee-sat"
flagSlashingRate = "slashing-rate"
flagMinCommissionRate = "min-commission-rate"
Expand All @@ -64,12 +69,16 @@ type GenesisCLIArgs struct {
VoteExtensionEnableHeight int64
CovenantPKs []string
CovenantQuorum uint32
SlashingAddress string
MinStakingAmtSat int64
MaxStakingAmtSat int64
MinStakingTimeBlocks uint16
MaxStakingTimeBlocks uint16
SlashingPkScript string
MinSlashingTransactionFeeSat int64
SlashingRate math.LegacyDec
MaxActiveFinalityProviders uint32
MinUnbondingTime uint16
MinUnbondingRate math.LegacyDec
UnbondingFeeSat int64
MinCommissionRate math.LegacyDec
}

Expand All @@ -91,13 +100,17 @@ func addGenesisFlags(cmd *cobra.Command) {
// btcstaking args
cmd.Flags().String(flagCovenantPks, strings.Join(btcstypes.DefaultParams().CovenantPksHex(), ","), "Bitcoin staking covenant public keys, comma separated")
cmd.Flags().Uint32(flagCovenantQuorum, btcstypes.DefaultParams().CovenantQuorum, "Bitcoin staking covenant quorum")
cmd.Flags().String(flagSlashingAddress, btcstypes.DefaultParams().SlashingAddress, "Bitcoin staking slashing address")
cmd.Flags().Int64(flagMinStakingAmtSat, 500000, "Minimum staking amount in satoshis")
cmd.Flags().Int64(flagMaxStakingAmtSat, 100000000000, "Maximum staking amount in satoshis")
cmd.Flags().Uint16(flagMinStakingTimeBlocks, 100, "Minimum staking time in blocks")
cmd.Flags().Uint16(flagMaxStakingTimeBlocks, 10000, "Maximum staking time in blocks")
cmd.Flags().String(flagSlashingPkScript, hex.EncodeToString(btcstypes.DefaultParams().SlashingPkScript), "Bitcoin staking slashing pk script. Hex encoded.")
cmd.Flags().Int64(flagMinSlashingFee, 1000, "Bitcoin staking minimum slashing fee")
cmd.Flags().String(flagMinCommissionRate, "0", "Bitcoin staking validator minimum commission rate")
cmd.Flags().String(flagSlashingRate, "0.1", "Bitcoin staking slashing rate")
cmd.Flags().Uint32(flagMaxActiveFinalityProviders, 100, "Bitcoin staking maximum active finality providers")
cmd.Flags().Uint16(flagMinUnbondingTime, 0, "Min timelock on unbonding transaction in btc blocks")
cmd.Flags().String(flagMinUnbondingRate, "0.8", "Min amount of btc required in unbonding output expressed as a fraction of staking output")
cmd.Flags().Int64(flagUnbondingFeeSat, 1000, "Required fee for unbonding transaction in satoshis")
// inflation args
cmd.Flags().Float64(flagInflationRateChange, 0.13, "Inflation rate change")
cmd.Flags().Float64(flagInflationMax, 0.2, "Maximum inflation")
Expand All @@ -123,13 +136,17 @@ func parseGenesisFlags(cmd *cobra.Command) *GenesisCLIArgs {
reporterAddresses, _ := cmd.Flags().GetString(flagAllowedReporterAddresses)
covenantPks, _ := cmd.Flags().GetString(flagCovenantPks)
covenantQuorum, _ := cmd.Flags().GetUint32(flagCovenantQuorum)
slashingAddress, _ := cmd.Flags().GetString(flagSlashingAddress)
minStakingAmtSat, _ := cmd.Flags().GetInt64(flagMinStakingAmtSat)
maxStakingAmtSat, _ := cmd.Flags().GetInt64(flagMaxStakingAmtSat)
minStakingTimeBlocks, _ := cmd.Flags().GetUint16(flagMinStakingTimeBlocks)
maxStakingTimeBlocks, _ := cmd.Flags().GetUint16(flagMaxStakingTimeBlocks)
slashingPkScript, _ := cmd.Flags().GetString(flagSlashingPkScript)
minSlashingFee, _ := cmd.Flags().GetInt64(flagMinSlashingFee)
minCommissionRate, _ := cmd.Flags().GetString(flagMinCommissionRate)
slashingRate, _ := cmd.Flags().GetString(flagSlashingRate)
maxActiveFinalityProviders, _ := cmd.Flags().GetUint32(flagMaxActiveFinalityProviders)
minUnbondingTime, _ := cmd.Flags().GetUint16(flagMinUnbondingTime)
minUnbondingRate, _ := cmd.Flags().GetString(flagMinUnbondingRate)
unbondingFeeSat, _ := cmd.Flags().GetInt64(flagUnbondingFeeSat)
genesisTimeUnix, _ := cmd.Flags().GetInt64(flagGenesisTime)
inflationRateChange, _ := cmd.Flags().GetFloat64(flagInflationRateChange)
inflationMax, _ := cmd.Flags().GetFloat64(flagInflationMax)
Expand Down Expand Up @@ -162,13 +179,17 @@ func parseGenesisFlags(cmd *cobra.Command) *GenesisCLIArgs {
AllowedReporterAddresses: allowedReporterAddresses,
CovenantPKs: strings.Split(covenantPks, ","),
CovenantQuorum: covenantQuorum,
SlashingAddress: slashingAddress,
MinStakingAmtSat: minStakingAmtSat,
MaxStakingAmtSat: maxStakingAmtSat,
MinStakingTimeBlocks: minStakingTimeBlocks,
MaxStakingTimeBlocks: maxStakingTimeBlocks,
SlashingPkScript: slashingPkScript,
MinSlashingTransactionFeeSat: minSlashingFee,
MinCommissionRate: math.LegacyMustNewDecFromStr(minCommissionRate),
SlashingRate: math.LegacyMustNewDecFromStr(slashingRate),
MaxActiveFinalityProviders: maxActiveFinalityProviders,
MinUnbondingTime: minUnbondingTime,
MinUnbondingRate: math.LegacyMustNewDecFromStr(minUnbondingRate),
UnbondingFeeSat: unbondingFeeSat,
GenesisTime: genesisTime,
InflationRateChange: inflationRateChange,
InflationMax: inflationMax,
Expand Down
Loading

0 comments on commit b1e255a

Please sign in to comment.