Skip to content

Commit

Permalink
Add validation that there is only one fp key in delegation (#270)
Browse files Browse the repository at this point in the history
Fixes: #269

In phase-2 every delegation must have only one finality provider.
Adds:
- validation
- test cases
  • Loading branch information
KonradStaniec authored Nov 15, 2024
1 parent 88cce45 commit 2d423a8
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 37 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

## Unreleased


### Bug fixes

- [#270](https://github.com/babylonlabs-io/babylon/pull/270) Validate there is only
one finality provider key in the staking request

## v0.16.0

### Improvements
Expand Down
4 changes: 4 additions & 0 deletions x/btcstaking/types/create_delegation_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ func ParseCreateDelegationMessage(msg *MsgCreateBTCDelegation) (*ParsedCreateDel
return nil, ErrDuplicatedFp
}

if len(fpPKs.PublicKeysBbnFormat) != 1 {
return nil, ErrTooManyFpKeys
}

// 7. Parse staker public key
stakerPK, err := NewParsedPublicKey(msg.BtcPk)

Expand Down
15 changes: 8 additions & 7 deletions x/btcstaking/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ var (
ErrInvalidDelegationState = errorsmod.Register(ModuleName, 1113, "Unexpected delegation state")
ErrInvalidUnbondingTx = errorsmod.Register(ModuleName, 1114, "the BTC unbonding tx is not valid")
ErrEmptyFpList = errorsmod.Register(ModuleName, 1115, "the finality provider list is empty")
ErrInvalidProofOfPossession = errorsmod.Register(ModuleName, 1116, "the proof of possession is not valid")
ErrDuplicatedFp = errorsmod.Register(ModuleName, 1117, "the staking request contains duplicated finality provider public key")
ErrInvalidBTCUndelegateReq = errorsmod.Register(ModuleName, 1118, "invalid undelegation request")
ErrParamsNotFound = errorsmod.Register(ModuleName, 1119, "the parameters are not found")
ErrFpAlreadyJailed = errorsmod.Register(ModuleName, 1120, "the finality provider has already been jailed")
ErrFpNotJailed = errorsmod.Register(ModuleName, 1121, "the finality provider is not jailed")
ErrDuplicatedCovenantSig = errorsmod.Register(ModuleName, 1122, "the covenant signature is already submitted")
ErrTooManyFpKeys = errorsmod.Register(ModuleName, 1116, "the finality provider list contains too many public keys, it must contain exactly one")
ErrInvalidProofOfPossession = errorsmod.Register(ModuleName, 1117, "the proof of possession is not valid")
ErrDuplicatedFp = errorsmod.Register(ModuleName, 1118, "the staking request contains duplicated finality provider public key")
ErrInvalidBTCUndelegateReq = errorsmod.Register(ModuleName, 1119, "invalid undelegation request")
ErrParamsNotFound = errorsmod.Register(ModuleName, 1120, "the parameters are not found")
ErrFpAlreadyJailed = errorsmod.Register(ModuleName, 1121, "the finality provider has already been jailed")
ErrFpNotJailed = errorsmod.Register(ModuleName, 1122, "the finality provider is not jailed")
ErrDuplicatedCovenantSig = errorsmod.Register(ModuleName, 1123, "the covenant signature is already submitted")
)
119 changes: 89 additions & 30 deletions x/btcstaking/types/validate_parsed_message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,10 @@ func createMsgDelegationForParams(

func TestValidateParsedMessageAgainstTheParams(t *testing.T) {
tests := []struct {
name string
fn func(r *rand.Rand, t *testing.T) (*types.MsgCreateBTCDelegation, *types.Params, *btcckpttypes.Params)
err error
name string
fn func(r *rand.Rand, t *testing.T) (*types.MsgCreateBTCDelegation, *types.Params, *btcckpttypes.Params)
errParsing error
errValidation error
}{
{
name: "valid create delegation message",
Expand All @@ -246,7 +247,36 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: nil,
errParsing: nil,
errValidation: nil,
},
{
name: "empty finality provider list",
fn: func(r *rand.Rand, t *testing.T) (*types.MsgCreateBTCDelegation, *types.Params, *btcckpttypes.Params) {
params := testStakingParams(r, t)
checkpointParams := testCheckpointParams()
msg, _ := createMsgDelegationForParams(r, t, params, checkpointParams)

msg.FpBtcPkList = []bbn.BIP340PubKey{}

return msg, params, checkpointParams
},
errParsing: types.ErrEmptyFpList,
errValidation: nil,
},
{
name: "too many finality providers",
fn: func(r *rand.Rand, t *testing.T) (*types.MsgCreateBTCDelegation, *types.Params, *btcckpttypes.Params) {
params := testStakingParams(r, t)
checkpointParams := testCheckpointParams()
msg, _ := createMsgDelegationForParams(r, t, params, checkpointParams)

msg.FpBtcPkList = append(msg.FpBtcPkList, *msg.BtcPk)

return msg, params, checkpointParams
},
errParsing: types.ErrTooManyFpKeys,
errValidation: nil,
},
{
name: "too low unbonding time",
Expand All @@ -259,7 +289,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidUnbondingTx,
errParsing: nil,
errValidation: types.ErrInvalidUnbondingTx,
},
{
name: "Msg.BtcPk do not match pk in staking transaction",
Expand All @@ -277,7 +308,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidStakingTx,
errParsing: nil,
errValidation: types.ErrInvalidStakingTx,
},
{
name: "Msg.StakingTime do not match staking time committed in staking transaction",
Expand All @@ -290,7 +322,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidStakingTx,
errParsing: nil,
errValidation: types.ErrInvalidStakingTx,
},
{
name: "Msg.StakingValue do not match staking value committed in staking transaction",
Expand All @@ -303,7 +336,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidStakingTx.Wrap("staking tx does not contain expected staking output"),
errParsing: nil,
errValidation: types.ErrInvalidStakingTx.Wrap("staking tx does not contain expected staking output"),
},
{
name: "Msg.StakingValue is lower than params.MinStakingValueSat",
Expand All @@ -316,7 +350,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidStakingTx,
errParsing: nil,
errValidation: types.ErrInvalidStakingTx,
},
{
name: "Msg.StakingValue is higher than params.MinStakingValueSat",
Expand All @@ -329,7 +364,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidStakingTx,
errParsing: nil,
errValidation: types.ErrInvalidStakingTx,
},
{
name: "Msg.StakingTime is lower than params.MinStakingTimeBlocks",
Expand Down Expand Up @@ -369,7 +405,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidStakingTx,
errParsing: nil,
errValidation: types.ErrInvalidStakingTx,
},
{
name: "Msg.StakingTime is higher than params.MinStakingTimeBlocks",
Expand Down Expand Up @@ -409,7 +446,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidStakingTx,
errParsing: nil,
errValidation: types.ErrInvalidStakingTx,
},
{
name: "Msg.StakingValue is lower than params.MinStakingValueSat",
Expand All @@ -435,7 +473,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidStakingTx,
errParsing: nil,
errValidation: types.ErrInvalidStakingTx,
},
{
name: "Msg.StakingValue is higher than params.MaxStakingValueSat",
Expand All @@ -461,7 +500,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidStakingTx,
errParsing: nil,
errValidation: types.ErrInvalidStakingTx,
},
{
name: "Msg.SlashingTx have invalid pk script",
Expand All @@ -487,7 +527,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidStakingTx,
errParsing: nil,
errValidation: types.ErrInvalidStakingTx,
},
{
name: "Msg.SlashingTx does not point to staking tx hash",
Expand All @@ -514,7 +555,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidStakingTx,
errParsing: nil,
errValidation: types.ErrInvalidStakingTx,
},
{
name: "Msg.SlashingTx does not point to staking tx output index",
Expand All @@ -534,7 +576,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidStakingTx,
errParsing: nil,
errValidation: types.ErrInvalidStakingTx,
},
{
name: "Msg.DelegatorSlashingSig is invalid signature",
Expand All @@ -557,7 +600,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidSlashingTx,
errParsing: nil,
errValidation: types.ErrInvalidSlashingTx,
},
{
name: "Msg.UnbondingSlashingTx does not point to unbonding tx hash",
Expand All @@ -584,7 +628,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidUnbondingTx,
errParsing: nil,
errValidation: types.ErrInvalidUnbondingTx,
},
{
name: "Msg.UnbondingSlashingTx does not point to unbonding tx output index",
Expand All @@ -604,7 +649,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidUnbondingTx,
errParsing: nil,
errValidation: types.ErrInvalidUnbondingTx,
},
{
name: "Msg.UnbondingSlashingTx have invalid pk script",
Expand All @@ -630,7 +676,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidUnbondingTx,
errParsing: nil,
errValidation: types.ErrInvalidUnbondingTx,
},
{
name: "Msg.DelegatorUnbondingSlashingSig is invalid signature",
Expand All @@ -653,7 +700,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidSlashingTx,
errParsing: nil,
errValidation: types.ErrInvalidSlashingTx,
},
{
name: "Msg.UnbondingTx does not point to staking tx hash",
Expand Down Expand Up @@ -691,7 +739,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidUnbondingTx,
errParsing: nil,
errValidation: types.ErrInvalidUnbondingTx,
},
{
name: "Msg.UnbondingTx does not point to staking tx output index",
Expand Down Expand Up @@ -722,7 +771,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidUnbondingTx,
errParsing: nil,
errValidation: types.ErrInvalidUnbondingTx,
},
{
name: "Msg.UnbondingTx does not have required fee",
Expand Down Expand Up @@ -756,7 +806,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidUnbondingTx,
errParsing: nil,
errValidation: types.ErrInvalidUnbondingTx,
},
{
name: "Msg.UnbondingTx has more than one output",
Expand All @@ -778,7 +829,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidUnbondingTx.Wrap("unbonding tx is not a valid pre-signed transaction: tx must have exactly 1 outputs"),
errParsing: nil,
errValidation: types.ErrInvalidUnbondingTx.Wrap("unbonding tx is not a valid pre-signed transaction: tx must have exactly 1 outputs"),
},
{
name: "Msg.UnbondingTx unbonding value in the msg does not match the output value in the unbonding tx",
Expand Down Expand Up @@ -811,7 +863,8 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {

return msg, params, checkpointParams
},
err: types.ErrInvalidUnbondingTx.Wrap("the unbonding output value is not expected"),
errParsing: nil,
errValidation: types.ErrInvalidUnbondingTx.Wrap("the unbonding output value is not expected"),
},
}
for _, tt := range tests {
Expand All @@ -821,18 +874,24 @@ func TestValidateParsedMessageAgainstTheParams(t *testing.T) {
msg, params, checkpointParams := tt.fn(r, t)

parsed, err := types.ParseCreateDelegationMessage(msg)
require.NoError(t, err)

if tt.errParsing != nil {
require.Error(t, err)
require.ErrorAs(t, err, &tt.errParsing)
return
}

require.NoError(t, err)
got, err := types.ValidateParsedMessageAgainstTheParams(
parsed,
params,
checkpointParams,
&chaincfg.MainNetParams,
)

if tt.err != nil {
if tt.errValidation != nil {
require.Error(t, err)
require.ErrorAs(t, err, &tt.err)
require.ErrorAs(t, err, &tt.errValidation)
} else {
require.NoError(t, err)
require.NotNil(t, got)
Expand Down

0 comments on commit 2d423a8

Please sign in to comment.