Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: btc staking params retrocompatible #42

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
95 changes: 76 additions & 19 deletions cmd/babylond/cmd/genesis.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"encoding/hex"
"encoding/json"
"fmt"
"time"
Expand Down Expand Up @@ -68,16 +69,37 @@ Example:

var genesisParams GenesisParams
if network == "testnet" {
genesisParams = TestnetGenesisParams(genesisCliArgs.MaxActiveValidators,
genesisCliArgs.BtcConfirmationDepth, genesisCliArgs.BtcFinalizationTimeout, genesisCliArgs.CheckpointTag,
genesisCliArgs.EpochInterval, genesisCliArgs.BaseBtcHeaderHex,
genesisCliArgs.BaseBtcHeaderHeight, genesisCliArgs.AllowedReporterAddresses,
genesisCliArgs.CovenantPKs, genesisCliArgs.CovenantQuorum,
genesisCliArgs.SlashingAddress, genesisCliArgs.MinSlashingTransactionFeeSat,
genesisCliArgs.MinCommissionRate, genesisCliArgs.SlashingRate, genesisCliArgs.MaxActiveFinalityProviders,
genesisCliArgs.MinUnbondingTime, genesisCliArgs.MinUnbondingRate, genesisCliArgs.InflationRateChange,
genesisCliArgs.InflationMin, genesisCliArgs.InflationMax, genesisCliArgs.GoalBonded,
genesisCliArgs.BlocksPerYear, genesisCliArgs.GenesisTime, genesisCliArgs.BlockGasLimit, genesisCliArgs.VoteExtensionEnableHeight)
genesisParams = TestnetGenesisParams(
genesisCliArgs.MaxActiveValidators,
genesisCliArgs.BtcConfirmationDepth,
genesisCliArgs.BtcFinalizationTimeout,
genesisCliArgs.CheckpointTag,
genesisCliArgs.EpochInterval,
genesisCliArgs.BaseBtcHeaderHex,
genesisCliArgs.BaseBtcHeaderHeight,
genesisCliArgs.AllowedReporterAddresses,
genesisCliArgs.CovenantPKs,
genesisCliArgs.CovenantQuorum,
genesisCliArgs.MinStakingAmtSat,
genesisCliArgs.MaxStakingAmtSat,
genesisCliArgs.MinStakingTimeBlocks,
genesisCliArgs.MaxStakingTimeBlocks,
genesisCliArgs.SlashingPkScript,
genesisCliArgs.MinSlashingTransactionFeeSat,
genesisCliArgs.MinCommissionRate,
genesisCliArgs.SlashingRate,
genesisCliArgs.MaxActiveFinalityProviders,
genesisCliArgs.MinUnbondingTime,
genesisCliArgs.UnbondingFeeSat,
genesisCliArgs.InflationRateChange,
genesisCliArgs.InflationMin,
genesisCliArgs.InflationMax,
genesisCliArgs.GoalBonded,
genesisCliArgs.BlocksPerYear,
genesisCliArgs.GenesisTime,
genesisCliArgs.BlockGasLimit,
genesisCliArgs.VoteExtensionEnableHeight,
)
} else if network == "mainnet" {
// TODO: mainnet genesis params
panic("Mainnet params not implemented.")
Expand Down Expand Up @@ -238,12 +260,37 @@ type GenesisParams struct {
VoteExtensionsEnableHeight int64
}

func TestnetGenesisParams(maxActiveValidators uint32, btcConfirmationDepth uint64,
btcFinalizationTimeout uint64, checkpointTag string, epochInterval uint64, baseBtcHeaderHex string,
baseBtcHeaderHeight uint64, allowedReporters []string, covenantPKs []string, covenantQuorum uint32, slashingAddress string, minSlashingFee int64,
minCommissionRate sdkmath.LegacyDec, slashingRate sdkmath.LegacyDec, maxActiveFinalityProviders uint32, minUnbondingTime uint16, minUnbondingRate sdkmath.LegacyDec, inflationRateChange float64,
inflationMin float64, inflationMax float64, goalBonded float64,
blocksPerYear uint64, genesisTime time.Time, blockGasLimit int64, voteExtensionEnableHeight int64) GenesisParams {
func TestnetGenesisParams(
maxActiveValidators uint32,
btcConfirmationDepth uint64,
btcFinalizationTimeout uint64,
checkpointTag string,
epochInterval uint64,
baseBtcHeaderHex string,
baseBtcHeaderHeight uint64,
allowedReporters []string,
covenantPKs []string,
covenantQuorum uint32,
minStakingAmtSat int64,
maxStakingAmtSat int64,
minStakingTimeBlocks uint16,
maxStakingTimeBlocks uint16,
slashingPkScriptHex string,
minSlashingFee int64,
minCommissionRate sdkmath.LegacyDec,
slashingRate sdkmath.LegacyDec,
maxActiveFinalityProviders uint32,
minUnbondingTime uint16,
unbondingFeeSat int64,
inflationRateChange float64,
inflationMin float64,
inflationMax float64,
goalBonded float64,
blocksPerYear uint64,
genesisTime time.Time,
blockGasLimit int64,
voteExtensionEnableHeight int64,
) GenesisParams {

genParams := GenesisParams{}

Expand Down Expand Up @@ -336,15 +383,25 @@ func TestnetGenesisParams(maxActiveValidators uint32, btcConfirmationDepth uint6
}
covenantPKsBIP340 = append(covenantPKsBIP340, *pk)
}

slashingPkScript, err := hex.DecodeString(slashingPkScriptHex)
if err != nil {
panic(err)
}

genParams.BtcstakingParams.CovenantPks = covenantPKsBIP340
genParams.BtcstakingParams.CovenantQuorum = covenantQuorum
genParams.BtcstakingParams.SlashingAddress = slashingAddress
genParams.BtcstakingParams.MinStakingValueSat = minStakingAmtSat
genParams.BtcstakingParams.MaxStakingValueSat = maxStakingAmtSat
genParams.BtcstakingParams.MinStakingTimeBlocks = uint32(minStakingTimeBlocks)
genParams.BtcstakingParams.MaxStakingTimeBlocks = uint32(maxStakingTimeBlocks)
genParams.BtcstakingParams.SlashingPkScript = slashingPkScript
genParams.BtcstakingParams.MinSlashingTxFeeSat = minSlashingFee
genParams.BtcstakingParams.MinCommissionRate = minCommissionRate
genParams.BtcstakingParams.SlashingRate = slashingRate
genParams.BtcstakingParams.MaxActiveFinalityProviders = maxActiveFinalityProviders
genParams.BtcstakingParams.MinUnbondingTime = uint32(minUnbondingTime)
genParams.BtcstakingParams.MinUnbondingRate = minUnbondingRate
genParams.BtcstakingParams.MinUnbondingTimeBlocks = uint32(minUnbondingTime)
genParams.BtcstakingParams.UnbondingFeeSat = unbondingFeeSat
if err := genParams.BtcstakingParams.Validate(); err != nil {
panic(err)
}
Expand Down
Loading
Loading