Skip to content

Commit

Permalink
epoching API: validator lifecycle (#109)
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastianElvis authored Sep 4, 2022
1 parent 0501cb1 commit eb75898
Show file tree
Hide file tree
Showing 18 changed files with 1,321 additions and 126 deletions.
14 changes: 0 additions & 14 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,6 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
Expand Down Expand Up @@ -556,7 +555,6 @@ github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1C
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jhump/protoreflect v1.9.0 h1:npqHz788dryJiR/l6K/RUQAyh2SwV91+d1dnh4RjO9w=
github.com/jhump/protoreflect v1.9.0/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
Expand Down Expand Up @@ -698,7 +696,6 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS
github.com/neilotoole/errgroup v0.1.5/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
Expand All @@ -714,7 +711,6 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
Expand Down Expand Up @@ -747,11 +743,6 @@ github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa
github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA=
github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ=
github.com/otiai10/copy v1.6.0/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
github.com/otiai10/mint v1.3.2/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
Expand Down Expand Up @@ -1270,7 +1261,6 @@ golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d h1:Zu/JngovGLVi6t2J3nmAf3AoTDwuzw85YZ3b9o4yU7s=
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
Expand Down Expand Up @@ -1337,10 +1327,8 @@ golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWc
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
Expand Down Expand Up @@ -1474,7 +1462,6 @@ google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ6
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220719170305-83ca9fad585f h1:P8EiVSxZwC6xH2niv2N66aqwMtYFg+D54gbjpcqKJtM=
google.golang.org/genproto v0.0.0-20220719170305-83ca9fad585f/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE=
google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o=
Expand All @@ -1490,7 +1477,6 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
Expand Down
18 changes: 18 additions & 0 deletions proto/babylon/epoching/v1/epoching.proto
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,21 @@ message QueuedMessage {
// TODO: after we bump to Cosmos SDK v0.46, add MsgCancelUnbondingDelegation
}
}

enum ValState {
CREATED = 0;
BONDED = 1;
UNBONDING = 2;
UNBONDED = 3;
REMOVED = 4;
}

message ValStateUpdate {
ValState state = 1;
uint64 height = 2;
}

message ValidatorLifecycle {
string val_addr = 1;
repeated ValStateUpdate val_life = 2;
}
13 changes: 13 additions & 0 deletions proto/babylon/epoching/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ service Query {
rpc EpochMsgs(QueryEpochMsgsRequest) returns (QueryEpochMsgsResponse) {
option (google.api.http).get = "/babylon/epoching/v1/epoch_msgs/{epoch_num}";
}

// ValidatorLifecycle queries the lifecycle of a given validator
rpc ValidatorLifecycle(QueryValidatorLifecycleRequest) returns (QueryValidatorLifecycleResponse) {
option (google.api.http).get = "/babylon/epoching/v1/validator_lifecycle/{val_addr}";
}
}

// QueryParamsRequest is request type for the Query/Params RPC method.
Expand Down Expand Up @@ -63,3 +68,11 @@ message QueryEpochMsgsResponse {
// pagination defines the pagination in the response
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

message QueryValidatorLifecycleRequest {
string val_addr = 1;
}

message QueryValidatorLifecycleResponse {
ValidatorLifecycle val_life = 1;
}
9 changes: 8 additions & 1 deletion x/checkpointing/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper
import (
"context"
"errors"

epochingtypes "github.com/babylonchain/babylon/x/epoching/types"
ed255192 "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -39,14 +40,20 @@ func (m msgServer) AddBlsSig(goCtx context.Context, msg *types.MsgAddBlsSig) (*t
// the epoching module
func (m msgServer) WrappedCreateValidator(goCtx context.Context, msg *types.MsgWrappedCreateValidator) (*types.MsgWrappedCreateValidatorResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

// TODO: porting other verification rules from staking module
valAddr, err := sdk.ValAddressFromBech32(msg.MsgCreateValidator.ValidatorAddress)
if err != nil {
return nil, err
}

// verify Proof-of-Possession
ok := msg.VerifyPoP(&ed255192.PubKey{Key: msg.MsgCreateValidator.Pubkey.Value})
if !ok {
return nil, errors.New("the proof-of-possession is not valid")
}

// store BLS public key
valAddr, err := sdk.ValAddressFromBech32(msg.MsgCreateValidator.ValidatorAddress)
err = m.k.CreateRegistration(ctx, *msg.Key.Pubkey, valAddr)
if err != nil {
return nil, err
Expand Down
12 changes: 11 additions & 1 deletion x/epoching/keeper/epoch_msg_queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,11 @@ func (k Keeper) GetCurrentEpochMsgs(ctx sdk.Context) []*types.QueuedMessage {

// HandleQueuedMsg unwraps a QueuedMessage and forwards it to the staking module
func (k Keeper) HandleQueuedMsg(ctx sdk.Context, msg *types.QueuedMessage) (*sdk.Result, error) {
var unwrappedMsgWithType sdk.Msg
var (
unwrappedMsgWithType sdk.Msg
err error
)

// TODO (non-urgent): after we bump to Cosmos SDK v0.46, add MsgCancelUnbondingDelegation
switch unwrappedMsg := msg.Msg.(type) {
case *types.QueuedMessage_MsgCreateValidator:
Expand All @@ -115,6 +119,11 @@ func (k Keeper) HandleQueuedMsg(ctx sdk.Context, msg *types.QueuedMessage) (*sdk
panic(sdkerrors.Wrap(types.ErrInvalidQueuedMessageType, msg.String()))
}

// failed to decode validator address
if err != nil {
panic(err)
}

// get the handler function from router
handler := k.router.Handler(unwrappedMsgWithType)

Expand All @@ -128,6 +137,7 @@ func (k Keeper) HandleQueuedMsg(ctx sdk.Context, msg *types.QueuedMessage) (*sdk
return result, err
}

// release the cache
msCache.Write()

return result, nil
Expand Down
23 changes: 23 additions & 0 deletions x/epoching/keeper/epoch_msg_queue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ func FuzzHandleQueuedMsg_MsgWrappedDelegate(f *testing.F) {
valPower, err := keeper.GetCurrentValidatorVotingPower(ctx, val)
require.NoError(t, err)

// ensure the validator's lifecycle data is generated
lc := keeper.GetValLifecycle(ctx, val)
require.NotNil(t, lc)
require.Equal(t, 1, len(lc.ValLife))
require.Equal(t, types.ValState_CREATED, lc.ValLife[0].State)
require.Equal(t, uint64(0), lc.ValLife[0].Height)

// delegate a random amount of tokens to the validator
numNewDels := rand.Int63n(1000) + 1
for i := int64(0); i < numNewDels; i++ {
Expand Down Expand Up @@ -149,6 +156,13 @@ func FuzzHandleQueuedMsg_MsgWrappedUndelegate(f *testing.F) {
valPower, err := helper.EpochingKeeper.GetCurrentValidatorVotingPower(ctx, val)
require.NoError(t, err)

// ensure the validator's lifecycle data is generated
lc := keeper.GetValLifecycle(ctx, val)
require.NotNil(t, lc)
require.Equal(t, 1, len(lc.ValLife))
require.Equal(t, types.ValState_CREATED, lc.ValLife[0].State)
require.Equal(t, uint64(0), lc.ValLife[0].Height)

// unbond a random amount of tokens from the validator
// Note that for any pair of delegator and validator, there can be `<=DefaultMaxEntries=7` concurrent undelegations at any time slot
// Otherwise, only `DefaultMaxEntries` undelegations will be processed at this height and the rest will be rejected
Expand Down Expand Up @@ -225,6 +239,15 @@ func FuzzHandleQueuedMsg_MsgWrappedBeginRedelegate(f *testing.F) {
require.NoError(t, err)
require.Equal(t, val1Power, val2Power)

// ensure the validator's lifecycle data is generated
for _, val := range []sdk.ValAddress{val1, val2} {
lc := keeper.GetValLifecycle(ctx, val)
require.NotNil(t, lc)
require.Equal(t, 1, len(lc.ValLife))
require.Equal(t, types.ValState_CREATED, lc.ValLife[0].State)
require.Equal(t, uint64(0), lc.ValLife[0].Height)
}

// redelegate a random amount of tokens from val1 to val2
// same as undelegation, there can be `<=DefaultMaxEntries=7` concurrent redelegation requests for any tuple (delegatorAddr, srcValidatorAddr, dstValidatorAddr)
// See https://github.com/cosmos/cosmos-sdk/blob/v0.45.5/x/staking/keeper/delegation.go#L908-L910
Expand Down
14 changes: 14 additions & 0 deletions x/epoching/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,17 @@ func (k Keeper) EpochMsgs(c context.Context, req *types.QueryEpochMsgsRequest) (
}
return resp, nil
}

// ValidatorLifecycle handles the QueryValidatorLifecycleRequest query
func (k Keeper) ValidatorLifecycle(c context.Context, req *types.QueryValidatorLifecycleRequest) (*types.QueryValidatorLifecycleResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
valAddr, err := sdk.ValAddressFromBech32(req.ValAddr)
if err != nil {
return nil, err
}
lc := k.GetValLifecycle(ctx, valAddr)
return &types.QueryValidatorLifecycleResponse{
ValLife: lc,
}, nil
// TODO: test this API
}
15 changes: 12 additions & 3 deletions x/epoching/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,24 @@ func (h Hooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, f
}
}

// Other staking hooks that are not used in the epoching module
func (h Hooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {}
func (h Hooks) BeforeValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {}
func (h Hooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
h.k.RecordNewValState(ctx, valAddr, types.ValState_CREATED)
}

func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.k.RecordNewValState(ctx, valAddr, types.ValState_REMOVED)
}

func (h Hooks) AfterValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.k.RecordNewValState(ctx, valAddr, types.ValState_BONDED)
}

func (h Hooks) AfterValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.k.RecordNewValState(ctx, valAddr, types.ValState_UNBONDING)
}

// Other staking hooks that are not used in the epoching module
func (h Hooks) BeforeValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {}
func (h Hooks) BeforeDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
}
func (h Hooks) BeforeDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
Expand Down
64 changes: 63 additions & 1 deletion x/epoching/keeper/modified_staking.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package keeper

import (
"fmt"

"github.com/babylonchain/babylon/x/epoching/types"
abci "github.com/tendermint/tendermint/abci/types"

sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -20,7 +23,7 @@ func (k *Keeper) ApplyMatureUnbonding(ctx sdk.Context, epochBoundaryHeader tmpro

// unbond all mature validators till the epoch boundary from the unbonding queue
ctx.WithBlockHeader(epochBoundaryHeader)
k.stk.UnbondAllMatureValidators(ctx)
k.UnbondAllMatureValidators(ctx)
ctx.WithBlockHeader(currHeader)

// get all mature unbonding delegations the epoch boundary from the ubd queue.
Expand Down Expand Up @@ -108,3 +111,62 @@ func (k *Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) []abci.Valid

return validatorUpdates
}

// UnbondAllMatureValidators unbonds all the mature unbonding validators that have finished their unbonding period.
// In addition, Babylon records the height of unbonding for each mature validator
// (adapted from https://github.com/cosmos/cosmos-sdk/blob/v0.45.5/x/staking/keeper/validator.go#L396-L447)
func (k Keeper) UnbondAllMatureValidators(ctx sdk.Context) {
store := ctx.KVStore(k.storeKey)

blockTime := ctx.BlockTime()
blockHeight := ctx.BlockHeight()

// unbondingValIterator will contains all validator addresses indexed under
// the ValidatorQueueKey prefix. Note, the entire index key is composed as
// ValidatorQueueKey | timeBzLen (8-byte big endian) | timeBz | heightBz (8-byte big endian),
// so it may be possible that certain validator addresses that are iterated
// over are not ready to unbond, so an explicit check is required.
unbondingValIterator := k.stk.ValidatorQueueIterator(ctx, blockTime, blockHeight)
defer unbondingValIterator.Close()

for ; unbondingValIterator.Valid(); unbondingValIterator.Next() {
key := unbondingValIterator.Key()
keyTime, keyHeight, err := stakingtypes.ParseValidatorQueueKey(key)
if err != nil {
panic(fmt.Errorf("failed to parse unbonding key: %w", err))
}

// All addresses for the given key have the same unbonding height and time.
// We only unbond if the height and time are less than the current height
// and time.
if keyHeight <= blockHeight && (keyTime.Before(blockTime) || keyTime.Equal(blockTime)) {
addrs := stakingtypes.ValAddresses{}
k.cdc.MustUnmarshal(unbondingValIterator.Value(), &addrs)

for _, valAddr := range addrs.Addresses {
addr, err := sdk.ValAddressFromBech32(valAddr)
if err != nil {
panic(err)
}
val, found := k.stk.GetValidator(ctx, addr)
if !found {
panic("validator in the unbonding queue was not found")
}

if !val.IsUnbonding() {
panic("unexpected validator in unbonding queue; status was not unbonding")
}

val = k.stk.UnbondingToUnbonded(ctx, val)
if val.GetDelegatorShares().IsZero() {
k.stk.RemoveValidator(ctx, val.GetOperator())
}

// Babylon modification: record the height when this validator becomes unbonded
k.RecordNewValState(ctx, addr, types.ValState_UNBONDED)
}

store.Delete(key)
}
}
}
Loading

0 comments on commit eb75898

Please sign in to comment.