Skip to content

Commit

Permalink
fix(rotation): complete rotation on afterStateUpdate hook (#1493)
Browse files Browse the repository at this point in the history
  • Loading branch information
mtsitrin authored Nov 17, 2024
1 parent b8a69b8 commit f611c49
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 8 deletions.
1 change: 1 addition & 0 deletions x/rollapp/keeper/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type SequencerKeeper interface {
SlashLiveness(ctx sdk.Context, rollappID string) error
PunishSequencer(ctx sdk.Context, seqAddr string, rewardee *sdk.AccAddress) error
GetProposer(ctx sdk.Context, rollappId string) types.Sequencer
GetSuccessor(ctx sdk.Context, rollapp string) types.Sequencer
}

// BankKeeper defines the expected interface needed to retrieve account balances.
Expand Down
5 changes: 5 additions & 0 deletions x/rollapp/keeper/liveness_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ type livenessMockSequencerKeeper struct {
slashes map[string]int
}

// GetSuccessor implements keeper.SequencerKeeper.
func (l livenessMockSequencerKeeper) GetSuccessor(ctx sdk.Context, rollapp string) seqtypes.Sequencer {
panic("unimplemented")
}

func (l livenessMockSequencerKeeper) PunishSequencer(ctx sdk.Context, seqAddr string, rewardee *sdk.AccAddress) error {
// TODO implement me
panic("implement me")
Expand Down
8 changes: 5 additions & 3 deletions x/rollapp/keeper/msg_server_update_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState)
}

// call the before-update-state hook
// currently used by `x/sequencer` to:
// 1. validate the state update submitter
// 2. complete the rotation of the proposer if needed
// currently used by `x/sequencer` to validate the proposer
err := k.hooks.BeforeUpdateState(ctx, msg.Creator, msg.RollappId, msg.Last)
if err != nil {
return nil, errorsmod.Wrap(err, "before update state")
Expand Down Expand Up @@ -82,6 +80,9 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState)
// by the sequencer rotation in k.hooks.BeforeUpdateState
// the proposer we get is the one that will propose the next block.
val := k.sequencerKeeper.GetProposer(ctx, msg.RollappId)
if msg.Last {
val = k.sequencerKeeper.GetSuccessor(ctx, msg.RollappId)
}

creationHeight := uint64(ctx.BlockHeight())
blockTime := ctx.BlockTime()
Expand Down Expand Up @@ -115,6 +116,7 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState)

// call the after-update-state hook
// currently used by `x/lightclient` to validate the state update in regards to the light client
// x/sequencer will complete the rotation if needed
err = k.hooks.AfterUpdateState(ctx, msg.RollappId, stateInfo)
if err != nil {
return nil, errorsmod.Wrap(err, "hook: after update state")
Expand Down
28 changes: 23 additions & 5 deletions x/sequencer/keeper/hook_listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types"
"github.com/dymensionxyz/dymension/v3/x/sequencer/types"
"github.com/dymensionxyz/gerr-cosmos/gerrc"
)

var _ rollapptypes.RollappHooks = rollappHook{}
Expand All @@ -18,17 +19,34 @@ func (k Keeper) RollappHooks() rollapptypes.RollappHooks {
return rollappHook{k: k}
}

// BeforeUpdateState will reject if the caller is not proposer, or if they are proposer but haven't
// finished their rotation notice period.
// If valid, it will set the successor as proposer
// BeforeUpdateState will reject if the caller is not proposer
// if lastStateUpdateBySequencer is true, validate that the sequencer is in the middle of a rotation
func (hook rollappHook) BeforeUpdateState(ctx sdk.Context, seqAddr, rollappId string, lastStateUpdateBySequencer bool) error {
proposer := hook.k.GetProposer(ctx, rollappId)
if seqAddr != proposer.Address {
return types.ErrNotProposer
}

if lastStateUpdateBySequencer {
return errorsmod.Wrap(hook.k.OnProposerLastBlock(ctx, proposer), "on proposer last block")
// if lastStateUpdateBySequencer is true, validate that the sequencer is in the middle of a rotation
if lastStateUpdateBySequencer && !hook.k.AwaitingLastProposerBlock(ctx, rollappId) {
return errorsmod.Wrap(gerrc.ErrInvalidArgument, "sequencer is not in the middle of a rotation")
}

return nil
}

// AfterUpdateState checks if rotation is completed and the nextProposer is changed
func (hook rollappHook) AfterUpdateState(ctx sdk.Context, rollappID string, stateInfo *rollapptypes.StateInfo) error {
// no proposer changed - no op
if stateInfo.Sequencer == stateInfo.NextProposer {
return nil
}

// handle proposer rotation completion
proposer := hook.k.GetProposer(ctx, rollappID)
err := hook.k.OnProposerLastBlock(ctx, proposer)
if err != nil {
return errorsmod.Wrap(err, "on proposer last block")
}

return nil
Expand Down

0 comments on commit f611c49

Please sign in to comment.