diff --git a/x/upgrade/abci_test.go b/x/upgrade/abci_test.go index 18f1752737b6..c4c277be2de1 100644 --- a/x/upgrade/abci_test.go +++ b/x/upgrade/abci_test.go @@ -68,9 +68,9 @@ func TestRequireName(t *testing.T) { require.True(t, errors.Is(sdkerrors.ErrInvalidRequest, err), err) } -func TestRequireFutureBlock(t *testing.T) { +func TestRequireNotPastBlock(t *testing.T) { s := setupTest(10, map[int64]bool{}) - err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Height: s.ctx.BlockHeight()}}) + err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Height: s.ctx.BlockHeight() - 1}}) require.NotNil(t, err) require.True(t, errors.Is(sdkerrors.ErrInvalidRequest, err), err) } diff --git a/x/upgrade/keeper/keeper.go b/x/upgrade/keeper/keeper.go index a9d6e59081af..20abc1ef10ed 100644 --- a/x/upgrade/keeper/keeper.go +++ b/x/upgrade/keeper/keeper.go @@ -145,14 +145,16 @@ func (k Keeper) getModuleVersion(ctx sdk.Context, name string) (uint64, bool) { // ScheduleUpgrade schedules an upgrade based on the specified plan. // If there is another Plan already scheduled, it will overwrite it // (implicitly cancelling the current plan) -// ScheduleUpgrade will also write the upgraded client to the upgraded client path -// if an upgraded client is specified in the plan +// ScheduleUpgrade will also write the upgraded IBC ClientState to the upgraded client +// path if it is specified in the plan. func (k Keeper) ScheduleUpgrade(ctx sdk.Context, plan types.Plan) error { if err := plan.ValidateBasic(); err != nil { return err } - if plan.Height <= ctx.BlockHeight() { + // NOTE: allow for the possibility of chains to schedule upgrades in begin block of the same block + // as a strategy for emergency hard fork recoveries + if plan.Height < ctx.BlockHeight() { return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "upgrade cannot be scheduled in the past") }