diff --git a/db/db.go b/db/db.go index 71d021e91b..f5187afb33 100644 --- a/db/db.go +++ b/db/db.go @@ -3111,6 +3111,17 @@ func GetTotalValidatorDeposits(validators []uint64, totalDeposits *uint64) error `, validatorsPQArray) } +func GetFirstActivationEpoch(validators []uint64, firstActivationEpoch *uint64) error { + validatorsPQArray := pq.Array(validators) + return ReaderDb.Get(firstActivationEpoch, ` + SELECT + activationepoch + FROM validators + WHERE validatorindex = ANY($1) + ORDER BY activationepoch LIMIT 1 + `, validatorsPQArray) +} + func GetTotalValidatorWithdrawals(validators []uint64, totalWithdrawals *uint64) error { validatorsPQArray := pq.Array(validators) return ReaderDb.Get(totalWithdrawals, ` diff --git a/handlers/common.go b/handlers/common.go index a9ed7530d4..c2d91600ca 100644 --- a/handlers/common.go +++ b/handlers/common.go @@ -94,6 +94,11 @@ func GetValidatorEarnings(validators []uint64, currency string) (*types.Validato return db.GetTotalValidatorDeposits(validators, &totalDeposits) }) + var firstActivationEpoch uint64 + g.Go(func() error { + return db.GetFirstActivationEpoch(validators, &firstActivationEpoch) + }) + var totalWithdrawals uint64 g.Go(func() error { return db.GetTotalValidatorWithdrawals(validators, &totalWithdrawals) @@ -214,13 +219,7 @@ func GetValidatorEarnings(validators []uint64, currency string) (*types.Validato } } - lookbackAmount := getProposalLuckBlockLookbackAmount(1) - startPeriod := len(slots) - lookbackAmount - if startPeriod < 0 { - startPeriod = 0 - } - - validatorProposalData.ProposalLuck = getProposalLuck(slots[startPeriod:], 1) + validatorProposalData.ProposalLuck = getProposalLuck(slots, len(validators), firstActivationEpoch) avgSlotInterval := uint64(getAvgSlotInterval(1)) avgSlotIntervalAsDuration := time.Duration(utils.Config.Chain.Config.SecondsPerSlot*avgSlotInterval) * time.Second validatorProposalData.AvgSlotInterval = &avgSlotIntervalAsDuration @@ -317,30 +316,11 @@ func GetValidatorEarnings(validators []uint64, currency string) (*types.Validato }, balancesMap, nil } -func getProposalLuckBlockLookbackAmount(validatorCount int) int { - switch { - case validatorCount <= 4: - return 10 - case validatorCount <= 10: - return 15 - case validatorCount <= 20: - return 20 - case validatorCount <= 50: - return 30 - case validatorCount <= 100: - return 50 - case validatorCount <= 200: - return 65 - default: - return 75 - } -} - // getProposalLuck calculates the luck of a given set of proposed blocks for a certain number of validators // given the blocks proposed by the validators and the number of validators // // precondition: slots is sorted by ascending block number -func getProposalLuck(slots []uint64, validatorsCount int) float64 { +func getProposalLuck(slots []uint64, validatorsCount int, fromEpoch uint64) float64 { // Return 0 if there are no proposed blocks or no validators if len(slots) == 0 || validatorsCount == 0 { return 0 @@ -363,32 +343,32 @@ func getProposalLuck(slots []uint64, validatorsCount int) float64 { // Get the timeframe for which we should consider qualified proposals var proposalTimeframe time.Duration - // Time since the first block in the proposed block slice - timeSinceFirstBlock := time.Since(utils.SlotToTime(slots[0])) + // Time since the first epoch of the related validators + timeSinceFirstEpoch := time.Since(utils.EpochToTime(fromEpoch)) targetBlocks := 8.0 // Determine the appropriate timeframe based on the time since the first block and the expected slot proposals switch { - case timeSinceFirstBlock < fiveDays: + case timeSinceFirstEpoch < fiveDays: proposalTimeframe = fiveDays - case timeSinceFirstBlock < oneWeek: + case timeSinceFirstEpoch < oneWeek: proposalTimeframe = oneWeek - case timeSinceFirstBlock < oneMonth: + case timeSinceFirstEpoch < oneMonth: proposalTimeframe = oneMonth - case timeSinceFirstBlock > year && expectedSlotProposals <= targetBlocks/12: + case timeSinceFirstEpoch > year && expectedSlotProposals <= targetBlocks/12: proposalTimeframe = year - case timeSinceFirstBlock > sixMonths && expectedSlotProposals <= targetBlocks/6: + case timeSinceFirstEpoch > sixMonths && expectedSlotProposals <= targetBlocks/6: proposalTimeframe = sixMonths - case timeSinceFirstBlock > fiveMonths && expectedSlotProposals <= targetBlocks/5: + case timeSinceFirstEpoch > fiveMonths && expectedSlotProposals <= targetBlocks/5: proposalTimeframe = fiveMonths - case timeSinceFirstBlock > fourMonths && expectedSlotProposals <= targetBlocks/4: + case timeSinceFirstEpoch > fourMonths && expectedSlotProposals <= targetBlocks/4: proposalTimeframe = fourMonths - case timeSinceFirstBlock > threeMonths && expectedSlotProposals <= targetBlocks/3: + case timeSinceFirstEpoch > threeMonths && expectedSlotProposals <= targetBlocks/3: proposalTimeframe = threeMonths - case timeSinceFirstBlock > twoMonths && expectedSlotProposals <= targetBlocks/2: + case timeSinceFirstEpoch > twoMonths && expectedSlotProposals <= targetBlocks/2: proposalTimeframe = twoMonths - case timeSinceFirstBlock > sixWeeks && expectedSlotProposals <= targetBlocks/1.5: + case timeSinceFirstEpoch > sixWeeks && expectedSlotProposals <= targetBlocks/1.5: proposalTimeframe = sixWeeks default: proposalTimeframe = oneMonth