Skip to content

Commit

Permalink
epoching: fix genesis, param and bootstrapping (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastianElvis authored Jul 1, 2022
1 parent d1372c3 commit 468dc96
Show file tree
Hide file tree
Showing 14 changed files with 219 additions and 73 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,6 @@ $RECYCLE.BIN/
tools-stamp
/tests/localbabylon/.babylond/*
docs/diagrams/plantuml.jar
.testnets/
mytestnet/
output/
3 changes: 2 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ var (
evidence.AppModuleBasic{},
authzmodule.AppModuleBasic{},
vesting.AppModuleBasic{},
epoching.AppModuleBasic{},
btclightclient.AppModuleBasic{},
btccheckpoint.AppModuleBasic{},
checkpointing.AppModuleBasic{},
Expand Down Expand Up @@ -483,7 +484,7 @@ func NewBabylonApp(
}
anteHandler := sdk.ChainAnteDecorators(
NewWrappedAnteHandler(authAnteHandler),
epochingkeeper.NewDropValidatorMsgDecorator(),
epochingkeeper.NewDropValidatorMsgDecorator(app.EpochingKeeper),
)
app.SetAnteHandler(anteHandler)

Expand Down
2 changes: 2 additions & 0 deletions proto/babylon/epoching/v1/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ option go_package = "github.com/babylonchain/babylon/x/epoching/types";

// Params defines the parameters for the module.
message Params {
option (gogoproto.equal) = true;

// epoch_interval is the number of consecutive blocks to form an epoch
uint64 epoch_interval = 1 [ (gogoproto.moretags) = "yaml:\"epoch_interval\"" ];
}
12 changes: 7 additions & 5 deletions x/epoching/genesis.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
package epoching

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/babylonchain/babylon/x/epoching/keeper"
"github.com/babylonchain/babylon/x/epoching/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)

// InitGenesis initializes the capability module's state from a provided genesis
// state.
func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) {
// this line is used by starport scaffolding # genesis/module/init
// set params for this module
k.SetParams(ctx, genState.Params)
// init epoch number
if err := k.SetEpochNumber(ctx, sdk.NewUint(0)); err != nil {
panic(err)
}
}

// ExportGenesis returns the capability module's exported genesis.
func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState {
genesis := types.DefaultGenesis()
genesis.Params = k.GetParams(ctx)

// this line is used by starport scaffolding # genesis/module/export

return genesis
return genesis
}
34 changes: 34 additions & 0 deletions x/epoching/genesis_test.go
Original file line number Diff line number Diff line change
@@ -1 +1,35 @@
package epoching_test

import (
"testing"

"github.com/babylonchain/babylon/x/epoching"
"github.com/stretchr/testify/require"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"

simapp "github.com/babylonchain/babylon/app"
"github.com/babylonchain/babylon/x/epoching/types"
)

func TestExportGenesis(t *testing.T) {
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})

app.EpochingKeeper.SetParams(ctx, types.DefaultParams())
genesisState := epoching.ExportGenesis(ctx, app.EpochingKeeper)
require.Equal(t, genesisState.Params, types.DefaultParams())
}

func TestInitGenesis(t *testing.T) {
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})

genesisState := types.GenesisState{
Params: types.Params{
EpochInterval: 100,
},
}

epoching.InitGenesis(ctx, app.EpochingKeeper, genesisState)
require.Equal(t, app.EpochingKeeper.GetParams(ctx).EpochInterval, uint64(100))
}
15 changes: 12 additions & 3 deletions x/epoching/keeper/drop_validator_msg_decorator.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ import (
)

// DropValidatorMsgDecorator defines an AnteHandler decorator that rejects all messages that might change the validator set.
type DropValidatorMsgDecorator struct{}
type DropValidatorMsgDecorator struct {
ek Keeper
}

// NewDropValidatorMsgDecorator creates a new DropValidatorMsgDecorator
func NewDropValidatorMsgDecorator() *DropValidatorMsgDecorator {
return &DropValidatorMsgDecorator{}
func NewDropValidatorMsgDecorator(ek Keeper) *DropValidatorMsgDecorator {
return &DropValidatorMsgDecorator{
ek: ek,
}
}

// AnteHandle performs an AnteHandler check that rejects all non-wrapped validator-related messages.
Expand All @@ -22,7 +26,12 @@ func NewDropValidatorMsgDecorator() *DropValidatorMsgDecorator {
// - MsgBeginRedelegate
// TODO: after we bump to Cosmos SDK v0.46, add MsgCancelUnbondingDelegation
func (qmd DropValidatorMsgDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// skip if at genesis block, as genesis state contains txs that bootstrap the initial validator set
if ctx.BlockHeight() == 0 {
return next(ctx, tx, simulate)
}
for _, msg := range tx.GetMsgs() {
// if validator-related message after genesis, reject msg
if qmd.IsValidatorRelatedMsg(msg) {
return ctx, epochingtypes.ErrInvalidMsgType
}
Expand Down
2 changes: 1 addition & 1 deletion x/epoching/keeper/drop_validator_msg_decorator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestDropValidatorMsgDecorator(t *testing.T) {
{&stakingtypes.MsgEditValidator{}, false},
}

decorator := NewDropValidatorMsgDecorator()
decorator := NewDropValidatorMsgDecorator(Keeper{})

for _, tc := range testCases {
res := decorator.IsValidatorRelatedMsg(tc.msg)
Expand Down
22 changes: 12 additions & 10 deletions x/epoching/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ import (
"github.com/tendermint/tendermint/libs/log"
)

const (
DefaultEpochNumber = 0
)

type (
Keeper struct {
cdc codec.BinaryCodec
Expand Down Expand Up @@ -68,16 +64,16 @@ func (k Keeper) GetEpochNumber(ctx sdk.Context) (sdk.Uint, error) {

bz := store.Get(types.EpochNumberKey)
if bz == nil {
return sdk.NewUint(uint64(DefaultEpochNumber)), nil
return sdk.NewUint(0), types.ErrUnknownEpochNumber
}
var epochNumber sdk.Uint
err := epochNumber.Unmarshal(bz)

return epochNumber, err
}

// setEpochNumber sets epoch number
func (k Keeper) setEpochNumber(ctx sdk.Context, epochNumber sdk.Uint) error {
// SetEpochNumber sets epoch number
func (k Keeper) SetEpochNumber(ctx sdk.Context, epochNumber sdk.Uint) error {
store := ctx.KVStore(k.storeKey)

epochNumberBytes, err := epochNumber.Marshal()
Expand All @@ -97,7 +93,7 @@ func (k Keeper) IncEpochNumber(ctx sdk.Context) error {
return err
}
incrementedEpochNumber := epochNumber.AddUint64(1)
return k.setEpochNumber(ctx, incrementedEpochNumber)
return k.SetEpochNumber(ctx, incrementedEpochNumber)
}

// GetEpochBoundary gets the epoch boundary, i.e., the height of the block that ends this epoch
Expand All @@ -106,9 +102,15 @@ func (k Keeper) GetEpochBoundary(ctx sdk.Context) (sdk.Uint, error) {
if err != nil {
return sdk.NewUint(0), err
}
// epoch number is 0 at the 0-th block, i.e., genesis
if epochNumber.IsZero() {
return sdk.NewUint(0), nil
}
epochInterval := sdk.NewUint(k.GetParams(ctx).EpochInterval)
// example: in epoch 0, epoch interval is 5 blocks, boundary will be (0+1)*5=5
return epochNumber.AddUint64(1).Mul(epochInterval), nil
// example: in epoch 1, epoch interval is 5 blocks, boundary will be 1*5=5
// 0 | 1 2 3 4 5 | 6 7 8 9 10 |
// 0 | 1 | 2 |
return epochNumber.Mul(epochInterval), nil
}

// GetQueueLength fetches the number of queued messages
Expand Down
3 changes: 2 additions & 1 deletion x/epoching/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ import (

// x/epoching module sentinel errors
var (
ErrInvalidMsgType = sdkerrors.Register(ModuleName, 1, "invalid message type in {MsgCreateValidator, MsgDelegate, MsgUndelegate, MsgBeginRedelegate} messages. use wrapped versions instead")
ErrInvalidMsgType = sdkerrors.Register(ModuleName, 1, "invalid message type in {MsgCreateValidator, MsgDelegate, MsgUndelegate, MsgBeginRedelegate} messages. use wrapped versions instead")
ErrUnknownEpochNumber = sdkerrors.Register(ModuleName, 2, "the epoch number is not known in DB")
)
8 changes: 3 additions & 5 deletions x/epoching/types/genesis.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
package types

import (
// this line is used by starport scaffolding # genesis/types/import
)

// DefaultIndex is the default capability global index
const DefaultIndex uint64 = 1

// DefaultGenesis returns the default Capability genesis state
func DefaultGenesis() *GenesisState {
return &GenesisState{
// this line is used by starport scaffolding # genesis/types/default
Params: DefaultParams(),
// this line is used by starport scaffolding # genesis/types/default
Params: DefaultParams(),
}
}

// Validate performs basic genesis state validation returning an error upon any
// failure.
func (gs GenesisState) Validate() error {
// this line is used by starport scaffolding # genesis/types/validate
// this line is used by starport scaffolding # genesis/types/validate

return gs.Params.Validate()
}
80 changes: 49 additions & 31 deletions x/epoching/types/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,56 @@ package types_test
import (
"testing"

"github.com/stretchr/testify/require"
keepertest "github.com/babylonchain/babylon/testutil/keeper"
"github.com/babylonchain/babylon/testutil/nullify"
"github.com/babylonchain/babylon/x/epoching"

"github.com/babylonchain/babylon/x/epoching/types"
"github.com/stretchr/testify/require"
)

func TestGenesis(t *testing.T) {
genesisState := types.GenesisState{
Params: types.DefaultParams(),
}

k, ctx := keepertest.EpochingKeeper(t)
epoching.InitGenesis(ctx, *k, genesisState)
got := epoching.ExportGenesis(ctx, *k)
require.NotNil(t, got)

nullify.Fill(&genesisState)
nullify.Fill(got)
}

func TestGenesisState_Validate(t *testing.T) {
for _, tc := range []struct {
desc string
genState *types.GenesisState
valid bool
} {
{
desc: "default is valid",
genState: types.DefaultGenesis(),
valid: true,
},
{
desc: "valid genesis state",
genState: &types.GenesisState{
// this line is used by starport scaffolding # types/genesis/validField
},
valid: true,
},
// this line is used by starport scaffolding # types/genesis/testcase
} {
t.Run(tc.desc, func(t *testing.T) {
err := tc.genState.Validate()
if tc.valid {
require.NoError(t, err)
} else {
require.Error(t, err)
}
})
}
}
for _, tc := range []struct {
desc string
genState *types.GenesisState
valid bool
}{
{
desc: "default is valid",
genState: types.DefaultGenesis(),
valid: true,
},
{
desc: "valid genesis state",
genState: &types.GenesisState{
Params: types.Params{
EpochInterval: 100,
},
},
valid: true,
},
} {
t.Run(tc.desc, func(t *testing.T) {
err := tc.genState.Validate()
if tc.valid {
require.NoError(t, err)
} else {
require.Error(t, err)
}
})
}
}
47 changes: 39 additions & 8 deletions x/epoching/types/params.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
package types

import (
fmt "fmt"

paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
)

const (
DefaultEpochInterval uint64 = 10
)

var (
KeyEpochInterval = []byte("EpochInterval")
)

var _ paramtypes.ParamSet = (*Params)(nil)

// ParamKeyTable the param key table for launch module
Expand All @@ -12,21 +22,42 @@ func ParamKeyTable() paramtypes.KeyTable {
}

// NewParams creates a new Params instance
func NewParams() Params {
return Params{}
}

// DefaultParams returns a default set of parameters
func DefaultParams() Params {
return NewParams()
func NewParams(epochInterval uint64) Params {
return Params{
EpochInterval: epochInterval,
}
}

// ParamSetPairs get the params.ParamSet
func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
return paramtypes.ParamSetPairs{}
return paramtypes.ParamSetPairs{
paramtypes.NewParamSetPair(KeyEpochInterval, &p.EpochInterval, validateEpochInterval),
}
}

// DefaultParams returns a default set of parameters
func DefaultParams() Params {
return NewParams(DefaultEpochInterval)
}

// Validate validates the set of params
func (p Params) Validate() error {
if err := validateEpochInterval(p.EpochInterval); err != nil {
return err
}

return nil
}

func validateEpochInterval(i interface{}) error {
v, ok := i.(uint64)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}

if v <= 0 {
return fmt.Errorf("epoch interval must be positive: %d", v)
}

return nil
}
Loading

0 comments on commit 468dc96

Please sign in to comment.