Skip to content

Commit 5a8c322

Browse files
committed
refactor(api)!: omitting missing efficiencies
1 parent 84707b1 commit 5a8c322

File tree

10 files changed

+93
-64
lines changed

10 files changed

+93
-64
lines changed

backend/pkg/api/data_access/mobile.go

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ func (d *DataAccessService) GetValidatorDashboardMobileWidget(ctx context.Contex
173173
if err != nil {
174174
return nil, fmt.Errorf("error retrieving validator dashboard overview data: %w", err)
175175
}
176-
data.NetworkEfficiency = efficiency.TotalEfficiency[enums.AllTime].Float64 * 100
176+
networkEfficiency := efficiency.TotalEfficiency[enums.AllTime].Float64 * 100
177+
data.NetworkEfficiency = &networkEfficiency
177178

178179
// Validator status
179180
eg.Go(func() error {
@@ -251,22 +252,33 @@ func (d *DataAccessService) GetValidatorDashboardMobileWidget(ctx context.Contex
251252
share := queryResult.EffectiveRPLStake.Div(rpNetworkStats.EffectiveRPLStaked)
252253

253254
periodsPerYear := decimal.NewFromFloat(365 / (rpNetworkStats.ClaimIntervalHours / 24))
254-
data.RplApr = rpNetworkStats.NodeOperatorRewards.
255+
rplApr := rpNetworkStats.NodeOperatorRewards.
255256
Mul(share).
256257
Div(queryResult.RPLStake).
257258
Mul(periodsPerYear).
258259
Mul(decimal.NewFromInt(100)).InexactFloat64()
260+
data.RplApr = &rplApr
259261
}
260262
return nil
261263
})
262264

263-
retrieveApr := func(timeFrame enums.TimePeriod, apr *float64) {
265+
retrieveApr := func(timeFrame enums.TimePeriod, apr **float64) {
264266
eg.Go(func() error {
265267
incomeInfo, err := d.getElClAPR(ctx, wrappedDashboardId, -1, timeFrame)
266268
if err != nil {
267269
return err
268270
}
269-
*apr = incomeInfo.Apr.El + incomeInfo.Apr.Cl
271+
if incomeInfo.Apr.El == nil && incomeInfo.Apr.Cl == nil {
272+
return nil
273+
}
274+
var totalApr float64
275+
if incomeInfo.Apr.El != nil {
276+
totalApr += *incomeInfo.Apr.El
277+
}
278+
if incomeInfo.Apr.Cl != nil {
279+
totalApr += *incomeInfo.Apr.El
280+
}
281+
*apr = &totalApr
270282
return nil
271283
})
272284
}
@@ -282,19 +294,28 @@ func (d *DataAccessService) GetValidatorDashboardMobileWidget(ctx context.Contex
282294
})
283295
}
284296

285-
retrieveEfficiency := func(table string, efficiency *float64) {
297+
retrieveEfficiency := func(table string, efficiency **float64) {
286298
eg.Go(func() error {
287299
ds := goqu.Dialect("postgres").
288300
From(goqu.L(fmt.Sprintf(`%s AS r FINAL`, table))).
289301
With("validators", goqu.L("(SELECT dashboard_id, validator_index FROM users_val_dashboards_validators WHERE dashboard_id = ?)", dashboardId)).
290302
Select(
291-
goqu.L("COALESCE(SUM(efficiency_dividend::Int256) / NULLIF(SUM(efficiency_divisor::Int256), 0), 0)").As("efficiency"),
303+
goqu.L("SUM(efficiency_dividend::decimal)").As("efficiency_dividend"),
304+
goqu.L("SUM(efficiency_divisor::decimal)").As("efficiency_divisor"),
292305
).
293306
InnerJoin(goqu.L("validators v"), goqu.On(goqu.L("r.validator_index = v.validator_index"))).
294307
Where(goqu.L("r.validator_index IN (SELECT validator_index FROM validators)"))
295308

296-
*efficiency, err = runQuery[float64](ctx, d.clickhouseReader, ds)
297-
*efficiency *= 100
309+
type dbResult struct {
310+
EfficiencyDividend decimal.Decimal `db:"efficiency_dividend"`
311+
EfficiencyDivisor decimal.Decimal `db:"efficiency_divisor"`
312+
}
313+
dbRes, err := runQuery[dbResult](ctx, d.clickhouseReader, ds)
314+
if !dbRes.EfficiencyDivisor.IsZero() {
315+
eff := dbRes.EfficiencyDividend.Div(dbRes.EfficiencyDivisor).InexactFloat64()
316+
eff *= 100
317+
*efficiency = &eff
318+
}
298319

299320
return err
300321
})

backend/pkg/api/data_access/vdb_helpers.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ func (d *DataAccessService) getTotalRewardsColumns() string {
116116
type IncomeInfo struct {
117117
Rewards t.ClElValue[decimal.Decimal]
118118

119-
Apr t.ClElValue[float64]
119+
Apr t.ClElValue[*float64]
120120
}
121121

122122
func (d *DataAccessService) getElClAPR(ctx context.Context, dashboardId t.VDBId, groupId int64, timeFrame enums.TimePeriod) (rewardsApr IncomeInfo, err error) {
@@ -207,13 +207,18 @@ func (d *DataAccessService) getElClAPR(ctx context.Context, dashboardId t.VDBId,
207207
}
208208

209209
// precondition: invested amount and rewards are in the same currency
210-
func calcAPR(rewards, cumulativeDivisor decimal.Decimal, duration time.Duration) float64 {
210+
func calcAPR(rewards, cumulativeDivisor decimal.Decimal, duration time.Duration) *float64 {
211+
if cumulativeDivisor.IsZero() {
212+
return nil
213+
}
214+
var apr float64
211215
if rewards.IsZero() || cumulativeDivisor.IsZero() || duration.Nanoseconds() == 0 {
212-
return 0
216+
return &apr
213217
}
214218
annualizationFactor := decimal.NewFromInt(utils.Year.Nanoseconds()).Div(decimal.NewFromInt(duration.Nanoseconds()))
215219
percentScaleFactor := decimal.NewFromInt(100) // TODO remove BEDS-1147
216-
return rewards.Div(cumulativeDivisor).Mul(annualizationFactor).Mul(percentScaleFactor).InexactFloat64()
220+
apr = rewards.Div(cumulativeDivisor).Mul(annualizationFactor).Mul(percentScaleFactor).InexactFloat64()
221+
return &apr
217222
}
218223

219224
// converts a cl amount to the main currency

backend/pkg/api/data_access/vdb_management.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ func (d *DataAccessService) GetValidatorDashboardOverview(ctx context.Context, d
377377
return nil
378378
})
379379

380-
retrieveRewardsAndEfficiency := func(timeFrame enums.TimePeriod, rewards *t.ClElValue[decimal.Decimal], apr *t.ClElValue[float64], efficiency *float64) {
380+
retrieveRewardsAndEfficiency := func(timeFrame enums.TimePeriod, rewards *t.ClElValue[decimal.Decimal], apr *t.ClElValue[*float64], efficiency **float64) {
381381
// Rewards + APR
382382
eg.Go(func() error {
383383
incomeInfo, err := d.getElClAPR(ctx, dashboardId, -1, timeFrame)
@@ -399,7 +399,8 @@ func (d *DataAccessService) GetValidatorDashboardOverview(ctx context.Context, d
399399
From(goqu.L(fmt.Sprintf(`%s AS r FINAL`, table))).
400400
With("validators", goqu.L("(SELECT dashboard_id, validator_index FROM users_val_dashboards_validators WHERE dashboard_id = ?)", dashboardId.Id)).
401401
Select(
402-
goqu.L("COALESCE(SUM(efficiency_dividend::Int256) / NULLIF(SUM(efficiency_divisor::Int256), 0), 0)").As("efficiency"),
402+
goqu.L("SUM(efficiency_dividend::decimal)").As("efficiency_dividend"),
403+
goqu.L("SUM(efficiency_divisor::decimal)").As("efficiency_divisor"),
403404
)
404405

405406
if len(dashboardId.Validators) == 0 {
@@ -411,8 +412,17 @@ func (d *DataAccessService) GetValidatorDashboardOverview(ctx context.Context, d
411412
Where(goqu.L("r.validator_index IN ?", dashboardId.Validators))
412413
}
413414

414-
*efficiency, err = runQuery[float64](ctx, d.clickhouseReader, ds)
415-
*efficiency *= 100
415+
type dbResult struct {
416+
EfficiencyDividend decimal.Decimal `db:"efficiency_dividend"`
417+
EfficiencyDivisor decimal.Decimal `db:"efficiency_divisor"`
418+
}
419+
dbRes, err := runQuery[dbResult](ctx, d.clickhouseReader, ds)
420+
if !dbRes.EfficiencyDivisor.IsZero() {
421+
eff := dbRes.EfficiencyDividend.Div(dbRes.EfficiencyDivisor).InexactFloat64()
422+
eff *= 100
423+
*efficiency = &eff
424+
}
425+
416426
return err
417427
})
418428
}

backend/pkg/api/data_access/vdb_summary.go

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,10 @@ func (d *DataAccessService) GetValidatorDashboardSummary(ctx context.Context, da
389389
}
390390
case enums.VDBSummaryColumns.Efficiency:
391391
sortParam = func(resultEntry t.VDBSummaryTableRow) float64 {
392-
return resultEntry.Efficiency
392+
if resultEntry.Efficiency == nil {
393+
return -1
394+
}
395+
return *resultEntry.Efficiency
393396
}
394397
case enums.VDBSummaryColumns.Attestations:
395398
sortParam = func(resultEntry t.VDBSummaryTableRow) float64 {
@@ -738,23 +741,21 @@ func (d *DataAccessService) GetValidatorDashboardGroupSummary(ctx context.Contex
738741
}
739742

740743
if totalBlockChance > 0 {
741-
ret.Luck.Proposal.Percent = (float64(totalBlocksScheduled)) / totalBlockChance * 100
744+
proposalLuck := (float64(totalBlocksScheduled)) / totalBlockChance * 100
745+
ret.Luck.Proposal.Percent = &proposalLuck
742746

743747
// calculate the average time it takes for the set of validators to propose a single block on average
744748
ret.Luck.Proposal.AverageIntervalSeconds = uint64(time.Duration((luckHours / totalBlockChance) * float64(time.Hour)).Seconds())
745749

746750
ret.Luck.Proposal.ExpectedTimestamp = uint64(lastBlockTs.Unix()) + ret.Luck.Proposal.AverageIntervalSeconds
747-
} else {
748-
ret.Luck.Proposal.Percent = 0
749751
}
750752

751-
if totalSyncExpected == 0 {
752-
ret.Luck.Sync.Percent = 0
753-
} else {
753+
if totalSyncExpected > 0 {
754754
totalSyncSlotDuties := float64(ret.SyncCommittee.StatusCount.Failed) + float64(ret.SyncCommittee.StatusCount.Success)
755755
slotDutiesPerSyncCommittee := float64(utils.SlotsPerSyncCommittee())
756756
syncCommittees := math.Ceil(totalSyncSlotDuties / slotDutiesPerSyncCommittee) // gets the number of sync committees
757-
ret.Luck.Sync.Percent = syncCommittees / totalSyncExpected * 100
757+
syncLuck := syncCommittees / totalSyncExpected * 100
758+
ret.Luck.Sync.Percent = &syncLuck
758759

759760
// calculate the average time it takes for the set of validators to be elected into a sync committee on average
760761
ret.Luck.Sync.AverageIntervalSeconds = uint64(time.Duration((luckHours / totalSyncExpected) * float64(time.Hour)).Seconds())
@@ -813,24 +814,16 @@ func (d *DataAccessService) GetValidatorDashboardGroupSummary(ctx context.Contex
813814
return ret, nil
814815
}
815816

816-
func calcEfficiencyNulled(dividend, divisor decimal.Decimal) *float64 {
817+
func calcEfficiency(dividend, divisor decimal.Decimal) *float64 {
817818
if divisor.IsZero() {
818819
return nil
819820
}
820-
efficiency := calcEfficiency(dividend, divisor)
821-
return &efficiency
822-
}
823-
824-
func calcEfficiency(dividend, divisor decimal.Decimal) float64 {
825-
if divisor.IsZero() {
826-
return 100
827-
}
828821
eff := dividend.Div(divisor).InexactFloat64() * 100
829822
if eff > 100 {
830823
log.Error(nil, "efficiency is greater than 100%", 1, map[string]interface{}{"efficiency": eff})
831824
eff = 100
832825
}
833-
return eff
826+
return &eff
834827
}
835828

836829
// for summary charts: series id is group id, no stack
@@ -953,7 +946,7 @@ func (d *DataAccessService) GetValidatorDashboardSummaryChart(ctx context.Contex
953946
}
954947

955948
if !dashboardId.AggregateGroups && requestedGroupsMap[row.GroupId] {
956-
eff := calcEfficiencyNulled(row.EfficiencyDividend, row.EfficiencyDivisor)
949+
eff := calcEfficiency(row.EfficiencyDividend, row.EfficiencyDivisor)
957950
if eff == nil {
958951
continue
959952
}
@@ -995,7 +988,7 @@ func (d *DataAccessService) GetValidatorDashboardSummaryChart(ctx context.Contex
995988
totalLineGroupId = t.DefaultGroupId
996989
}
997990
for _, row := range totalEfficiencyMap {
998-
data[row.Timestamp][totalLineGroupId] = calcEfficiencyNulled(row.EfficiencyDividend, row.EfficiencyDivisor)
991+
data[row.Timestamp][totalLineGroupId] = calcEfficiency(row.EfficiencyDividend, row.EfficiencyDivisor)
999992
}
1000993
groupMap[totalLineGroupId] = true
1001994
}

backend/pkg/api/types/common.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ type Address struct {
3939
}
4040

4141
type LuckItem struct {
42-
Percent float64 `json:"percent"`
43-
ExpectedTimestamp uint64 `json:"expected_timestamp"`
44-
AverageIntervalSeconds uint64 `json:"average_interval_seconds"`
42+
Percent *float64 `json:"percent"`
43+
ExpectedTimestamp uint64 `json:"expected_timestamp"`
44+
AverageIntervalSeconds uint64 `json:"average_interval_seconds"`
4545
}
4646

4747
type Luck struct {

backend/pkg/api/types/mobile.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ type MobileWidgetData struct {
1313
ValidatorStateCounts ValidatorStateCounts `json:"validator_state_counts"`
1414
Last24hIncome ClElValue[decimal.Decimal] `json:"last_24h_income" faker:"eth"`
1515
Last7dIncome ClElValue[decimal.Decimal] `json:"last_7d_income" faker:"eth"`
16-
Last30dApr float64 `json:"last_30d_apr"`
17-
Last30dEfficiency float64 `json:"last_30d_efficiency"`
18-
NetworkEfficiency float64 `json:"network_efficiency"`
16+
Last30dApr *float64 `json:"last_30d_apr"`
17+
Last30dEfficiency *float64 `json:"last_30d_efficiency"`
18+
NetworkEfficiency *float64 `json:"network_efficiency"`
1919
RplPrice decimal.Decimal `json:"rpl_price" faker:"eth"`
20-
RplApr float64 `json:"rpl_apr"`
20+
RplApr *float64 `json:"rpl_apr"`
2121
ELCLPrice float64 `json:"el_cl_price"`
2222
}
2323

backend/pkg/api/types/validator_dashboard.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ type VDBOverviewData struct {
2525
Network uint64 `json:"network"`
2626
Groups []VDBOverviewGroup `json:"groups"`
2727
Validators ValidatorStateCounts `json:"validators"`
28-
Efficiency PeriodicValues[float64] `json:"efficiency"`
28+
Efficiency PeriodicValues[*float64] `json:"efficiency"`
2929
Rewards PeriodicValues[ClElValue[decimal.Decimal]] `json:"rewards"`
30-
Apr PeriodicValues[ClElValue[float64]] `json:"apr"`
30+
Apr PeriodicValues[ClElValue[*float64]] `json:"apr"`
3131
ChartHistorySeconds ChartHistorySeconds `json:"chart_history_seconds"`
3232
Balances ValidatorBalances `json:"balances"`
3333
IsAboveEbLimit bool `json:"is_above_effective_balance_limit"` // refers to owner; relevant for shared dashboards
@@ -58,7 +58,7 @@ type VDBSummaryTableRow struct {
5858
GroupId int64 `json:"group_id" extensions:"x-order=1"`
5959
Status VDBSummaryStatus `json:"status"`
6060
Validators VDBSummaryValidators `json:"validators"`
61-
Efficiency float64 `json:"efficiency"`
61+
Efficiency *float64 `json:"efficiency"`
6262
AverageNetworkEfficiency float64 `json:"average_network_efficiency"`
6363
Attestations StatusCount `json:"attestations"`
6464
Proposals StatusCount `json:"proposals"`
@@ -84,26 +84,26 @@ type VDBGroupSummaryMissedRewards struct {
8484
Sync decimal.Decimal `json:"sync"`
8585
}
8686
type VDBGroupSummaryData struct {
87-
Efficiency float64 `json:"efficiency"`
87+
Efficiency *float64 `json:"efficiency"`
8888
Balances ValidatorBalances `json:"balances"`
8989
Rewards ClElValue[decimal.Decimal] `json:"rewards"`
9090

9191
AttestationsHead StatusCount `json:"attestations_head"`
9292
AttestationsSource StatusCount `json:"attestations_source"`
9393
AttestationsTarget StatusCount `json:"attestations_target"`
94-
AttestationEfficiency float64 `json:"attestation_efficiency"`
94+
AttestationEfficiency *float64 `json:"attestation_efficiency"`
9595
AttestationAvgInclDist float64 `json:"attestation_avg_incl_dist"`
9696

9797
SyncCommittee VDBGroupSummaryColumnItem `json:"sync"`
9898
SyncCommitteeCount VDBGroupSummarySyncCount `json:"sync_count"`
99-
SyncEfficiency float64 `json:"sync_efficiency"`
99+
SyncEfficiency *float64 `json:"sync_efficiency"`
100100
Slashings VDBGroupSummaryColumnItem `json:"slashings"` // Failed slashings are count of validators in the group that were slashed
101101
ProposalValidators []uint64 `json:"proposal_validators"` // fill with up to 3 validator indexes
102102
ProposalValidatorCount uint64 `json:"proposal_validator_count"` // number of distinct validators
103-
ProposalEfficiency float64 `json:"proposal_efficiency"`
103+
ProposalEfficiency *float64 `json:"proposal_efficiency"`
104104
MissedRewards VDBGroupSummaryMissedRewards `json:"missed_rewards"`
105105

106-
Apr ClElValue[float64] `json:"apr"`
106+
Apr ClElValue[*float64] `json:"apr"`
107107

108108
Luck Luck `json:"luck"`
109109

frontend/types/api/common.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export interface Address {
3232
label?: string;
3333
}
3434
export interface LuckItem {
35-
percent: number /* float64 */;
35+
percent?: number /* float64 */;
3636
expected_timestamp: number /* uint64 */;
3737
average_interval_seconds: number /* uint64 */;
3838
}

frontend/types/api/mobile.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ export interface MobileWidgetData {
1414
validator_state_counts: ValidatorStateCounts;
1515
last_24h_income: ClElValue<string /* decimal.Decimal */>;
1616
last_7d_income: ClElValue<string /* decimal.Decimal */>;
17-
last_30d_apr: number /* float64 */;
18-
last_30d_efficiency: number /* float64 */;
19-
network_efficiency: number /* float64 */;
17+
last_30d_apr?: number /* float64 */;
18+
last_30d_efficiency?: number /* float64 */;
19+
network_efficiency?: number /* float64 */;
2020
rpl_price: string /* decimal.Decimal */;
21-
rpl_apr: number /* float64 */;
21+
rpl_apr?: number /* float64 */;
2222
el_cl_price: number /* float64 */;
2323
}
2424
export type InternalGetValidatorDashboardMobileWidgetResponse = ApiDataResponse<MobileWidgetData>;

frontend/types/api/validator_dashboard.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ export interface VDBOverviewData {
2121
network: number /* uint64 */;
2222
groups: VDBOverviewGroup[];
2323
validators: ValidatorStateCounts;
24-
efficiency: PeriodicValues<number /* float64 */>;
24+
efficiency: PeriodicValues<number /* float64 */ | undefined>;
2525
rewards: PeriodicValues<ClElValue<string /* decimal.Decimal */>>;
26-
apr: PeriodicValues<ClElValue<number /* float64 */>>;
26+
apr: PeriodicValues<ClElValue<number /* float64 */ | undefined>>;
2727
chart_history_seconds: ChartHistorySeconds;
2828
balances: ValidatorBalances;
2929
is_above_effective_balance_limit: boolean; // refers to owner; relevant for shared dashboards
@@ -47,7 +47,7 @@ export interface VDBSummaryTableRow {
4747
group_id: number /* int64 */;
4848
status: VDBSummaryStatus;
4949
validators: VDBSummaryValidators;
50-
efficiency: number /* float64 */;
50+
efficiency?: number /* float64 */;
5151
average_network_efficiency: number /* float64 */;
5252
attestations: StatusCount;
5353
proposals: StatusCount;
@@ -70,23 +70,23 @@ export interface VDBGroupSummaryMissedRewards {
7070
sync: string /* decimal.Decimal */;
7171
}
7272
export interface VDBGroupSummaryData {
73-
efficiency: number /* float64 */;
73+
efficiency?: number /* float64 */;
7474
balances: ValidatorBalances;
7575
rewards: ClElValue<string /* decimal.Decimal */>;
7676
attestations_head: StatusCount;
7777
attestations_source: StatusCount;
7878
attestations_target: StatusCount;
79-
attestation_efficiency: number /* float64 */;
79+
attestation_efficiency?: number /* float64 */;
8080
attestation_avg_incl_dist: number /* float64 */;
8181
sync: VDBGroupSummaryColumnItem;
8282
sync_count: VDBGroupSummarySyncCount;
83-
sync_efficiency: number /* float64 */;
83+
sync_efficiency?: number /* float64 */;
8484
slashings: VDBGroupSummaryColumnItem; // Failed slashings are count of validators in the group that were slashed
8585
proposal_validators: number /* uint64 */[]; // fill with up to 3 validator indexes
8686
proposal_validator_count: number /* uint64 */; // number of distinct validators
87-
proposal_efficiency: number /* float64 */;
87+
proposal_efficiency?: number /* float64 */;
8888
missed_rewards: VDBGroupSummaryMissedRewards;
89-
apr: ClElValue<number /* float64 */>;
89+
apr: ClElValue<number /* float64 */ | undefined>;
9090
luck: Luck;
9191
rocket_pool?: {
9292
minipools: number /* uint64 */;

0 commit comments

Comments
 (0)