@@ -23,42 +23,71 @@ func (d *Pegnetd) GetPegNetRateAverages(ctx context.Context, height uint32) (Avg
2323 return d .LastAverages
2424 }
2525
26- ratesOverPeriod := map [fat2.PTicker ][]uint64 {} // First collect all the values over the blocks
27- averages := map [fat2.PTicker ]uint64 {} // in the average period, then compute the averages
26+ ratesOverPeriod := d .LastAveragesData // First collect all the values over the blocks
27+ averages := map [fat2.PTicker ]uint64 {} // in the average period, then compute the averages
28+ if ratesOverPeriod == nil { // If no map exists yet
29+ ratesOverPeriod = map [fat2.PTicker ][]uint64 {} // create one.
30+ }
2831
2932 defer func () { // Always set up the cache when exiting the routine
30- d .LastAveragesHeight = height
31- d .LastAverages = averages
33+ d .LastAveragesData = ratesOverPeriod // Save the data we used to create averages
34+ d .LastAveragesHeight = height // Save the height of this data
35+ d .LastAverages = averages // Save the averages we computed
3236 }()
3337
34- startHeight := height - (uint32 (AveragePeriod )) + 1 // The startHeight is AveragePeriod before height+1
35- // (add 1 so the block at height is included)
36- if startHeight < 1 { // If AveragePeriod blocks don't exist, then ignore
37- return averages
38- }
39-
40- for h := startHeight ; height <= height ; h ++ { // Collect rates over the blocks (including height)
41- var rates map [fat2.PTicker ]uint64 // Collect all the rates
42- var err error
43-
44- if rates , err = d .Pegnet .SelectRates (ctx , h ); err != nil { // Pull the rates out of the database at each
45- return averages // height. Return averages if an error
38+ // collectRatesAtHeight
39+ // This routine collects all the data used to compute an average. If any data is missing, then
40+ // that data is represented by a zero.
41+ collectRatesAtHeight := func (h uint32 ) {
42+ for k := range ratesOverPeriod { // Make sure there is room for a new height
43+ for len (ratesOverPeriod [k ]) >= int (AveragePeriod ) { // If at the limit or above,
44+ copy (ratesOverPeriod [k ], ratesOverPeriod [k ][1 :]) // Shift data down 1 element
45+ ratesOverPeriod [k ] = ratesOverPeriod [k ][:len (ratesOverPeriod [k ])- 1 ] // And drop off the last value
46+ }
4647 }
4748
48- for k , v := range rates { // For all the rates
49- if ratesOverPeriod [k ] == nil { // if no rates yet, at a slice for them
50- ratesOverPeriod [k ] = []uint64 {} // Allocate the slice
51- }
52- if v != 0 { // Only collect non-zero rates
49+ if rates , err := d .Pegnet .SelectRates (ctx , h ); err != nil { // Pull the rates out of the database at each
50+ panic ("no recovery from a database error getting rates" )
51+ } else {
52+ for k , v := range rates { // For all the rates
53+ if ratesOverPeriod [k ] == nil { // if no rates yet, at a slice for them
54+ ratesOverPeriod [k ] = []uint64 {} // Allocate the slice
55+ }
5356 ratesOverPeriod [k ] = append (ratesOverPeriod [k ], v ) // Add the rates we find
5457 }
5558 }
5659 }
5760
58- for k , v := range ratesOverPeriod { // When we average the rates, we return a zero for
59- averages [k ] = 0 // any asset that doesn't have a rate in all blocks
60- if uint64 (len (v )) < AverageRequired { // We can see missing rates because the list isn't
61- continue // long enough. Too many missing rates, and we skip it
61+ switch {
62+ // If the LastAveragesHeight is out of range given our current height, we just need to load
63+ // all the values
64+ case d .LastAveragesHeight + 1 < height || d .LastAveragesHeight > height :
65+ for k , v := range ratesOverPeriod {
66+ if v != nil {
67+ ratesOverPeriod [k ] = ratesOverPeriod [k ][:0 ]
68+ }
69+ }
70+ startHeightS := int64 (height ) - (int64 (AveragePeriod )) + 1 // startHeight is AveragePeriod before height+1
71+ // (add 1 so the block at height is included)
72+ if startHeightS < 1 { // If AveragePeriod blocks don't exist,
73+ startHeightS = 1 // then flour the start to 1
74+ }
75+
76+ startHeight := uint32 (startHeightS )
77+
78+ for h := startHeight ; h <= height ; h ++ { // Collect rates over the blocks (including height)
79+ collectRatesAtHeight (h ) // and add them to ratesOverPeriod
80+ }
81+
82+ // If all we need is the next height, then only collect that height.
83+ case d .LastAveragesHeight + 1 == height :
84+ collectRatesAtHeight (height ) // Add the current height to the dataset so far
85+ }
86+
87+ for k , v := range ratesOverPeriod { // The average rate is zero for any asset without
88+ averages [k ] = 0 // the number of required rates
89+ if AveragePeriod - numberMissing (v ) < AverageRequired { // Count the missing values, and if not enough
90+ continue // skip it
6291 }
6392 for _ , v2 := range v { // Sum up all the rates found for an asset
6493 averages [k ] += v2 // The assumption is that rates are no where near
@@ -68,3 +97,15 @@ func (d *Pegnetd) GetPegNetRateAverages(ctx context.Context, height uint32) (Avg
6897
6998 return averages // Return the rates we found.
7099}
100+
101+ func numberMissing (dataset []uint64 ) (numZeros uint64 ) {
102+ for _ , v := range dataset {
103+ if v == 0 {
104+ numZeros ++
105+ }
106+ }
107+ if len (dataset ) < int (AveragePeriod ) {
108+ numZeros += AveragePeriod - uint64 (len (dataset ))
109+ }
110+ return numZeros
111+ }
0 commit comments