forkplan9.go raw
1 package blockchain
2
3 import (
4 "fmt"
5 bits2 "github.com/p9c/p9/pkg/bits"
6 "github.com/p9c/p9/pkg/fork"
7 "math/big"
8 "strings"
9
10 "github.com/VividCortex/ewma"
11
12 "github.com/p9c/p9/pkg/wire"
13 )
14
15 // GetAlgStamps ...
16 func GetAlgStamps(algoName string, startHeight int32, lastNode *BlockNode) (last *BlockNode,
17 found bool, algStamps []int64, version int32,
18 ) {
19
20 version = fork.P9Algos[algoName].Version
21 for ln := lastNode; ln != nil && ln.height > startHeight &&
22 len(algStamps) <= int(fork.List[1].AveragingInterval); ln = ln.
23 RelativeAncestor(1) {
24 if ln.version == version && ln.height > startHeight {
25 algStamps = append(algStamps, ln.timestamp)
26 if !found {
27 found = true
28 last = ln
29 }
30 }
31 }
32 // D.Ln(algStamps)
33 // reverse order of stamps
34 for i := 0; i < len(algStamps)/2; i++ {
35 algStamps[i], algStamps[len(algStamps)-i-1] = algStamps[len(
36 algStamps,
37 )-i-1], algStamps[i]
38 }
39 // D.Ln(algStamps)
40 return
41 }
42
43 func GetAllStamps(startHeight int32, lastNode *BlockNode) (allStamps []int64) {
44
45 for ln := lastNode; ln != nil && ln.height > startHeight &&
46 len(allStamps) <= int(fork.List[1].AveragingInterval); ln = ln.RelativeAncestor(1) {
47 allStamps = append(allStamps, ln.timestamp)
48 }
49 // D.Ln(allStamps)
50 // reverse order of stamps
51 for i := 0; i < len(allStamps)/2; i++ {
52 allStamps[i], allStamps[len(allStamps)-i-1] =
53 allStamps[len(allStamps)-i-1], allStamps[i]
54 }
55 // D.Ln(allStamps)
56 return
57 }
58
59 func GetAll(allStamps []int64) (allAv, allAdj float64) {
60 allAdj = 1
61 allAv = fork.P9Average
62 // calculate intervals
63 allIntervals := make([]float64, len(allStamps)-1)
64 for i := range allStamps {
65 if i > 0 {
66 r := allStamps[i] - allStamps[i-1]
67 allIntervals[i-1] = float64(r)
68 }
69 }
70 // D.Ln(allStamps)
71 // calculate exponential weighted moving average from intervals
72 aewma := ewma.NewMovingAverage()
73 for _, x := range allIntervals {
74 aewma.Add(x)
75 }
76 allAv = aewma.Value()
77 // W.Ln(allAv)
78 if allAv != 0 {
79 allAdj = allAv / fork.P9Average
80 }
81 return
82 }
83
84 func GetAlg(algStamps []int64, targetTimePerBlock float64) (algAv, algAdj float64) {
85 // calculate intervals
86 algIntervals := make([]int64, len(algStamps)-1)
87 for i := range algStamps {
88 if i > 0 {
89 r := algStamps[i] - algStamps[i-1]
90 algIntervals[i-1] = r
91 }
92 }
93 // D.Ln(algStamps)
94 // calculate exponential weighted moving average from intervals
95 gewma := ewma.NewMovingAverage()
96 for _, x := range algIntervals {
97 gewma.Add(float64(x))
98 }
99 algAv = gewma.Value()
100 if algAv != 0 {
101 algAdj = algAv / targetTimePerBlock
102 }
103 return
104 }
105
106 // CalcNextRequiredDifficultyPlan9 returns the consensus difficulty adjustment by processing recent past blocks
107 func (b *BlockChain) CalcNextRequiredDifficultyPlan9(lastNodeP *BlockNode, algoName string,
108 l bool,
109 ) (newTargetBits uint32, adjustment float64, e error) {
110 lastNode := lastNodeP
111
112 algoVer := fork.GetAlgoVer(algoName, lastNode.height+1)
113 ttpb := float64(fork.List[1].Algos[algoName].VersionInterval)
114 newTargetBits = fork.SecondPowLimitBits
115 const minAvSamples = 3
116 adjustment = 1
117 var algAdj, allAdj, algAv, allAv float64 = 1, 1, ttpb, fork.P9Average
118 if lastNode == nil {
119 D.Ln("lastNode is nil")
120 }
121 // algoInterval := fork.P9Algos[algoname].VersionInterval
122 startHeight := fork.List[1].ActivationHeight
123 if b.params.Net == wire.TestNet3 {
124 startHeight = fork.List[1].TestnetStart
125 }
126 allStamps := GetAllStamps(startHeight, lastNode)
127 last, _, algStamps, algoVer := GetAlgStamps(algoName, startHeight, lastNode)
128 if len(allStamps) > minAvSamples {
129 allAv, allAdj = GetAll(allStamps)
130 }
131 if len(algStamps) > minAvSamples {
132 algAv, algAdj = GetAlg(algStamps, ttpb)
133 }
134 bits := fork.SecondPowLimitBits
135 if last != nil {
136 bits = last.bits
137 }
138 // D.Ln(
139 // "allAv", allAv,
140 // "fork.P9Average", fork.P9Average,
141 // "allAv/fork.P9Average", allAv/fork.P9Average,
142 // "algAv", algAv,
143 // "algAdj", algAdj,
144 // "allAdj", allAdj)
145
146 adjustment = algAdj * allAdj
147
148 // thisInterval := fork.P9AlgosNumeric[algoVer].VersionInterval
149 // baseInterval := fork.P9AlgosNumeric[5].VersionInterval
150 // timeFactor := float64(baseInterval) / float64(thisInterval)
151 // // if adjustment < 1 {
152 // // if the difficulty is adjusting upwards, accelerate it in proportion with block interval's ratio
153 // adjustment *= timeFactor
154 // // }
155
156 // adjustment *= adjustment
157 bigAdjustment := big.NewFloat(adjustment)
158 bigOldTarget := big.NewFloat(1.0).SetInt(bits2.CompactToBig(bits))
159 bigNewTargetFloat := big.NewFloat(1.0).Mul(bigAdjustment, bigOldTarget)
160 newTarget, _ := bigNewTargetFloat.Int(nil)
161 if newTarget == nil {
162 I.Ln("newTarget is nil ")
163 return
164 }
165 if newTarget.Cmp(&fork.FirstPowLimit) < 0 {
166 newTargetBits = bits2.BigToCompact(newTarget)
167 // Tracef("newTarget %064x %08x", newTarget, newTargetBits)
168 }
169 // if l {
170 // if lastNode.version == algoVer {
171 I.Ln(func() string {
172 an := fork.List[1].AlgoVers[algoVer]
173 pad := 8 - len(an)
174 if pad > 0 {
175 an += strings.Repeat(" ", pad)
176 }
177 factor := 1 / adjustment
178 symbol := ">"
179 if factor < 1 {
180 factor = adjustment
181 symbol = "<"
182 }
183 if factor == 1 {
184 symbol = "-"
185 }
186 isNewest := ""
187 if lastNode.version == algoVer {
188 isNewest = "*"
189 }
190 return fmt.Sprintf("%s %s av %s/%2.2f %s %s %08x %08x%s",
191 an,
192 RightJustify(fmt.Sprintf("%4.2f", algAv), 8),
193 RightJustify(fmt.Sprintf("%4.2f", allAv), 7),
194 fork.P9Average,
195 RightJustify(fmt.Sprintf("%4.2f", factor), 7),
196 symbol,
197 bits,
198 newTargetBits,
199 isNewest,
200 )
201 }(),
202 )
203 // }
204 // }
205 return
206 }
207
208 // CalcNextRequiredDifficultyPlan9old calculates the required difficulty for the block after the passed previous block node
209 // based on the difficulty retarget rules. This function differs from the exported CalcNextRequiredDifficulty in that
210 // the exported version uses the current best chain as the previous block node while this function accepts any block
211 // node.
212 func (b *BlockChain) CalcNextRequiredDifficultyPlan9old(lastNode *BlockNode, algoName string, l bool,
213 ) (newTargetBits uint32, adjustment float64, e error) {
214
215 nH := lastNode.height + 1
216 newTargetBits = fork.SecondPowLimitBits
217 adjustment = 1.0
218 if lastNode == nil || b.IsP9HardFork(nH) {
219 return
220 }
221 allTimeAv, allTimeDiv, qhourDiv, hourDiv,
222 dayDiv := b.GetCommonP9Averages(lastNode, nH)
223 algoVer := fork.GetAlgoVer(algoName, nH)
224 since, ttpb, timeSinceAlgo, startHeight, last := b.GetP9Since(lastNode, algoVer)
225 if last == nil {
226 return
227 }
228 algDiv := b.GetP9AlgoDiv(allTimeDiv, last, startHeight, algoVer, ttpb)
229 adjustment = (allTimeDiv + algDiv + dayDiv + hourDiv + qhourDiv +
230 timeSinceAlgo) / 6
231 bigAdjustment := big.NewFloat(adjustment)
232 bigOldTarget := big.NewFloat(1.0).SetInt(bits2.CompactToBig(last.bits))
233 bigNewTargetFloat := big.NewFloat(1.0).Mul(bigAdjustment, bigOldTarget)
234 newTarget, _ := bigNewTargetFloat.Int(nil)
235 if newTarget == nil {
236 I.Ln("newTarget is nil ")
237 return
238 }
239 if newTarget.Cmp(&fork.FirstPowLimit) < 0 {
240 newTargetBits = bits2.BigToCompact(newTarget)
241 T.F("newTarget %064x %08x", newTarget, newTargetBits)
242 }
243 if l {
244 an := fork.List[1].AlgoVers[algoVer]
245 pad := 9 - len(an)
246 if pad > 0 {
247 an += strings.Repeat(" ", pad)
248 }
249 D.C(func() string {
250 return fmt.Sprintf("hght: %d %08x %s %s %s %s %s %s %s"+
251 " %s %s %08x",
252 lastNode.height+1,
253 last.bits,
254 an,
255 RightJustify(fmt.Sprintf("%3.2f", allTimeAv), 5),
256 RightJustify(fmt.Sprintf("%3.2fa", allTimeDiv*ttpb), 7),
257 RightJustify(fmt.Sprintf("%3.2fd", dayDiv*ttpb), 7),
258 RightJustify(fmt.Sprintf("%3.2fh", hourDiv*ttpb), 7),
259 RightJustify(fmt.Sprintf("%3.2fq", qhourDiv*ttpb), 7),
260 RightJustify(fmt.Sprintf("%3.2fA", algDiv*ttpb), 7),
261 RightJustify(fmt.Sprintf("%3.0f %3.3fD",
262 since-ttpb*float64(len(fork.List[1].Algos)), timeSinceAlgo*ttpb,
263 ), 13,
264 ),
265 RightJustify(fmt.Sprintf("%4.4fx", 1/adjustment), 11),
266 newTargetBits,
267 )
268 },
269 )
270 }
271 return
272 }
273