diff --git a/x/gravity/keeper/batch.go b/x/gravity/keeper/batch.go index b3ff9e2e2..e0cf1d6e5 100644 --- a/x/gravity/keeper/batch.go +++ b/x/gravity/keeper/batch.go @@ -82,7 +82,10 @@ func (k Keeper) BuildOutgoingTxBatch(ctx sdk.Context, contractAddress, feeReceiv // GetBatchTimeoutHeight This gets the batch timeout height in External blocks. func (k Keeper) GetBatchTimeoutHeight(ctx sdk.Context) (uint64, uint64) { - currentMeHeight := ctx.BlockHeight() + currentMeHeight := uint64(0) + if ctx.BlockHeight() > 0 { + currentMeHeight = uint64(ctx.BlockHeight()) + } params := k.GetParams(ctx) if params.AverageExternalBlockTime == 0 { return 0, 0 @@ -93,8 +96,11 @@ func (k Keeper) GetBatchTimeoutHeight(ctx sdk.Context) (uint64, uint64) { if heights.ExternalBlockHeight == 0 { return 0, 0 } + if currentMeHeight < heights.BlockHeight { + currentMeHeight = heights.BlockHeight + } // we project how long it has been in milliseconds since the last Ethereum block height was observed - projectedMillis := (uint64(currentMeHeight) - heights.BlockHeight) * params.AverageBlockTime + projectedMillis := (currentMeHeight - heights.BlockHeight) * params.AverageBlockTime // we convert that projection into the current Ethereum height using the average Ethereum block time in millis projectedCurrentEthereumHeight := (projectedMillis / params.AverageExternalBlockTime) + heights.ExternalBlockHeight // we convert our target time for block timeouts (lets say 12 hours) into a number of blocks to diff --git a/x/gravity/keeper/batch_test.go b/x/gravity/keeper/batch_test.go index ccdcd5c65..3f4365678 100644 --- a/x/gravity/keeper/batch_test.go +++ b/x/gravity/keeper/batch_test.go @@ -70,6 +70,22 @@ func (suite *KeeperTestSuite) TestLastPendingBatchRequestByAddr() { } } +func (suite *KeeperTestSuite) TestBatchTimeoutHeightDoesNotUnderflowWhenObservedLocalHeightAhead() { + suite.SetupTest() + + suite.Ctx = suite.Ctx.WithBlockHeight(1) + suite.Keeper().SetLastObservedBlockHeight(suite.Ctx, 1_000, 100) + + params := suite.Keeper().GetParams(suite.Ctx) + expectedBlocksToAdd := params.ExternalBatchTimeout / params.AverageExternalBlockTime + + projectedHeight, batchTimeout := suite.Keeper().GetBatchTimeoutHeight(suite.Ctx) + + suite.Require().Equal(uint64(1_000), projectedHeight) + suite.Require().Equal(uint64(1_000)+expectedBlocksToAdd, batchTimeout) + suite.Require().Less(batchTimeout, uint64(2_000_000)) +} + func (suite *KeeperTestSuite) TestKeeper_DeleteBatchConfirm() { tokenContract := helpers.GenerateAddress().Hex() batch := &types.OutgoingTxBatch{