Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 28 additions & 27 deletions x/vaas/provider/keeper/consumer_equivocation.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,32 +215,6 @@ func (k Keeper) HandleConsumerDowntime(ctx sdk.Context, consumerId uint64, evide

providerAddr := k.GetProviderAddrFromConsumerAddr(ctx, consumerId, consumerAddr)

// Check that the consumer chain is outside its downtime grace period.
// During the grace period after launch, downtime evidence is suppressed to give
// validators time to spin up their consumer chain nodes.
infractionParams := k.GetInfractionParams(ctx)
if infractionParams.DowntimeGracePeriod > 0 {
initParams, err := k.GetConsumerInitializationParameters(ctx, consumerId)
if err != nil {
return errorsmod.Wrapf(
vaastypes.ErrInvalidConsumerState,
"cannot get initialization parameters for consumer chain %d: %s",
consumerId, err,
)
}
gracePeriodEnd := initParams.SpawnTime.Add(infractionParams.DowntimeGracePeriod)
if ctx.BlockTime().Before(gracePeriodEnd) {
return errorsmod.Wrapf(
vaastypes.ErrInvalidPacketData,
"consumer chain %d is still in downtime grace period (launched %s, grace ends %s, now %s)",
consumerId,
initParams.SpawnTime.UTC(),
gracePeriodEnd.UTC(),
ctx.BlockTime().UTC(),
)
}
}

// Verify the infraction height is not too old.
minHeight := k.GetEquivocationEvidenceMinHeight(ctx, consumerId)
if uint64(evidencePacket.InfractionHeight) < minHeight {
Expand All @@ -265,7 +239,8 @@ func (k Keeper) HandleConsumerDowntime(ctx sdk.Context, consumerId uint64, evide
}

consensusHeight := ibcclienttypes.NewHeight(0, uint64(evidencePacket.InfractionHeight))
if _, ok := k.clientKeeper.GetClientConsensusState(ctx, clientId, consensusHeight); !ok {
consensusState, ok := k.clientKeeper.GetClientConsensusState(ctx, clientId, consensusHeight)
if !ok {
return errorsmod.Wrapf(
vaastypes.ErrInvalidPacketData,
"no consensus state for consumer chain %d at infraction height %d: cannot verify downtime",
Expand All @@ -274,6 +249,32 @@ func (k Keeper) HandleConsumerDowntime(ctx sdk.Context, consumerId uint64, evide
)
}

// Check that the consumer chain is outside its downtime grace period.
// During the grace period after launch, downtime evidence is suppressed to give
// validators time to spin up their consumer chain nodes.
infractionParams := k.GetInfractionParams(ctx)
if infractionParams.DowntimeGracePeriod > 0 {
initParams, err := k.GetConsumerInitializationParameters(ctx, consumerId)
if err != nil {
return errorsmod.Wrapf(
vaastypes.ErrInvalidConsumerState,
"cannot get initialization parameters for consumer chain %d: %s",
consumerId, err,
)
}
gracePeriodEnd := initParams.SpawnTime.Add(infractionParams.DowntimeGracePeriod)
if consumerTime := consensusState.GetTimestamp(); consumerTime < uint64(gracePeriodEnd.UnixNano()) { //nolint:staticcheck
return errorsmod.Wrapf(
vaastypes.ErrInvalidPacketData,
"consumer chain %d is still in downtime grace period (launched %d, grace ends %d, infraction time %d)",
consumerId,
initParams.SpawnTime.UnixNano(),
gracePeriodEnd.UnixNano(),
consumerTime,
)
}
}

// Verify the validator was part of the consumer's validator set.
validator, found := k.GetConsumerValidator(ctx, consumerId, providerAddr)
if !found {
Expand Down
11 changes: 10 additions & 1 deletion x/vaas/provider/keeper/consumer_equivocation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1119,12 +1119,14 @@ func TestEvidencePacketDataJSONRoundTrip(t *testing.T) {

func TestHandleConsumerDowntimeRejectsDuringGracePeriod(t *testing.T) {
keeperParams := testkeeper.NewInMemKeeperParams(t)
providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, keeperParams)
providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, keeperParams)
defer ctrl.Finish()

consumerId := uint64(0)
providerKeeper.SetConsumerPhase(ctx, consumerId, types.CONSUMER_PHASE_LAUNCHED)
providerKeeper.SetConsumerChainId(ctx, consumerId, "consumer-chain")
providerKeeper.SetConsumerClientId(ctx, consumerId, "07-tendermint-0")
providerKeeper.SetEquivocationEvidenceMinHeight(ctx, consumerId, 1)

spawnTime := time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)
gracePeriod := 24 * time.Hour
Expand Down Expand Up @@ -1155,6 +1157,13 @@ func TestHandleConsumerDowntimeRejectsDuringGracePeriod(t *testing.T) {
stakingtypes.Infraction_INFRACTION_DOWNTIME,
)

consensusStateTimestamp := spawnTime.Add(12 * time.Hour)
mocks.MockClientKeeper.EXPECT().
GetClientConsensusState(ctx, "07-tendermint-0", ibcclienttypes.NewHeight(0, 100)).
Return(ibcexported.ConsensusState(&ibctmtypes.ConsensusState{
Timestamp: consensusStateTimestamp,
}), true)

err := providerKeeper.HandleConsumerEvidencePacket(ctx, consumerId, evidencePacket)
require.Error(t, err)
require.Contains(t, err.Error(), "grace period")
Expand Down
Loading