From 117cd3702360060e4fc52c62eb0381541b167a53 Mon Sep 17 00:00:00 2001 From: oren-lava Date: Tue, 20 Dec 2022 16:46:36 +0200 Subject: [PATCH] CNS-45: avgTime calculated with seperate funcs, fixed some PR issues --- app/upgrades/v0.2.0/constants.go | 4 +- app/upgrades/v0.2.0/upgrade_test.go | 2 +- app/upgrades/v0.2.0/upgrades.go | 2 +- x/pairing/keeper/grpc_query_get_pairing.go | 2 +- x/pairing/keeper/pairing.go | 102 ++++++++++++--------- 5 files changed, 64 insertions(+), 48 deletions(-) diff --git a/app/upgrades/v0.2.0/constants.go b/app/upgrades/v0.2.0/constants.go index 111ef9f6c6..42f8b16cb2 100644 --- a/app/upgrades/v0.2.0/constants.go +++ b/app/upgrades/v0.2.0/constants.go @@ -1,11 +1,11 @@ -package v020 +package vx import ( store "github.com/cosmos/cosmos-sdk/store/types" "github.com/lavanet/lava/app/upgrades" ) -const UpgradeName = "v0.2.0" +const UpgradeName = "vx" var Upgrade = upgrades.Upgrade{ UpgradeName: UpgradeName, // upgrade name defined few lines above diff --git a/app/upgrades/v0.2.0/upgrade_test.go b/app/upgrades/v0.2.0/upgrade_test.go index a20c73d608..7adf0dad04 100644 --- a/app/upgrades/v0.2.0/upgrade_test.go +++ b/app/upgrades/v0.2.0/upgrade_test.go @@ -1,6 +1,6 @@ //go:build ignore -package v020_test +package vx_test import ( "testing" diff --git a/app/upgrades/v0.2.0/upgrades.go b/app/upgrades/v0.2.0/upgrades.go index 079768bb74..13dfff56a8 100644 --- a/app/upgrades/v0.2.0/upgrades.go +++ b/app/upgrades/v0.2.0/upgrades.go @@ -1,4 +1,4 @@ -package v020 +package vx import ( "log" diff --git a/x/pairing/keeper/grpc_query_get_pairing.go b/x/pairing/keeper/grpc_query_get_pairing.go index aa9b79f4ea..3dccb7fd53 100644 --- a/x/pairing/keeper/grpc_query_get_pairing.go +++ b/x/pairing/keeper/grpc_query_get_pairing.go @@ -36,7 +36,7 @@ func (k Keeper) GetPairing(goCtx context.Context, req *types.QueryGetPairingRequ // Get pairing list for latest block providers, err := k.GetPairingForClient(ctx, req.ChainID, clientAddr) if err != nil { - return nil, fmt.Errorf("could not get pairing for chainID: %s, client addr: %s, err: %s", req.ChainID, clientAddr, err) + return nil, fmt.Errorf("could not get pairing for chainID: %s, client addr: %s, blockHeight: %d, err: %s", req.ChainID, clientAddr, ctx.BlockHeight(), err) } // Calculate the time left until the new epoch (when epoch changes, new pairing is generated) diff --git a/x/pairing/keeper/pairing.go b/x/pairing/keeper/pairing.go index 3d82c0231e..2b3d7c7bd6 100644 --- a/x/pairing/keeper/pairing.go +++ b/x/pairing/keeper/pairing.go @@ -2,8 +2,10 @@ package keeper import ( "fmt" + "math" "math/big" "strconv" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/utils" @@ -258,23 +260,6 @@ func (k Keeper) calculateNextEpochTime(ctx sdk.Context) (uint64, error) { // Function to calculate the average block time (i.e., how much time it takes to create a new block, in average) func (k Keeper) calculateAverageBlockTime(ctx sdk.Context, epoch uint64) (float64, error) { - // Check if a previous epoch exists (on the first epoch or after a chain fork, there is no previous epoch) - prevEpoch, err := k.epochStorageKeeper.GetPreviousEpochStartForBlock(ctx, epoch) - prevEpochExists := true - if err != nil { - prevEpochExists = false - } - - // If previous epoch can't be retrieved, return averageBlockTime = 0 - if !prevEpochExists { - return 0, nil - } - - // Make sure epoch is larger than prevEpoch - if epoch < prevEpoch { - return 0, fmt.Errorf("previous reference start block height is larger than the present reference start block height") - } - // Get epochBlocks (the number of blocks in an epoch) epochBlocks, err := k.epochStorageKeeper.EpochBlocks(ctx, epoch) if err != nil { @@ -287,51 +272,82 @@ func (k Keeper) calculateAverageBlockTime(ctx sdk.Context, epoch uint64) (float6 if MinSampleStep > epochBlocks { return 0, fmt.Errorf("invalid MinSampleStep value since it's larger than epochBlocks. MinSampleStep: %v, epochBlocks: %v", MinSampleStep, epochBlocks) } - sampleStep := int64(MinSampleStep) + sampleStepInt64 := int64(MinSampleStep) if epochBlocks > EpochBlocksDivider { - sampleStep = int64(epochBlocks) / EpochBlocksDivider + sampleStepInt64 = int64(epochBlocks) / EpochBlocksDivider } + sampleStep := uint64(sampleStepInt64) - // To get a block's timestamp, we use core.Block(). core.Block() can't get block 0 (results in error from Tendermint code) - startBlock := int64(prevEpoch) - if startBlock == 0 { - startBlock++ + // Get a list of the previous epoch's blocks timestamp and height + prevEpochTimestampAndHeightList, err := k.getPreviousEpochTimestampsByHeight(ctx, epoch, sampleStep) + if err != nil { + return 0, fmt.Errorf("couldn't get prevEpochTimestampAndHeightList. err: %v", err) } - // Get the timestamp of the startBlock - startBlockCore, err := core.Block(nil, &startBlock) + // Calculate the average block time from prevEpochTimestampAndHeightList + averageBlockTime, err := calculateAverageBlockTimeFromList(ctx, prevEpochTimestampAndHeightList, sampleStep) if err != nil { - return 0, fmt.Errorf("could not get startBlock's header, err: %s", err) + return 0, fmt.Errorf("couldn't get calculate average block time. err: %v", err) } - // Init prevBlockTimestamp (used in the loop below) - prevBlockTimestamp := startBlockCore.Block.Header.Time.UTC() + return averageBlockTime, nil +} + +type blockHeightAndTime struct { + blockHeight uint64 + blockTime time.Time +} + +// Function to get a list of the timestamps of the blocks in the previous epoch of the input (so it'll be deterministic) +func (k Keeper) getPreviousEpochTimestampsByHeight(ctx sdk.Context, epoch uint64, sampleStep uint64) ([]blockHeightAndTime, error) { - // Get the timestamps of the blocks between prevEpoch and epoch according to sampleStep. - // Then, calculate the difference between currentBlockTimestamp and prevBlockTimestamp and divide by the sample step (the number of block between them). - // The averageBlockTime will be the minimal value found (must be a non-zero positive number) - epochInt64 := int64(epoch) - averageBlockTime := float64(0) - for block := startBlock + sampleStep; block < epochInt64; block = block + sampleStep { + // Check if a previous epoch exists (on the first epoch or after a chain fork, there is no previous epoch. In this case, return an error since this function only calculates the average block time on epochs that fully passed). + prevEpoch, err := k.epochStorageKeeper.GetPreviousEpochStartForBlock(ctx, epoch) + if err != nil { + return nil, fmt.Errorf("can't get previous epoch for current epoch. epoch: %d", epoch) + } + + // Get previous epoch timestamps, in sampleStep steps + prevEpochTimestampAndHeightList := make([]blockHeightAndTime, EpochBlocksDivider) + loopCounter := 0 + for block := prevEpoch; block < epoch; block = block + sampleStep { - // Get current block timestamp - blockCore, err := core.Block(nil, &block) + // Get current block's height and timestamp + blockInt64 := int64(block) + blockCore, err := core.Block(nil, &blockInt64) if err != nil { - return 0, fmt.Errorf("could not get current block header, err: %s", err) + return nil, fmt.Errorf("could not get current block header, err: %s", err) } currentBlockTimestamp := blockCore.Block.Header.Time.UTC() + currentBlockHeight := uint64(blockCore.Block.Height) + blockHeightAndTimeStruct := blockHeightAndTime{blockHeight: currentBlockHeight, blockTime: currentBlockTimestamp} + + // Append the timestamp to the timestamp list + prevEpochTimestampAndHeightList[loopCounter] = blockHeightAndTimeStruct + loopCounter++ + } + + return prevEpochTimestampAndHeightList, nil - // Calculate time difference - currentAverageBlockTime := currentBlockTimestamp.Sub(prevBlockTimestamp).Seconds() / float64(sampleStep) +} + +func calculateAverageBlockTimeFromList(ctx sdk.Context, blockHeightAndTimeList []blockHeightAndTime, sampleStep uint64) (float64, error) { + + if blockHeightAndTimeList == nil { + return 0, fmt.Errorf("empty blockHeightAndTimeList") + } + + averageBlockTime := math.MaxFloat64 + for i := 1; i < len(blockHeightAndTimeList); i++ { + + // Calculate time difference (the average block time will be the minimum difference) + currentAverageBlockTime := blockHeightAndTimeList[i].blockTime.Sub(blockHeightAndTimeList[i-1].blockTime).Seconds() / float64(sampleStep) if currentAverageBlockTime <= 0 { - prevBlock := block - sampleStep - return 0, fmt.Errorf("calculated average block time is less than or equal to zero. block %v timestamp: %s, block %v timestamp: %s", block, currentBlockTimestamp.String(), prevBlock, prevBlockTimestamp.String()) + return 0, fmt.Errorf("calculated average block time is less than or equal to zero. block %v timestamp: %s, block %v timestamp: %s", blockHeightAndTimeList[i].blockHeight, blockHeightAndTimeList[i].blockTime.String(), blockHeightAndTimeList[i-1].blockHeight, blockHeightAndTimeList[i-1].blockTime.String()) } if averageBlockTime > currentAverageBlockTime || averageBlockTime == 0 { averageBlockTime = currentAverageBlockTime } - - prevBlockTimestamp = currentBlockTimestamp } return averageBlockTime, nil