Skip to content

Commit c84048a

Browse files
committed
Added a rate sampling threshhold to allow averaging with missing rates to avoid really long conversion stalls
1 parent d30b281 commit c84048a

2 files changed

Lines changed: 41 additions & 23 deletions

File tree

node/average.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import (
66
"github.com/pegnet/pegnetd/fat/fat2"
77
)
88

9-
const AveragePeriod = uint64(288) // Our Average Period is 2 days (144 10 minute blocks per day)
9+
const AveragePeriod = uint64(288) // Our Average Period is 2 days (144 10 minute blocks per day)
10+
const AverageRequired = AveragePeriod / 2 // If we have at least half the rates, we can do conversions
1011

1112
// getPegNetRateAverages
1213
// Gets all the rates for the AveragePeriod (the number of blocks contributing to the average), and computes
@@ -55,14 +56,14 @@ func (d *Pegnetd) GetPegNetRateAverages(ctx context.Context, height uint32) (Avg
5556
}
5657

5758
for k, v := range ratesOverPeriod { // When we average the rates, we return a zero for
58-
averages[k] = 0 // any asset that doesn't have a rate in all blocks
59-
if uint64(len(v)) != AveragePeriod { // We can see missing rates because the list isn't
60-
continue // long enough. Just skip it, it will be zero
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
6162
}
6263
for _, v2 := range v { // Sum up all the rates found for an asset
63-
averages[k] += v2
64-
}
65-
averages[k] = averages[k] / AveragePeriod // We made sure all valid assets have AveragePeriod rates
64+
averages[k] += v2 // The assumption is that rates are no where near
65+
} // 64 bits, so they won't overflow
66+
averages[k] = averages[k] / uint64(len(v)) // Divide the sum of the rates by the number of rates
6667
}
6768

6869
return averages // Return the rates we found.

node/conversions/conversions.go

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,45 @@ import (
77
"github.com/pegnet/pegnetd/config"
88
)
99

10-
// Convert takes an input amount and returns an output amount that can be created
10+
// Convert
11+
// takes an input amount and returns an output amount that can be created
1112
// from it, given the two rates `fromRate` and `toRate` denominated in 1e-8 USD.
1213
// All parameters must be in their lowest divisible unit as whole numbers.
13-
// X fromType -> ?? toType
1414
//
15-
// X fromType fromRate USD 1 toType
16-
// ---------- * ------------ * ---------- = ?? toType
15+
// Prior to PIP-10:
16+
// RateSource = fromRate
17+
// RateDest = toRate
18+
//
19+
// Under PIP-10:
20+
// RateSource = min(fromRate, fromAvg)
21+
// RateDest = max(toRate, toAvg)
22+
//
23+
// A Source Tokens
24+
// X Destination Tokens
25+
//
26+
// A fromRate USD 1
27+
// ---------- * ------------ * ---------- = X
1728
// 1 1 fromType toRate USD
29+
//
1830
func Convert(height uint32, amount int64, fromRate, fromAvg, toRate, toAvg uint64) (int64, error) {
19-
if amount < 0 {
20-
return 0, fmt.Errorf("invalid amount: must be greater than or equal to zero")
21-
}
22-
if fromRate == 0 || toRate == 0 {
23-
return 0, fmt.Errorf("invalid rate: 0")
31+
if amount < 0 { // Must have something to convert; negative numbers
32+
return 0, fmt.Errorf("invalid amount: must be greater than or equal to zero") // do not qualify
2433
}
2534

26-
if height >= config.PIP10AverageActivation {
27-
if fromRate > fromAvg {
28-
fromRate = fromAvg
35+
if fromRate == 0 || toRate == 0 { // If either rate (fromRate or toRate) is zero
36+
return 0, fmt.Errorf("invalid rate: 0") // then we can't do the conversion
37+
}
38+
RateSource := fromRate
39+
RateDest := toRate
40+
if height >= config.PIP10AverageActivation { // Check that PIP-10 has been activated.
41+
if fromAvg == 0 || toAvg == 0 { // If either Average (fromAvg or toAvg) is zero
42+
return 0, fmt.Errorf("invalid rate: 0") // then we can't do the conversion
43+
}
44+
if fromRate > fromAvg { // Use the min(fromRate, fromAvg)
45+
RateSource = fromAvg
2946
}
30-
if toRate < toAvg {
31-
toRate = toAvg
47+
if toRate < toAvg { // Use the max(toRate,toAvg)
48+
RateDest = toAvg
3249
}
3350
}
3451

@@ -37,8 +54,8 @@ func Convert(height uint32, amount int64, fromRate, fromAvg, toRate, toAvg uint6
3754
// accuracy a miner reports. Anything beyond the 8th decimal point, we cannot account for.
3855
//
3956
// Uses big ints to avoid overflows.
40-
fr := new(big.Int).SetUint64(fromRate)
41-
tr := new(big.Int).SetUint64(toRate)
57+
fr := new(big.Int).SetUint64(RateSource)
58+
tr := new(big.Int).SetUint64(RateDest)
4259
amt := big.NewInt(amount)
4360

4461
// Now we can run the conversion

0 commit comments

Comments
 (0)