Skip to content

Commit f5bd321

Browse files
authored
fix(vaas): verify grace period against client timestamp (#56)
* fix(vaas): verify grace period against client timestamp * fix test * improve error wrap
1 parent 18cc2e5 commit f5bd321

2 files changed

Lines changed: 38 additions & 28 deletions

File tree

x/vaas/provider/keeper/consumer_equivocation.go

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -215,32 +215,6 @@ func (k Keeper) HandleConsumerDowntime(ctx sdk.Context, consumerId uint64, evide
215215

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

218-
// Check that the consumer chain is outside its downtime grace period.
219-
// During the grace period after launch, downtime evidence is suppressed to give
220-
// validators time to spin up their consumer chain nodes.
221-
infractionParams := k.GetInfractionParams(ctx)
222-
if infractionParams.DowntimeGracePeriod > 0 {
223-
initParams, err := k.GetConsumerInitializationParameters(ctx, consumerId)
224-
if err != nil {
225-
return errorsmod.Wrapf(
226-
vaastypes.ErrInvalidConsumerState,
227-
"cannot get initialization parameters for consumer chain %d: %s",
228-
consumerId, err,
229-
)
230-
}
231-
gracePeriodEnd := initParams.SpawnTime.Add(infractionParams.DowntimeGracePeriod)
232-
if ctx.BlockTime().Before(gracePeriodEnd) {
233-
return errorsmod.Wrapf(
234-
vaastypes.ErrInvalidPacketData,
235-
"consumer chain %d is still in downtime grace period (launched %s, grace ends %s, now %s)",
236-
consumerId,
237-
initParams.SpawnTime.UTC(),
238-
gracePeriodEnd.UTC(),
239-
ctx.BlockTime().UTC(),
240-
)
241-
}
242-
}
243-
244218
// Verify the infraction height is not too old.
245219
minHeight := k.GetEquivocationEvidenceMinHeight(ctx, consumerId)
246220
if uint64(evidencePacket.InfractionHeight) < minHeight {
@@ -265,7 +239,8 @@ func (k Keeper) HandleConsumerDowntime(ctx sdk.Context, consumerId uint64, evide
265239
}
266240

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

252+
// Check that the consumer chain is outside its downtime grace period.
253+
// During the grace period after launch, downtime evidence is suppressed to give
254+
// validators time to spin up their consumer chain nodes.
255+
infractionParams := k.GetInfractionParams(ctx)
256+
if infractionParams.DowntimeGracePeriod > 0 {
257+
initParams, err := k.GetConsumerInitializationParameters(ctx, consumerId)
258+
if err != nil {
259+
return errorsmod.Wrapf(
260+
vaastypes.ErrInvalidConsumerState,
261+
"cannot get initialization parameters for consumer chain %d: %s",
262+
consumerId, err,
263+
)
264+
}
265+
gracePeriodEnd := initParams.SpawnTime.Add(infractionParams.DowntimeGracePeriod)
266+
if consumerTime := consensusState.GetTimestamp(); consumerTime < uint64(gracePeriodEnd.UnixNano()) { //nolint:staticcheck
267+
return errorsmod.Wrapf(
268+
vaastypes.ErrInvalidPacketData,
269+
"consumer chain %d is still in downtime grace period (launched %d, grace ends %d, infraction time %d)",
270+
consumerId,
271+
initParams.SpawnTime.UnixNano(),
272+
gracePeriodEnd.UnixNano(),
273+
consumerTime,
274+
)
275+
}
276+
}
277+
277278
// Verify the validator was part of the consumer's validator set.
278279
validator, found := k.GetConsumerValidator(ctx, consumerId, providerAddr)
279280
if !found {

x/vaas/provider/keeper/consumer_equivocation_test.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1119,12 +1119,14 @@ func TestEvidencePacketDataJSONRoundTrip(t *testing.T) {
11191119

11201120
func TestHandleConsumerDowntimeRejectsDuringGracePeriod(t *testing.T) {
11211121
keeperParams := testkeeper.NewInMemKeeperParams(t)
1122-
providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, keeperParams)
1122+
providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, keeperParams)
11231123
defer ctrl.Finish()
11241124

11251125
consumerId := uint64(0)
11261126
providerKeeper.SetConsumerPhase(ctx, consumerId, types.CONSUMER_PHASE_LAUNCHED)
11271127
providerKeeper.SetConsumerChainId(ctx, consumerId, "consumer-chain")
1128+
providerKeeper.SetConsumerClientId(ctx, consumerId, "07-tendermint-0")
1129+
providerKeeper.SetEquivocationEvidenceMinHeight(ctx, consumerId, 1)
11281130

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

1160+
consensusStateTimestamp := spawnTime.Add(12 * time.Hour)
1161+
mocks.MockClientKeeper.EXPECT().
1162+
GetClientConsensusState(ctx, "07-tendermint-0", ibcclienttypes.NewHeight(0, 100)).
1163+
Return(ibcexported.ConsensusState(&ibctmtypes.ConsensusState{
1164+
Timestamp: consensusStateTimestamp,
1165+
}), true)
1166+
11581167
err := providerKeeper.HandleConsumerEvidencePacket(ctx, consumerId, evidencePacket)
11591168
require.Error(t, err)
11601169
require.Contains(t, err.Error(), "grace period")

0 commit comments

Comments
 (0)