-
Notifications
You must be signed in to change notification settings - Fork 165
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
epoching: event and hook upon a certain threshold amount of slashed v…
…oting power (#35)
- Loading branch information
1 parent
66c0338
commit 8667398
Showing
21 changed files
with
1,314 additions
and
238 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
package keeper | ||
|
||
import ( | ||
"github.com/babylonchain/babylon/x/epoching/types" | ||
"github.com/cosmos/cosmos-sdk/store/prefix" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
) | ||
|
||
// InitQueueLength initialises the msg queue length to 0 | ||
func (k Keeper) InitQueueLength(ctx sdk.Context) { | ||
store := ctx.KVStore(k.storeKey) | ||
|
||
queueLenBytes, err := sdk.NewUint(0).Marshal() | ||
if err != nil { | ||
panic(sdkerrors.Wrap(types.ErrMarshal, err.Error())) | ||
} | ||
|
||
store.Set(types.QueueLengthKey, queueLenBytes) | ||
} | ||
|
||
// GetQueueLength fetches the number of queued messages | ||
func (k Keeper) GetQueueLength(ctx sdk.Context) sdk.Uint { | ||
store := ctx.KVStore(k.storeKey) | ||
|
||
// get queue len in bytes from DB | ||
bz := store.Get(types.QueueLengthKey) | ||
if bz == nil { | ||
panic(types.ErrUnknownQueueLen) | ||
} | ||
// unmarshal | ||
var queueLen sdk.Uint | ||
if err := queueLen.Unmarshal(bz); err != nil { | ||
panic(sdkerrors.Wrap(types.ErrUnmarshal, err.Error())) | ||
} | ||
|
||
return queueLen | ||
} | ||
|
||
// setQueueLength sets the msg queue length | ||
func (k Keeper) setQueueLength(ctx sdk.Context, queueLen sdk.Uint) { | ||
store := ctx.KVStore(k.storeKey) | ||
|
||
queueLenBytes, err := queueLen.Marshal() | ||
if err != nil { | ||
panic(sdkerrors.Wrap(types.ErrMarshal, err.Error())) | ||
} | ||
|
||
store.Set(types.QueueLengthKey, queueLenBytes) | ||
} | ||
|
||
// incQueueLength adds the queue length by 1 | ||
func (k Keeper) incQueueLength(ctx sdk.Context) { | ||
queueLen := k.GetQueueLength(ctx) | ||
incrementedQueueLen := queueLen.AddUint64(1) | ||
k.setQueueLength(ctx, incrementedQueueLen) | ||
} | ||
|
||
// EnqueueMsg enqueues a message to the queue of the current epoch | ||
func (k Keeper) EnqueueMsg(ctx sdk.Context, msg types.QueuedMessage) { | ||
// prefix: QueuedMsgKey | ||
store := ctx.KVStore(k.storeKey) | ||
queuedMsgStore := prefix.NewStore(store, types.QueuedMsgKey) | ||
|
||
// key: queueLenBytes | ||
queueLen := k.GetQueueLength(ctx) | ||
queueLenBytes, err := queueLen.Marshal() | ||
if err != nil { | ||
panic(sdkerrors.Wrap(types.ErrMarshal, err.Error())) | ||
} | ||
// value: msgBytes | ||
msgBytes, err := k.cdc.Marshal(&msg) | ||
if err != nil { | ||
panic(sdkerrors.Wrap(types.ErrMarshal, err.Error())) | ||
} | ||
queuedMsgStore.Set(queueLenBytes, msgBytes) | ||
|
||
// increment queue length | ||
k.incQueueLength(ctx) | ||
} | ||
|
||
// GetEpochMsgs returns the set of messages queued in the current epoch | ||
func (k Keeper) GetEpochMsgs(ctx sdk.Context) []*types.QueuedMessage { | ||
queuedMsgs := []*types.QueuedMessage{} | ||
store := ctx.KVStore(k.storeKey) | ||
|
||
// add each queued msg to queuedMsgs | ||
iterator := sdk.KVStorePrefixIterator(store, types.QueuedMsgKey) | ||
defer iterator.Close() | ||
for ; iterator.Valid(); iterator.Next() { | ||
queuedMsgBytes := iterator.Value() | ||
var queuedMsg types.QueuedMessage | ||
if err := k.cdc.Unmarshal(queuedMsgBytes, &queuedMsg); err != nil { | ||
panic(sdkerrors.Wrap(types.ErrUnmarshal, err.Error())) | ||
} | ||
queuedMsgs = append(queuedMsgs, &queuedMsg) | ||
} | ||
|
||
return queuedMsgs | ||
} | ||
|
||
// ClearEpochMsgs removes all messages in the queue | ||
func (k Keeper) ClearEpochMsgs(ctx sdk.Context) { | ||
store := ctx.KVStore(k.storeKey) | ||
|
||
// remove all epoch msgs | ||
iterator := sdk.KVStorePrefixIterator(store, types.QueuedMsgKey) | ||
defer iterator.Close() | ||
for ; iterator.Valid(); iterator.Next() { | ||
key := iterator.Key() | ||
store.Delete(key) | ||
} | ||
|
||
// set queue len to zero | ||
k.setQueueLength(ctx, sdk.NewUint(0)) | ||
} | ||
|
||
// 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 | ||
// TODO: after we bump to Cosmos SDK v0.46, add MsgCancelUnbondingDelegation | ||
switch unwrappedMsg := msg.Msg.(type) { | ||
case *types.QueuedMessage_MsgCreateValidator: | ||
unwrappedMsgWithType = unwrappedMsg.MsgCreateValidator | ||
case *types.QueuedMessage_MsgDelegate: | ||
unwrappedMsgWithType = unwrappedMsg.MsgDelegate | ||
case *types.QueuedMessage_MsgUndelegate: | ||
unwrappedMsgWithType = unwrappedMsg.MsgUndelegate | ||
case *types.QueuedMessage_MsgBeginRedelegate: | ||
unwrappedMsgWithType = unwrappedMsg.MsgBeginRedelegate | ||
default: | ||
panic(sdkerrors.Wrap(types.ErrInvalidQueuedMessageType, msg.String())) | ||
} | ||
|
||
// get the handler function from router | ||
handler := k.router.Handler(unwrappedMsgWithType) | ||
// handle the unwrapped message | ||
return handler(ctx, unwrappedMsgWithType) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package keeper | ||
|
||
import ( | ||
"github.com/babylonchain/babylon/x/epoching/types" | ||
"github.com/cosmos/cosmos-sdk/store/prefix" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
) | ||
|
||
// setSlashedVotingPower sets the total amount of voting power that has been slashed in the epoch | ||
func (k Keeper) setSlashedVotingPower(ctx sdk.Context, epochNumber sdk.Uint, power int64) { | ||
store := k.slashedVotingPowerStore(ctx) | ||
|
||
// key: epochNumber | ||
epochNumberBytes, err := epochNumber.Marshal() | ||
if err != nil { | ||
panic(sdkerrors.Wrap(types.ErrMarshal, err.Error())) | ||
} | ||
// value: power | ||
powerBytes, err := sdk.NewInt(power).Marshal() | ||
if err != nil { | ||
panic(sdkerrors.Wrap(types.ErrMarshal, err.Error())) | ||
} | ||
|
||
store.Set(epochNumberBytes, powerBytes) | ||
} | ||
|
||
// InitSlashedVotingPower sets the slashed voting power of the current epoch to 0 | ||
// This is called upon initialising the genesis state and upon a new epoch | ||
func (k Keeper) InitSlashedVotingPower(ctx sdk.Context) { | ||
epochNumber := k.GetEpochNumber(ctx) | ||
k.setSlashedVotingPower(ctx, epochNumber, 0) | ||
} | ||
|
||
// GetSlashedVotingPower fetches the amount of slashed voting power of a given epoch | ||
func (k Keeper) GetSlashedVotingPower(ctx sdk.Context, epochNumber sdk.Uint) int64 { | ||
store := k.slashedVotingPowerStore(ctx) | ||
|
||
// key: epochNumber | ||
epochNumberBytes, err := epochNumber.Marshal() | ||
if err != nil { | ||
panic(sdkerrors.Wrap(types.ErrMarshal, err.Error())) | ||
} | ||
bz := store.Get(epochNumberBytes) | ||
if bz == nil { | ||
panic(types.ErrUnknownSlashedVotingPower) | ||
} | ||
// get value | ||
var slashedVotingPower sdk.Int | ||
if err := slashedVotingPower.Unmarshal(bz); err != nil { | ||
panic(sdkerrors.Wrap(types.ErrUnmarshal, err.Error())) | ||
} | ||
|
||
return slashedVotingPower.Int64() | ||
} | ||
|
||
// AddSlashedValidator adds a slashed validator to the set of the current epoch | ||
// This is called upon hook `BeforeValidatorSlashed` exposed by the staking module | ||
func (k Keeper) AddSlashedValidator(ctx sdk.Context, valAddr sdk.ValAddress) { | ||
epochNumber := k.GetEpochNumber(ctx) | ||
store := k.slashedValSetStore(ctx, epochNumber) | ||
|
||
// insert into "set of slashed addresses" as KV pair, where | ||
// - key: valAddr | ||
// - value: empty | ||
store.Set(valAddr, []byte{}) | ||
|
||
// add voting power | ||
slashedVotingPower := k.GetSlashedVotingPower(ctx, epochNumber) | ||
thisVotingPower := k.GetValidatorVotingPower(ctx, epochNumber, valAddr) | ||
k.setSlashedVotingPower(ctx, epochNumber, slashedVotingPower+thisVotingPower) | ||
} | ||
|
||
// GetSlashedValidators returns the set of slashed validators of a given epoch | ||
func (k Keeper) GetSlashedValidators(ctx sdk.Context, epochNumber sdk.Uint) []sdk.ValAddress { | ||
addrs := []sdk.ValAddress{} | ||
store := k.slashedValSetStore(ctx, epochNumber) | ||
// add each valAddr, which is the key | ||
iterator := store.Iterator(nil, nil) | ||
defer iterator.Close() | ||
for ; iterator.Valid(); iterator.Next() { | ||
addr := sdk.ValAddress(iterator.Key()) | ||
addrs = append(addrs, addr) | ||
} | ||
|
||
return addrs | ||
} | ||
|
||
// ClearSlashedValidators removes all slashed validators in the set | ||
// TODO: This is called upon the epoch is checkpointed | ||
func (k Keeper) ClearSlashedValidators(ctx sdk.Context, epochNumber sdk.Uint) { | ||
// prefix : SlashedValidatorSetKey || epochNumber | ||
store := k.slashedValSetStore(ctx, epochNumber) | ||
|
||
// remove all entries with this prefix | ||
iterator := store.Iterator(nil, nil) | ||
defer iterator.Close() | ||
for ; iterator.Valid(); iterator.Next() { | ||
key := iterator.Key() | ||
store.Delete(key) | ||
} | ||
|
||
// forget the slashed voting power of this epoch | ||
epochNumberBytes, err := epochNumber.Marshal() | ||
if err != nil { | ||
panic(sdkerrors.Wrap(types.ErrMarshal, err.Error())) | ||
} | ||
k.slashedVotingPowerStore(ctx).Delete(epochNumberBytes) | ||
} | ||
|
||
// slashedValSetStore returns the KVStore of the slashed validator set for a given epoch | ||
// prefix : SlashedValidatorSetKey || epochNumber | ||
func (k Keeper) slashedValSetStore(ctx sdk.Context, epochNumber sdk.Uint) prefix.Store { | ||
store := ctx.KVStore(k.storeKey) | ||
slashedValStore := prefix.NewStore(store, types.SlashedValidatorSetKey) | ||
epochNumberBytes, err := epochNumber.Marshal() | ||
if err != nil { | ||
panic(sdkerrors.Wrap(types.ErrMarshal, err.Error())) | ||
} | ||
return prefix.NewStore(slashedValStore, epochNumberBytes) | ||
} | ||
|
||
// slashedVotingPower returns the KVStore of the slashed voting power | ||
// prefix: SlashedVotingPowerKey | ||
func (k Keeper) slashedVotingPowerStore(ctx sdk.Context) prefix.Store { | ||
store := ctx.KVStore(k.storeKey) | ||
return prefix.NewStore(store, types.SlashedVotingPowerKey) | ||
} |
Oops, something went wrong.