@@ -10,6 +10,7 @@ import (
1010 "sort"
1111 "strconv"
1212 "strings"
13+ "time"
1314
1415 "github.com/doug-martin/goqu/v9"
1516 _ "github.com/doug-martin/goqu/v9/dialect/postgres"
@@ -696,11 +697,11 @@ func (d *DataAccessService) GetValidatorDashboardRewardsChart(ctx context.Contex
696697 var err error
697698
698699 var dataTable exp.LiteralExpression
699- dataColumn := goqu .C ("t" )
700+ timeColumn := goqu .C ("t" )
700701 switch aggregation {
701702 case enums .IntervalEpoch :
702703 dataTable = goqu .L ("validator_dashboard_data_epoch AS e" )
703- dataColumn = goqu .C ("epoch_timestamp" )
704+ timeColumn = goqu .C ("epoch_timestamp" )
704705 case enums .IntervalHourly :
705706 dataTable = goqu .L ("validator_dashboard_data_hourly AS e FINAL" )
706707 case enums .IntervalDaily :
@@ -724,7 +725,10 @@ func (d *DataAccessService) GetValidatorDashboardRewardsChart(ctx context.Contex
724725 // Build the query that serves as base for both the main and EL rewards queries
725726 // CL
726727 rewardsDs := goqu .Dialect ("postgres" ).
727- Select (goqu .L (`SUM(COALESCE(e.attestations_reward, 0) + COALESCE(e.blocks_cl_reward, 0) + COALESCE(e.sync_reward, 0)) AS cl_rewards` )).
728+ Select (
729+ goqu .L (`SUM(COALESCE(e.attestations_reward, 0) + COALESCE(e.blocks_cl_reward, 0) + COALESCE(e.sync_reward, 0)) AS cl_rewards` ),
730+ timeColumn .As ("timestamp" ),
731+ ).
728732 From (dataTable ).
729733 With ("validators" , goqu .Dialect ("postgres" ).
730734 From (goqu .T ("users_val_dashboards_validators" )).
@@ -741,19 +745,19 @@ func (d *DataAccessService) GetValidatorDashboardRewardsChart(ctx context.Contex
741745 ),
742746 ).
743747 Where (
744- dataColumn .Between (goqu .Range (
748+ timeColumn .Between (goqu .Range (
745749 goqu .L ("fromUnixTimestamp(?)" , afterTs ),
746750 goqu .L ("fromUnixTimestamp(?)" , beforeTs ))),
747751 )
748752
749753 if aggregation == enums .IntervalEpoch {
750754 rewardsDs = rewardsDs .
751- SelectAppend (goqu .L ("e.epoch" ).As ("epoch_start" )).
752- SelectAppend (goqu .L ("e.epoch" ).As ("epoch_end" ))
755+ SelectAppend (goqu .L ("min( e.epoch) " ).As ("epoch_start" )).
756+ SelectAppend (goqu .L ("max( e.epoch) " ).As ("epoch_end" ))
753757 } else {
754758 rewardsDs = rewardsDs .
755- SelectAppend (goqu .L ("epoch_start" )).
756- SelectAppend (goqu .L ("epoch_end" ))
759+ SelectAppend (goqu .L ("min(epoch_start)" ). As ( " epoch_start" )).
760+ SelectAppend (goqu .L ("max(epoch_end)" ). As ( " epoch_end" ))
757761 }
758762
759763 // EL
@@ -767,8 +771,8 @@ func (d *DataAccessService) GetValidatorDashboardRewardsChart(ctx context.Contex
767771
768772 // grouping, ordering
769773 rewardsDs = rewardsDs .
770- GroupBy (goqu . L ( "epoch_start, epoch_end" ) ).
771- Order (goqu . L ( "epoch_start" ) .Asc ())
774+ GroupBy (timeColumn ).
775+ Order (timeColumn .Asc ())
772776
773777 elDs = elDs .
774778 GroupBy (goqu .L ("epoch_start, epoch_end" )).
@@ -809,10 +813,11 @@ func (d *DataAccessService) GetValidatorDashboardRewardsChart(ctx context.Contex
809813 // ------------------------------------------------------------------------------------------------------------------
810814 // Build the main query and get the data
811815 queryResult := []struct {
812- EpochStart uint64 `db:"epoch_start"`
813- EpochEnd uint64 `db:"epoch_end"`
814- GroupId uint64 `db:"result_group_id"`
815- ClRewards int64 `db:"cl_rewards"`
816+ Timestamp time.Time `db:"timestamp"`
817+ EpochStart uint64 `db:"epoch_start"`
818+ EpochEnd uint64 `db:"epoch_end"`
819+ GroupId uint64 `db:"result_group_id"`
820+ ClRewards int64 `db:"cl_rewards"`
816821 }{}
817822
818823 query , args , err := rewardsDs .Prepared (true ).ToSQL ()
@@ -829,11 +834,29 @@ func (d *DataAccessService) GetValidatorDashboardRewardsChart(ctx context.Contex
829834 return ret , nil
830835 }
831836
832- var epochStarts , epochEnds []uint64
837+ // deduplicate epoch boundaries & make sure they are correct even with newly activated validators
838+ type epochBoundaries struct {
839+ Start uint64
840+ End uint64
841+ }
842+ epochBoundariesMap := make (map [time.Time ]epochBoundaries )
833843 for _ , res := range queryResult {
834- epochStarts = append (epochStarts , res .EpochStart )
835- epochEnds = append (epochEnds , res .EpochEnd )
844+ curBoundary := epochBoundariesMap [res .Timestamp ]
845+ if epochBoundariesMap [res .Timestamp ].Start == 0 || epochBoundariesMap [res .Timestamp ].Start > res .EpochStart {
846+ curBoundary .Start = res .EpochStart
847+ }
848+ if epochBoundariesMap [res .Timestamp ].End < res .EpochEnd {
849+ curBoundary .End = res .EpochEnd
850+ }
851+ epochBoundariesMap [res .Timestamp ] = curBoundary
852+ }
853+ var epochStarts , epochEnds []uint64
854+ for _ , v := range epochBoundariesMap {
855+ epochStarts = append (epochStarts , v .Start )
856+ epochEnds = append (epochEnds , v .End )
836857 }
858+ slices .Sort (epochStarts )
859+ slices .Sort (epochEnds )
837860 elDs = elDs .
838861 With ("epoch_ranges(epoch_start, epoch_end)" , goqu .L ("(SELECT * FROM unnest(?::int[], ?::int[]))" , pq .Array (epochStarts ), pq .Array (epochEnds ))).
839862 InnerJoin (goqu .L ("epoch_ranges" ), goqu .On (goqu .L ("b.epoch BETWEEN epoch_ranges.epoch_start AND epoch_ranges.epoch_end" ))).
0 commit comments