Skip to content

Commit

Permalink
feat(ADR-025): Enable jailing and unjailing (#80)
Browse files Browse the repository at this point in the history
Closes #64.

TODOs:
- [x] #65 
- [x] #74
- [x] babylonlabs-io/finality-provider#56 
- [x] #81 

We still need to update the docs, add CLI cmd, and e2e tests but can be
done in separate PRs
  • Loading branch information
gitferry authored Sep 19, 2024
1 parent b834df2 commit e7ac8fd
Show file tree
Hide file tree
Showing 49 changed files with 2,268 additions and 812 deletions.
1 change: 0 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,6 @@ func (app *BabylonApp) setupUpgradeHandlers() {
upgrade.CreateUpgradeHandler(
app.ModuleManager,
app.configurator,
app.BaseApp,
app.AppKeepers,
),
)
Expand Down
5 changes: 3 additions & 2 deletions app/upgrades/signetlaunch/btcstaking_params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ package signetlaunch_test
import (
"testing"

"github.com/stretchr/testify/require"

"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) {
func TestHardCodedBtcStakingParamsAreValid(t *testing.T) {
bbnApp := app.NewTmpBabylonApp()
loadedParamas, err := v1.LoadBtcStakingParamsFromData(bbnApp.AppCodec())
require.NoError(t, err)
Expand Down
11 changes: 11 additions & 0 deletions app/upgrades/signetlaunch/finality_params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package signetlaunch

// TODO Some default parameters. Consider how to switch those depending on network:
// mainnet, testnet, devnet etc.
const FinalityParamStr = `{
"signed_blocks_window": 100,
"finality_sig_timeout": 3,
"min_signed_per_window": "0.1",
"min_pub_rand": 100,
"jail_duration": "86400s"
}`
17 changes: 17 additions & 0 deletions app/upgrades/signetlaunch/finality_params_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package signetlaunch_test

import (
"testing"

"github.com/stretchr/testify/require"

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

func TestHardCodedFinalityParamsAreValid(t *testing.T) {
bbnApp := app.NewTmpBabylonApp()
loadedParamas, err := v1.LoadFinalityParamsFromData(bbnApp.AppCodec())
require.NoError(t, err)
require.NoError(t, loadedParamas.Validate())
}
36 changes: 35 additions & 1 deletion app/upgrades/signetlaunch/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
btclighttypes "github.com/babylonlabs-io/babylon/x/btclightclient/types"
btcstkkeeper "github.com/babylonlabs-io/babylon/x/btcstaking/keeper"
btcstktypes "github.com/babylonlabs-io/babylon/x/btcstaking/types"
finalitykeeper "github.com/babylonlabs-io/babylon/x/finality/keeper"
finalitytypes "github.com/babylonlabs-io/babylon/x/finality/types"
)

var Upgrade = upgrades.Upgrade{
Expand All @@ -42,7 +44,6 @@ type DataSignedFps struct {
func CreateUpgradeHandler(
mm *module.Manager,
cfg module.Configurator,
app upgrades.BaseAppParamManager,
keepers *keepers.AppKeepers,
) upgradetypes.UpgradeHandler {
return func(context context.Context, _plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
Expand All @@ -58,6 +59,10 @@ func CreateUpgradeHandler(
panic(err)
}

if err := upgradeFinalityParameters(ctx, keepers.EncCfg, &keepers.FinalityKeeper); err != nil {
panic(err)
}

if err := propLaunch(ctx, keepers.EncCfg, &keepers.BTCLightClientKeeper, &keepers.BTCStakingKeeper); err != nil {
panic(err)
}
Expand All @@ -78,6 +83,18 @@ func LoadBtcStakingParamsFromData(cdc codec.Codec) (btcstktypes.Params, error) {
return params, nil
}

func LoadFinalityParamsFromData(cdc codec.Codec) (finalitytypes.Params, error) {
buff := bytes.NewBufferString(FinalityParamStr)

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

return params, nil
}

func upgradeBtcStakingParameters(
ctx sdk.Context,
e *appparams.EncodingConfig,
Expand All @@ -97,6 +114,23 @@ func upgradeBtcStakingParameters(
return k.OverwriteParamsAtVersion(ctx, 0, params)
}

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

cdc := e.Codec

params, err := LoadFinalityParamsFromData(cdc)

if err != nil {
return err
}

return k.SetParams(ctx, params)
}

// propLaunch runs the proposal of launch that is meant to insert new BTC Headers.
func propLaunch(
ctx sdk.Context,
Expand Down
29 changes: 19 additions & 10 deletions app/upgrades/signetlaunch/upgrades_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import (
"cosmossdk.io/core/header"
"cosmossdk.io/x/upgrade"
upgradetypes "cosmossdk.io/x/upgrade/types"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/suite"

"github.com/babylonlabs-io/babylon/app"
v1 "github.com/babylonlabs-io/babylon/app/upgrades/signetlaunch"
"github.com/babylonlabs-io/babylon/x/btclightclient"
btclighttypes "github.com/babylonlabs-io/babylon/x/btclightclient/types"
"github.com/babylonlabs-io/babylon/x/btcstaking/types"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/suite"
)

const (
Expand Down Expand Up @@ -75,10 +76,14 @@ func (s *UpgradeTestSuite) TestUpgrade() {
oldFPsLen = len(resp.FinalityProviders)

// Before upgrade, the params should be different
paramsFromUpgrade, err := v1.LoadBtcStakingParamsFromData(s.app.AppCodec())
bsParamsFromUpgrade, err := v1.LoadBtcStakingParamsFromData(s.app.AppCodec())
s.NoError(err)
moduleParams := s.app.BTCStakingKeeper.GetParams(s.ctx)
s.NotEqualValues(moduleParams, paramsFromUpgrade)
bsModuleParams := s.app.BTCStakingKeeper.GetParams(s.ctx)
s.NotEqualValues(bsModuleParams, bsParamsFromUpgrade)
fParamsFromUpgrade, err := v1.LoadFinalityParamsFromData(s.app.AppCodec())
s.NoError(err)
fModuleParams := s.app.FinalityKeeper.GetParams(s.ctx)
s.NotEqualValues(fModuleParams, fParamsFromUpgrade)
},
func() {
// inject upgrade plan
Expand Down Expand Up @@ -135,11 +140,15 @@ func (s *UpgradeTestSuite) TestUpgrade() {
s.EqualValues(fpFromKeeper.Pop.String(), fpInserted.Pop.String())
}

// Afer upgrade, the params should be the same
paramsFromUpgrade, err := v1.LoadBtcStakingParamsFromData(s.app.AppCodec())
// After upgrade, the params should be the same
bsParamsFromUpgrade, err := v1.LoadBtcStakingParamsFromData(s.app.AppCodec())
s.NoError(err)
bsModuleParams := s.app.BTCStakingKeeper.GetParams(s.ctx)
s.EqualValues(bsModuleParams, bsParamsFromUpgrade)
fParamsFromUpgrade, err := v1.LoadFinalityParamsFromData(s.app.AppCodec())
s.NoError(err)
moduleParams := s.app.BTCStakingKeeper.GetParams(s.ctx)
s.EqualValues(moduleParams, paramsFromUpgrade)
fModuleParams := s.app.FinalityKeeper.GetParams(s.ctx)
s.EqualValues(fModuleParams, fParamsFromUpgrade)
},
},
}
Expand Down
2 changes: 1 addition & 1 deletion app/upgrades/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type Upgrade struct {
UpgradeName string

// CreateUpgradeHandler defines the function that creates an upgrade handler
CreateUpgradeHandler func(*module.Manager, module.Configurator, BaseAppParamManager, *keepers.AppKeepers) upgradetypes.UpgradeHandler
CreateUpgradeHandler func(*module.Manager, module.Configurator, *keepers.AppKeepers) upgradetypes.UpgradeHandler

// Store upgrades, should be used for any new modules introduced, new modules deleted, or store names renamed.
StoreUpgrades store.StoreUpgrades
Expand Down
8 changes: 4 additions & 4 deletions proto/babylon/btcstaking/v1/btcstaking.proto
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ message FinalityProvider {
// the finality provider is slashed.
// if it's 0 then the finality provider is not slashed
uint64 slashed_btc_height = 7;
// sluggish defines whether the finality provider is detected sluggish
bool sluggish = 8;
// jailed defines whether the finality provider is jailed
bool jailed = 8;
}

// FinalityProviderWithMeta wraps the FinalityProvider with metadata.
Expand All @@ -54,8 +54,8 @@ message FinalityProviderWithMeta {
// the finality provider is slashed.
// if it's 0 then the finality provider is not slashed
uint64 slashed_btc_height = 5;
// sluggish defines whether the finality provider is detected sluggish
bool sluggish = 6;
// jailed defines whether the finality provider is detected jailed
bool jailed = 6;
}

// BTCDelegation defines a BTC delegation
Expand Down
18 changes: 17 additions & 1 deletion proto/babylon/btcstaking/v1/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,27 @@ message EventPowerDistUpdate {
bytes pk = 1 [ (gogoproto.customtype) = "github.com/babylonlabs-io/babylon/types.BIP340PubKey" ];
}

// EventJailedFinalityProvider defines an event that a finality provider
// is jailed after being detected sluggish
message EventJailedFinalityProvider {
bytes pk = 1 [ (gogoproto.customtype) = "github.com/babylonlabs-io/babylon/types.BIP340PubKey" ];
}

// EventUnjailedFinalityProvider defines an event that a jailed finality provider
// is unjailed after the jailing period is passed
message EventUnjailedFinalityProvider {
bytes pk = 1 [ (gogoproto.customtype) = "github.com/babylonlabs-io/babylon/types.BIP340PubKey" ];
}

// ev is the event that affects voting power distribution
oneof ev {
// slashed_fp means a finality provider is slashed
EventSlashedFinalityProvider slashed_fp = 1;
// jailed_fp means a finality provider is jailed
EventJailedFinalityProvider jailed_fp = 2;
// unjailed_fp means a jailed finality provider is unjailed
EventUnjailedFinalityProvider unjailed_fp = 3;
// btc_del_state_update means a BTC delegation's state is updated
EventBTCDelegationStateUpdate btc_del_state_update = 2;
EventBTCDelegationStateUpdate btc_del_state_update = 4;
}
}
3 changes: 3 additions & 0 deletions proto/babylon/btcstaking/v1/incentive.proto
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ message FinalityProviderDistInfo {
// is_timestamped indicates whether the finality provider
// has timestamped public randomness committed
bool is_timestamped = 6;
// is_jailed indicates whether the finality provider
// is jailed, if so, it should not be assigned voting power
bool is_jailed = 7;
}

// BTCDelDistInfo contains the information related to reward distribution for a BTC delegation
Expand Down
4 changes: 2 additions & 2 deletions proto/babylon/btcstaking/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,6 @@ message FinalityProviderResponse {
uint64 height = 8;
// voting_power is the voting power of this finality provider at the given height
uint64 voting_power = 9;
// sluggish defines whether the finality provider is detected sluggish
bool sluggish = 10;
// jailed defines whether the finality provider is jailed
bool jailed = 10;
}
13 changes: 3 additions & 10 deletions proto/babylon/finality/v1/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,9 @@ message EventSlashedFinalityProvider {
Evidence evidence = 1;
}

// EventSluggishFinalityProviderDetected is the event emitted when a finality provider is
// detected as sluggish
message EventSluggishFinalityProviderDetected {
// public_key is the BTC public key of the finality provider
string public_key = 1;
}

// EventSluggishFinalityProviderReverted is the event emitted when a sluggish finality
// provider is no longer considered sluggish
message EventSluggishFinalityProviderReverted {
// EventJailedFinalityProvider is the event emitted when a finality provider is
// jailed due to inactivity
message EventJailedFinalityProvider {
// public_key is the BTC public key of the finality provider
string public_key = 1;
}
5 changes: 5 additions & 0 deletions proto/babylon/finality/v1/finality.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ package babylon.finality.v1;
option go_package = "github.com/babylonlabs-io/babylon/x/finality/types";

import "gogoproto/gogo.proto";
import "amino/amino.proto";
import "google/protobuf/timestamp.proto";

// IndexedBlock is the necessary metadata and finalization status of a block
message IndexedBlock {
Expand Down Expand Up @@ -64,4 +66,7 @@ message FinalityProviderSigningInfo {
// missed_blocks_counter defines a counter to avoid unnecessary array reads.
// Note that `Sum(MissedBlocksBitArray)` always equals `MissedBlocksCounter`.
int64 missed_blocks_counter = 3;
// Timestamp until which the validator is jailed due to liveness downtime.
google.protobuf.Timestamp jailed_until = 4
[(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (amino.dont_omitempty) = true];
}
6 changes: 5 additions & 1 deletion proto/babylon/finality/v1/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package babylon.finality.v1;
import "gogoproto/gogo.proto";
import "amino/amino.proto";
import "cosmos_proto/cosmos.proto";
import "google/protobuf/duration.proto";

option go_package = "github.com/babylonlabs-io/babylon/x/finality/types";

Expand All @@ -16,7 +17,7 @@ message Params {
// vote before being judged as missing their voting turn on the given block
int64 finality_sig_timeout = 2;
// min_signed_per_window defines the minimum number of blocks that a finality provider is required to sign
// within the sliding window to avoid being detected as sluggish
// within the sliding window to avoid being jailed
bytes min_signed_per_window = 3 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
Expand All @@ -26,4 +27,7 @@ message Params {
// min_pub_rand is the minimum number of public randomness each
// message should commit
uint64 min_pub_rand = 4;
// jail_duration is the minimum period of time that a finality provider remains jailed
google.protobuf.Duration jail_duration = 5
[(gogoproto.nullable) = false, (amino.dont_omitempty) = true, (gogoproto.stdduration) = true];
}
22 changes: 19 additions & 3 deletions proto/babylon/finality/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ service Msg {
// TODO: msg for evidence of equivocation. this is not specified yet
// UpdateParams updates the finality module parameters.
rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse);
// UnjailFinalityProvider defines a method for unjailing a jailed
// finality provider, thus it can receive voting power
rpc UnjailFinalityProvider(MsgUnjailFinalityProvider) returns (MsgUnjailFinalityProviderResponse);
}

// MsgCommitPubRandList defines a message for committing a list of public randomness for EOTS
Expand All @@ -36,7 +39,7 @@ message MsgCommitPubRandList {
// commitment is the commitment of these public randomness
// currently it's the root of the Merkle tree that includes these public randomness
bytes commitment = 5;
// sig is the signature on (start_height || num_pub_rand || commitment) signed by
// sig is the signature on (start_height || num_pub_rand || commitment) signed by
// SK corresponding to fp_btc_pk. This prevents others to commit public
// randomness on behalf of fp_btc_pk
// TODO: another option is to restrict signer to correspond to fp_btc_pk. This restricts
Expand Down Expand Up @@ -73,17 +76,30 @@ message MsgAddFinalitySigResponse{}
// MsgUpdateParams defines a message for updating finality 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];
}
// MsgUpdateParamsResponse is the response to the MsgUpdateParams message.
message MsgUpdateParamsResponse {}

// MsgUnjailFinalityProvider defines the Msg/UnjailFinalityProvider request type
message MsgUnjailFinalityProvider {
option (gogoproto.goproto_getters) = false;
option (cosmos.msg.v1.signer) = "signer";

string signer = 1;
// fp_btc_pk is the BTC PK of the finality provider that commits the public randomness
bytes fp_btc_pk = 2 [ (gogoproto.customtype) = "github.com/babylonlabs-io/babylon/types.BIP340PubKey" ];
}

// MsgUnjailFinalityProviderResponse defines the Msg/UnjailFinalityProvider response type
message MsgUnjailFinalityProviderResponse {}
11 changes: 11 additions & 0 deletions test/e2e/configurer/chain/queries_btcstaking.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ func (n *NodeConfig) QueryBTCStakingParams() *bstypes.Params {
return &resp.Params
}

func (n *NodeConfig) QueryFinalityParams() *ftypes.Params {
bz, err := n.QueryGRPCGateway("/babylon/finality/v1/params", url.Values{})
require.NoError(n.t, err)

var resp ftypes.QueryParamsResponse
err = util.Cdc.UnmarshalJSON(bz, &resp)
require.NoError(n.t, err)

return &resp.Params
}

func (n *NodeConfig) QueryFinalityProviders() []*bstypes.FinalityProviderResponse {
bz, err := n.QueryGRPCGateway("/babylon/btcstaking/v1/finality_providers", url.Values{})
require.NoError(n.t, err)
Expand Down
Loading

0 comments on commit e7ac8fd

Please sign in to comment.