forked from decred/dcrd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
difficulty.go
1514 lines (1310 loc) · 54.2 KB
/
difficulty.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2015-2017 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain
import (
"fmt"
"math/big"
"time"
"github.com/decred/dcrd/chaincfg"
"github.com/decred/dcrd/chaincfg/chainhash"
"github.com/decred/dcrd/wire"
)
var (
// bigZero is 0 represented as a big.Int. It is defined here to avoid
// the overhead of creating it multiple times.
bigZero = big.NewInt(0)
// bigOne is 1 represented as a big.Int. It is defined here to avoid
// the overhead of creating it multiple times.
bigOne = big.NewInt(1)
// oneLsh256 is 1 shifted left 256 bits. It is defined here to avoid
// the overhead of creating it multiple times.
oneLsh256 = new(big.Int).Lsh(bigOne, 256)
)
// maxShift is the maximum shift for a difficulty that resets (e.g.
// testnet difficulty).
const maxShift = uint(256)
// HashToBig converts a chainhash.Hash into a big.Int that can be used to
// perform math comparisons.
func HashToBig(hash *chainhash.Hash) *big.Int {
// A Hash is in little-endian, but the big package wants the bytes in
// big-endian, so reverse them.
buf := *hash
blen := len(buf)
for i := 0; i < blen/2; i++ {
buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i]
}
return new(big.Int).SetBytes(buf[:])
}
// CompactToBig converts a compact representation of a whole number N to an
// unsigned 32-bit number. The representation is similar to IEEE754 floating
// point numbers.
//
// Like IEEE754 floating point, there are three basic components: the sign,
// the exponent, and the mantissa. They are broken out as follows:
//
// * the most significant 8 bits represent the unsigned base 256 exponent
// * bit 23 (the 24th bit) represents the sign bit
// * the least significant 23 bits represent the mantissa
//
// -------------------------------------------------
// | Exponent | Sign | Mantissa |
// -------------------------------------------------
// | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] |
// -------------------------------------------------
//
// The formula to calculate N is:
// N = (-1^sign) * mantissa * 256^(exponent-3)
//
// This compact form is only used in decred to encode unsigned 256-bit numbers
// which represent difficulty targets, thus there really is not a need for a
// sign bit, but it is implemented here to stay consistent with bitcoind.
func CompactToBig(compact uint32) *big.Int {
// Extract the mantissa, sign bit, and exponent.
mantissa := compact & 0x007fffff
isNegative := compact&0x00800000 != 0
exponent := uint(compact >> 24)
// Since the base for the exponent is 256, the exponent can be treated
// as the number of bytes to represent the full 256-bit number. So,
// treat the exponent as the number of bytes and shift the mantissa
// right or left accordingly. This is equivalent to:
// N = mantissa * 256^(exponent-3)
var bn *big.Int
if exponent <= 3 {
mantissa >>= 8 * (3 - exponent)
bn = big.NewInt(int64(mantissa))
} else {
bn = big.NewInt(int64(mantissa))
bn.Lsh(bn, 8*(exponent-3))
}
// Make it negative if the sign bit is set.
if isNegative {
bn = bn.Neg(bn)
}
return bn
}
// BigToCompact converts a whole number N to a compact representation using
// an unsigned 32-bit number. The compact representation only provides 23 bits
// of precision, so values larger than (2^23 - 1) only encode the most
// significant digits of the number. See CompactToBig for details.
func BigToCompact(n *big.Int) uint32 {
// No need to do any work if it's zero.
if n.Sign() == 0 {
return 0
}
// Since the base for the exponent is 256, the exponent can be treated
// as the number of bytes. So, shift the number right or left
// accordingly. This is equivalent to:
// mantissa = mantissa / 256^(exponent-3)
var mantissa uint32
exponent := uint(len(n.Bytes()))
if exponent <= 3 {
mantissa = uint32(n.Bits()[0])
mantissa <<= 8 * (3 - exponent)
} else {
// Use a copy to avoid modifying the caller's original number.
tn := new(big.Int).Set(n)
mantissa = uint32(tn.Rsh(tn, 8*(exponent-3)).Bits()[0])
}
// When the mantissa already has the sign bit set, the number is too
// large to fit into the available 23-bits, so divide the number by 256
// and increment the exponent accordingly.
if mantissa&0x00800000 != 0 {
mantissa >>= 8
exponent++
}
// Pack the exponent, sign bit, and mantissa into an unsigned 32-bit
// int and return it.
compact := uint32(exponent<<24) | mantissa
if n.Sign() < 0 {
compact |= 0x00800000
}
return compact
}
// CalcWork calculates a work value from difficulty bits. Decred increases
// the difficulty for generating a block by decreasing the value which the
// generated hash must be less than. This difficulty target is stored in each
// block header using a compact representation as described in the documentation
// for CompactToBig. The main chain is selected by choosing the chain that has
// the most proof of work (highest difficulty). Since a lower target difficulty
// value equates to higher actual difficulty, the work value which will be
// accumulated must be the inverse of the difficulty. Also, in order to avoid
// potential division by zero and really small floating point numbers, the
// result adds 1 to the denominator and multiplies the numerator by 2^256.
func CalcWork(bits uint32) *big.Int {
// Return a work value of zero if the passed difficulty bits represent
// a negative number. Note this should not happen in practice with valid
// blocks, but an invalid block could trigger it.
difficultyNum := CompactToBig(bits)
if difficultyNum.Sign() <= 0 {
return big.NewInt(0)
}
// (1 << 256) / (difficultyNum + 1)
denominator := new(big.Int).Add(difficultyNum, bigOne)
return new(big.Int).Div(oneLsh256, denominator)
}
// calcEasiestDifficulty calculates the easiest possible difficulty that a block
// can have given starting difficulty bits and a duration. It is mainly used to
// verify that claimed proof of work by a block is sane as compared to a
// known good checkpoint.
func (b *BlockChain) calcEasiestDifficulty(bits uint32,
duration time.Duration) uint32 {
// Convert types used in the calculations below.
durationVal := int64(duration)
adjustmentFactor := big.NewInt(b.chainParams.RetargetAdjustmentFactor)
maxRetargetTimespan := int64(b.chainParams.TargetTimespan) *
b.chainParams.RetargetAdjustmentFactor
// The test network rules allow minimum difficulty blocks once too much
// time has elapsed without mining a block.
if b.chainParams.ReduceMinDifficulty {
if durationVal > int64(b.chainParams.MinDiffReductionTime) {
return b.chainParams.PowLimitBits
}
}
// Since easier difficulty equates to higher numbers, the easiest
// difficulty for a given duration is the largest value possible given
// the number of retargets for the duration and starting difficulty
// multiplied by the max adjustment factor.
newTarget := CompactToBig(bits)
for durationVal > 0 && newTarget.Cmp(b.chainParams.PowLimit) < 0 {
newTarget.Mul(newTarget, adjustmentFactor)
durationVal -= maxRetargetTimespan
}
// Limit new value to the proof of work limit.
if newTarget.Cmp(b.chainParams.PowLimit) > 0 {
newTarget.Set(b.chainParams.PowLimit)
}
return BigToCompact(newTarget)
}
// findPrevTestNetDifficulty returns the difficulty of the previous block which
// did not have the special testnet minimum difficulty rule applied.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) findPrevTestNetDifficulty(startNode *blockNode) (uint32, error) {
// Search backwards through the chain for the last block without
// the special rule applied.
blocksPerRetarget := b.chainParams.WorkDiffWindowSize *
b.chainParams.WorkDiffWindows
iterNode := startNode
for iterNode != nil && iterNode.height%blocksPerRetarget != 0 &&
iterNode.header.Bits == b.chainParams.PowLimitBits {
// Get the previous block node. This function is used over
// simply accessing iterNode.parent directly as it will
// dynamically create previous block nodes as needed. This
// helps allow only the pieces of the chain that are needed
// to remain in memory.
var err error
iterNode, err = b.getPrevNodeFromNode(iterNode)
if err != nil {
log.Errorf("getPrevNodeFromNode: %v", err)
return 0, err
}
}
// Return the found difficulty or the minimum difficulty if no
// appropriate block was found.
lastBits := b.chainParams.PowLimitBits
if iterNode != nil {
lastBits = iterNode.header.Bits
}
return lastBits, nil
}
// calcNextRequiredDifficulty calculates the required difficulty for the block
// after the passed previous block node based on the difficulty retarget rules.
// This function differs from the exported CalcNextRequiredDifficulty in that
// the exported version uses the current best chain as the previous block node
// while this function accepts any block node.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) calcNextRequiredDifficulty(curNode *blockNode,
newBlockTime time.Time) (uint32, error) {
// Genesis block.
if curNode == nil {
return b.chainParams.PowLimitBits, nil
}
// Get the old difficulty; if we aren't at a block height where it changes,
// just return this.
oldDiff := curNode.header.Bits
oldDiffBig := CompactToBig(curNode.header.Bits)
// We're not at a retarget point, return the oldDiff.
if (curNode.height+1)%b.chainParams.WorkDiffWindowSize != 0 {
// For networks that support it, allow special reduction of the
// required difficulty once too much time has elapsed without
// mining a block.
if b.chainParams.ReduceMinDifficulty {
// Return minimum difficulty when more than the desired
// amount of time has elapsed without mining a block.
reductionTime := b.chainParams.MinDiffReductionTime
allowMinTime := curNode.header.Timestamp.Add(reductionTime)
// For every extra target timespan that passes, we halve the
// difficulty.
if newBlockTime.After(allowMinTime) {
timePassed := newBlockTime.Sub(curNode.header.Timestamp)
timePassed -= b.chainParams.MinDiffReductionTime
shifts := uint((timePassed / b.chainParams.TargetTimePerBlock) + 1)
// Scale the difficulty with time passed.
oldTarget := CompactToBig(curNode.header.Bits)
newTarget := new(big.Int)
if shifts < maxShift {
newTarget.Lsh(oldTarget, shifts)
} else {
newTarget.Set(oneLsh256)
}
// Limit new value to the proof of work limit.
if newTarget.Cmp(b.chainParams.PowLimit) > 0 {
newTarget.Set(b.chainParams.PowLimit)
}
return BigToCompact(newTarget), nil
}
// The block was mined within the desired timeframe, so
// return the difficulty for the last block which did
// not have the special minimum difficulty rule applied.
prevBits, err := b.findPrevTestNetDifficulty(curNode)
if err != nil {
return 0, err
}
return prevBits, nil
}
return oldDiff, nil
}
// Declare some useful variables.
RAFBig := big.NewInt(b.chainParams.RetargetAdjustmentFactor)
nextDiffBigMin := CompactToBig(curNode.header.Bits)
nextDiffBigMin.Div(nextDiffBigMin, RAFBig)
nextDiffBigMax := CompactToBig(curNode.header.Bits)
nextDiffBigMax.Mul(nextDiffBigMax, RAFBig)
alpha := b.chainParams.WorkDiffAlpha
// Number of nodes to traverse while calculating difficulty.
nodesToTraverse := (b.chainParams.WorkDiffWindowSize *
b.chainParams.WorkDiffWindows)
// Initialize bigInt slice for the percentage changes for each window period
// above or below the target.
windowChanges := make([]*big.Int, b.chainParams.WorkDiffWindows)
// Regress through all of the previous blocks and store the percent changes
// per window period; use bigInts to emulate 64.32 bit fixed point.
oldNode := curNode
windowPeriod := int64(0)
weights := uint64(0)
recentTime := curNode.header.Timestamp.UnixNano()
olderTime := int64(0)
for i := int64(0); ; i++ {
// Store and reset after reaching the end of every window period.
if i%b.chainParams.WorkDiffWindowSize == 0 && i != 0 {
olderTime = oldNode.header.Timestamp.UnixNano()
timeDifference := recentTime - olderTime
// Just assume we're at the target (no change) if we've
// gone all the way back to the genesis block.
if oldNode.height == 0 {
timeDifference = int64(b.chainParams.TargetTimespan)
}
timeDifBig := big.NewInt(timeDifference)
timeDifBig.Lsh(timeDifBig, 32) // Add padding
targetTemp := big.NewInt(int64(b.chainParams.TargetTimespan))
windowAdjusted := targetTemp.Div(timeDifBig, targetTemp)
// Weight it exponentially. Be aware that this could at some point
// overflow if alpha or the number of blocks used is really large.
windowAdjusted = windowAdjusted.Lsh(windowAdjusted,
uint((b.chainParams.WorkDiffWindows-windowPeriod)*alpha))
// Sum up all the different weights incrementally.
weights += 1 << uint64((b.chainParams.WorkDiffWindows-windowPeriod)*
alpha)
// Store it in the slice.
windowChanges[windowPeriod] = windowAdjusted
windowPeriod++
recentTime = olderTime
}
if i == nodesToTraverse {
break // Exit for loop when we hit the end.
}
// Get the previous block node. This function is used over
// simply accessing firstNode.parent directly as it will
// dynamically create previous block nodes as needed. This
// helps allow only the pieces of the chain that are needed
// to remain in memory.
var err error
tempNode := oldNode
oldNode, err = b.getPrevNodeFromNode(oldNode)
if err != nil {
return 0, err
}
// If we're at the genesis block, reset the oldNode
// so that it stays at the genesis block.
if oldNode == nil {
oldNode = tempNode
}
}
// Sum up the weighted window periods.
weightedSum := big.NewInt(0)
for i := int64(0); i < b.chainParams.WorkDiffWindows; i++ {
weightedSum.Add(weightedSum, windowChanges[i])
}
// Divide by the sum of all weights.
weightsBig := big.NewInt(int64(weights))
weightedSumDiv := weightedSum.Div(weightedSum, weightsBig)
// Multiply by the old diff.
nextDiffBig := weightedSumDiv.Mul(weightedSumDiv, oldDiffBig)
// Right shift to restore the original padding (restore non-fixed point).
nextDiffBig = nextDiffBig.Rsh(nextDiffBig, 32)
// Check to see if we're over the limits for the maximum allowable retarget;
// if we are, return the maximum or minimum except in the case that oldDiff
// is zero.
if oldDiffBig.Cmp(bigZero) == 0 { // This should never really happen,
nextDiffBig.Set(nextDiffBig) // but in case it does...
} else if nextDiffBig.Cmp(bigZero) == 0 {
nextDiffBig.Set(b.chainParams.PowLimit)
} else if nextDiffBig.Cmp(nextDiffBigMax) == 1 {
nextDiffBig.Set(nextDiffBigMax)
} else if nextDiffBig.Cmp(nextDiffBigMin) == -1 {
nextDiffBig.Set(nextDiffBigMin)
}
// Limit new value to the proof of work limit.
if nextDiffBig.Cmp(b.chainParams.PowLimit) > 0 {
nextDiffBig.Set(b.chainParams.PowLimit)
}
// Log new target difficulty and return it. The new target logging is
// intentionally converting the bits back to a number instead of using
// newTarget since conversion to the compact representation loses
// precision.
nextDiffBits := BigToCompact(nextDiffBig)
log.Debugf("Difficulty retarget at block height %d", curNode.height+1)
log.Debugf("Old target %08x (%064x)", curNode.header.Bits, oldDiffBig)
log.Debugf("New target %08x (%064x)", nextDiffBits, CompactToBig(nextDiffBits))
return nextDiffBits, nil
}
// CalcNextRequiredDiffFromNode calculates the required difficulty for the block
// given with the passed hash along with the given timestamp.
//
// This function is NOT safe for concurrent access.
func (b *BlockChain) CalcNextRequiredDiffFromNode(hash *chainhash.Hash,
timestamp time.Time) (uint32, error) {
// Fetch the block to get the difficulty for.
node, err := b.findNode(hash, maxSearchDepth)
if err != nil {
return 0, err
}
return b.calcNextRequiredDifficulty(node, timestamp)
}
// CalcNextRequiredDifficulty calculates the required difficulty for the block
// after the end of the current best chain based on the difficulty retarget
// rules.
//
// This function is safe for concurrent access.
func (b *BlockChain) CalcNextRequiredDifficulty(timestamp time.Time) (uint32,
error) {
b.chainLock.Lock()
difficulty, err := b.calcNextRequiredDifficulty(b.bestNode, timestamp)
b.chainLock.Unlock()
return difficulty, err
}
// mergeDifficulty takes an original stake difficulty and two new, scaled
// stake difficulties, merges the new difficulties, and outputs a new
// merged stake difficulty.
func mergeDifficulty(oldDiff int64, newDiff1 int64, newDiff2 int64) int64 {
newDiff1Big := big.NewInt(newDiff1)
newDiff2Big := big.NewInt(newDiff2)
newDiff2Big.Lsh(newDiff2Big, 32)
oldDiffBig := big.NewInt(oldDiff)
oldDiffBigLSH := big.NewInt(oldDiff)
oldDiffBigLSH.Lsh(oldDiffBig, 32)
newDiff1Big.Div(oldDiffBigLSH, newDiff1Big)
newDiff2Big.Div(newDiff2Big, oldDiffBig)
// Combine the two changes in difficulty.
summedChange := big.NewInt(0)
summedChange.Set(newDiff2Big)
summedChange.Lsh(summedChange, 32)
summedChange.Div(summedChange, newDiff1Big)
summedChange.Mul(summedChange, oldDiffBig)
summedChange.Rsh(summedChange, 32)
return summedChange.Int64()
}
// calcNextRequiredStakeDifficultyV1 calculates the required stake difficulty
// for the block after the passed previous block node based on exponentially
// weighted averages.
//
// NOTE: This is the original stake difficulty algorithm that was used at Decred
// launch.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) calcNextRequiredStakeDifficultyV1(curNode *blockNode) (int64, error) {
alpha := b.chainParams.StakeDiffAlpha
stakeDiffStartHeight := int64(b.chainParams.CoinbaseMaturity) +
1
maxRetarget := b.chainParams.RetargetAdjustmentFactor
TicketPoolWeight := int64(b.chainParams.TicketPoolSizeWeight)
// Number of nodes to traverse while calculating difficulty.
nodesToTraverse := (b.chainParams.StakeDiffWindowSize *
b.chainParams.StakeDiffWindows)
// Genesis block. Block at height 1 has these parameters.
// Additionally, if we're before the time when people generally begin
// purchasing tickets, just use the MinimumStakeDiff.
// This is sort of sloppy and coded with the hopes that generally by
// stakeDiffStartHeight people will be submitting lots of SStx over the
// past nodesToTraverse many nodes. It should be okay with the default
// Decred parameters, but might do weird things if you use custom
// parameters.
if curNode == nil ||
curNode.height < stakeDiffStartHeight {
return b.chainParams.MinimumStakeDiff, nil
}
// Get the old difficulty; if we aren't at a block height where it changes,
// just return this.
oldDiff := curNode.header.SBits
if (curNode.height+1)%b.chainParams.StakeDiffWindowSize != 0 {
return oldDiff, nil
}
// The target size of the ticketPool in live tickets. Recast these as int64
// to avoid possible overflows for large sizes of either variable in
// params.
targetForTicketPool := int64(b.chainParams.TicketsPerBlock) *
int64(b.chainParams.TicketPoolSize)
// Initialize bigInt slice for the percentage changes for each window period
// above or below the target.
windowChanges := make([]*big.Int, b.chainParams.StakeDiffWindows)
// Regress through all of the previous blocks and store the percent changes
// per window period; use bigInts to emulate 64.32 bit fixed point.
oldNode := curNode
windowPeriod := int64(0)
weights := uint64(0)
for i := int64(0); ; i++ {
// Store and reset after reaching the end of every window period.
if (i+1)%b.chainParams.StakeDiffWindowSize == 0 {
// First adjust based on ticketPoolSize. Skew the difference
// in ticketPoolSize by max adjustment factor to help
// weight ticket pool size versus tickets per block.
poolSizeSkew := (int64(oldNode.header.PoolSize)-
targetForTicketPool)*TicketPoolWeight + targetForTicketPool
// Don't let this be negative or zero.
if poolSizeSkew <= 0 {
poolSizeSkew = 1
}
curPoolSizeTemp := big.NewInt(poolSizeSkew)
curPoolSizeTemp.Lsh(curPoolSizeTemp, 32) // Add padding
targetTemp := big.NewInt(targetForTicketPool)
windowAdjusted := curPoolSizeTemp.Div(curPoolSizeTemp, targetTemp)
// Weight it exponentially. Be aware that this could at some point
// overflow if alpha or the number of blocks used is really large.
windowAdjusted = windowAdjusted.Lsh(windowAdjusted,
uint((b.chainParams.StakeDiffWindows-windowPeriod)*alpha))
// Sum up all the different weights incrementally.
weights += 1 << uint64((b.chainParams.StakeDiffWindows-windowPeriod)*
alpha)
// Store it in the slice.
windowChanges[windowPeriod] = windowAdjusted
// windowFreshStake = 0
windowPeriod++
}
if (i + 1) == nodesToTraverse {
break // Exit for loop when we hit the end.
}
// Get the previous block node.
var err error
tempNode := oldNode
oldNode, err = b.getPrevNodeFromNode(oldNode)
if err != nil {
return 0, err
}
// If we're at the genesis block, reset the oldNode
// so that it stays at the genesis block.
if oldNode == nil {
oldNode = tempNode
}
}
// Sum up the weighted window periods.
weightedSum := big.NewInt(0)
for i := int64(0); i < b.chainParams.StakeDiffWindows; i++ {
weightedSum.Add(weightedSum, windowChanges[i])
}
// Divide by the sum of all weights.
weightsBig := big.NewInt(int64(weights))
weightedSumDiv := weightedSum.Div(weightedSum, weightsBig)
// Multiply by the old stake diff.
oldDiffBig := big.NewInt(oldDiff)
nextDiffBig := weightedSumDiv.Mul(weightedSumDiv, oldDiffBig)
// Right shift to restore the original padding (restore non-fixed point).
nextDiffBig = nextDiffBig.Rsh(nextDiffBig, 32)
nextDiffTicketPool := nextDiffBig.Int64()
// Check to see if we're over the limits for the maximum allowable retarget;
// if we are, return the maximum or minimum except in the case that oldDiff
// is zero.
if oldDiff == 0 { // This should never really happen, but in case it does...
return nextDiffTicketPool, nil
} else if nextDiffTicketPool == 0 {
nextDiffTicketPool = oldDiff / maxRetarget
} else if (nextDiffTicketPool / oldDiff) > (maxRetarget - 1) {
nextDiffTicketPool = oldDiff * maxRetarget
} else if (oldDiff / nextDiffTicketPool) > (maxRetarget - 1) {
nextDiffTicketPool = oldDiff / maxRetarget
}
// The target number of new SStx per block for any given window period.
targetForWindow := b.chainParams.StakeDiffWindowSize *
int64(b.chainParams.TicketsPerBlock)
// Regress through all of the previous blocks and store the percent changes
// per window period; use bigInts to emulate 64.32 bit fixed point.
oldNode = curNode
windowFreshStake := int64(0)
windowPeriod = int64(0)
weights = uint64(0)
for i := int64(0); ; i++ {
// Add the fresh stake into the store for this window period.
windowFreshStake += int64(oldNode.header.FreshStake)
// Store and reset after reaching the end of every window period.
if (i+1)%b.chainParams.StakeDiffWindowSize == 0 {
// Don't let fresh stake be zero.
if windowFreshStake <= 0 {
windowFreshStake = 1
}
freshTemp := big.NewInt(windowFreshStake)
freshTemp.Lsh(freshTemp, 32) // Add padding
targetTemp := big.NewInt(targetForWindow)
// Get the percentage change.
windowAdjusted := freshTemp.Div(freshTemp, targetTemp)
// Weight it exponentially. Be aware that this could at some point
// overflow if alpha or the number of blocks used is really large.
windowAdjusted = windowAdjusted.Lsh(windowAdjusted,
uint((b.chainParams.StakeDiffWindows-windowPeriod)*alpha))
// Sum up all the different weights incrementally.
weights += 1 <<
uint64((b.chainParams.StakeDiffWindows-windowPeriod)*alpha)
// Store it in the slice.
windowChanges[windowPeriod] = windowAdjusted
windowFreshStake = 0
windowPeriod++
}
if (i + 1) == nodesToTraverse {
break // Exit for loop when we hit the end.
}
// Get the previous block node.
var err error
tempNode := oldNode
oldNode, err = b.getPrevNodeFromNode(oldNode)
if err != nil {
return 0, err
}
// If we're at the genesis block, reset the oldNode
// so that it stays at the genesis block.
if oldNode == nil {
oldNode = tempNode
}
}
// Sum up the weighted window periods.
weightedSum = big.NewInt(0)
for i := int64(0); i < b.chainParams.StakeDiffWindows; i++ {
weightedSum.Add(weightedSum, windowChanges[i])
}
// Divide by the sum of all weights.
weightsBig = big.NewInt(int64(weights))
weightedSumDiv = weightedSum.Div(weightedSum, weightsBig)
// Multiply by the old stake diff.
oldDiffBig = big.NewInt(oldDiff)
nextDiffBig = weightedSumDiv.Mul(weightedSumDiv, oldDiffBig)
// Right shift to restore the original padding (restore non-fixed point).
nextDiffBig = nextDiffBig.Rsh(nextDiffBig, 32)
nextDiffFreshStake := nextDiffBig.Int64()
// Check to see if we're over the limits for the maximum allowable retarget;
// if we are, return the maximum or minimum except in the case that oldDiff
// is zero.
if oldDiff == 0 { // This should never really happen, but in case it does...
return nextDiffFreshStake, nil
} else if nextDiffFreshStake == 0 {
nextDiffFreshStake = oldDiff / maxRetarget
} else if (nextDiffFreshStake / oldDiff) > (maxRetarget - 1) {
nextDiffFreshStake = oldDiff * maxRetarget
} else if (oldDiff / nextDiffFreshStake) > (maxRetarget - 1) {
nextDiffFreshStake = oldDiff / maxRetarget
}
// Average the two differences using scaled multiplication.
nextDiff := mergeDifficulty(oldDiff, nextDiffTicketPool, nextDiffFreshStake)
// Check to see if we're over the limits for the maximum allowable retarget;
// if we are, return the maximum or minimum except in the case that oldDiff
// is zero.
if oldDiff == 0 { // This should never really happen, but in case it does...
return oldDiff, nil
} else if nextDiff == 0 {
nextDiff = oldDiff / maxRetarget
} else if (nextDiff / oldDiff) > (maxRetarget - 1) {
nextDiff = oldDiff * maxRetarget
} else if (oldDiff / nextDiff) > (maxRetarget - 1) {
nextDiff = oldDiff / maxRetarget
}
// If the next diff is below the network minimum, set the required stake
// difficulty to the minimum.
if nextDiff < b.chainParams.MinimumStakeDiff {
return b.chainParams.MinimumStakeDiff, nil
}
return nextDiff, nil
}
// estimateSupply returns an estimate of the coin supply for the provided block
// height. This is primarily used in the stake difficulty algorithm and relies
// on an estimate to simplify the necessary calculations. The actual total
// coin supply as of a given block height depends on many factors such as the
// number of votes included in every prior block (not including all votes
// reduces the subsidy) and whether or not any of the prior blocks have been
// invalidated by stakeholders thereby removing the PoW subsidy for them.
//
// This function is safe for concurrent access.
func estimateSupply(params *chaincfg.Params, height int64) int64 {
if height <= 0 {
return 0
}
// Estimate the supply by calculating the full block subsidy for each
// reduction interval and multiplying it the number of blocks in the
// interval then adding the subsidy produced by number of blocks in the
// current interval.
supply := params.BlockOneSubsidy()
reductions := int64(height) / params.SubsidyReductionInterval
subsidy := params.BaseSubsidy
for i := int64(0); i < reductions; i++ {
supply += params.SubsidyReductionInterval * subsidy
subsidy *= params.MulSubsidy
subsidy /= params.DivSubsidy
}
supply += (1 + int64(height)%params.SubsidyReductionInterval) * subsidy
// Blocks 0 and 1 have special subsidy amounts that have already been
// added above, so remove what their subsidies would have normally been
// which were also added above.
supply -= params.BaseSubsidy * 2
return supply
}
// sumPurchasedTickets returns the sum of the number of tickets purchased in the
// most recent specified number of blocks from the point of view of the passed
// node.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) sumPurchasedTickets(startNode *blockNode, numToSum int64) (int64, error) {
var numPurchased int64
for node, numTraversed := startNode, int64(0); node != nil &&
numTraversed < numToSum; numTraversed++ {
numPurchased += int64(node.header.FreshStake)
// Get the previous block node. This function is used over
// simply accessing iterNode.parent directly as it will
// dynamically create previous block nodes as needed. This
// helps allow only the pieces of the chain that are needed
// to remain in memory.
var err error
node, err = b.getPrevNodeFromNode(node)
if err != nil {
return 0, err
}
}
return numPurchased, nil
}
// calcNextStakeDiffV2 calculates the next stake difficulty for the given set
// of parameters using the algorithm defined in DCP0001.
//
// This function contains the heart of the algorithm and thus is separated for
// use in both the actual stake difficulty calculation as well as estimation.
//
// The caller must perform all of the necessary chain traversal in order to
// get the current difficulty, previous retarget interval's pool size plus
// its immature tickets, as well as the current pool size plus immature tickets.
//
// This function is safe for concurrent access.
func calcNextStakeDiffV2(params *chaincfg.Params, nextHeight, curDiff, prevPoolSizeAll, curPoolSizeAll int64) int64 {
// Shorter version of various parameter for convenience.
votesPerBlock := int64(params.TicketsPerBlock)
ticketPoolSize := int64(params.TicketPoolSize)
ticketMaturity := int64(params.TicketMaturity)
// Calculate the difficulty by multiplying the old stake difficulty
// with two ratios that represent a force to counteract the relative
// change in the pool size (Fc) and a restorative force to push the pool
// size towards the target value (Fr).
//
// Per DCP0001, the generalized equation is:
//
// nextDiff = min(max(curDiff * Fc * Fr, Slb), Sub)
//
// The detailed form expands to:
//
// curPoolSizeAll curPoolSizeAll
// nextDiff = curDiff * --------------- * -----------------
// prevPoolSizeAll targetPoolSizeAll
//
// Slb = b.chainParams.MinimumStakeDiff
//
// estimatedTotalSupply
// Sub = -------------------------------
// targetPoolSize / votesPerBlock
//
// In order to avoid the need to perform floating point math which could
// be problematic across langauges due to uncertainty in floating point
// math libs, this is further simplified to integer math as follows:
//
// curDiff * curPoolSizeAll^2
// nextDiff = -----------------------------------
// prevPoolSizeAll * targetPoolSizeAll
//
// Further, the Sub parameter must calculate the denomitor first using
// integer math.
targetPoolSizeAll := votesPerBlock * (ticketPoolSize + ticketMaturity)
curPoolSizeAllBig := big.NewInt(curPoolSizeAll)
nextDiffBig := big.NewInt(curDiff)
nextDiffBig.Mul(nextDiffBig, curPoolSizeAllBig)
nextDiffBig.Mul(nextDiffBig, curPoolSizeAllBig)
nextDiffBig.Div(nextDiffBig, big.NewInt(prevPoolSizeAll))
nextDiffBig.Div(nextDiffBig, big.NewInt(targetPoolSizeAll))
// Limit the new stake difficulty between the minimum allowed stake
// difficulty and a maximum value that is relative to the total supply.
//
// NOTE: This is intentionally using integer math to prevent any
// potential issues due to uncertainty in floating point math libs. The
// ticketPoolSize parameter already contains the result of
// (targetPoolSize / votesPerBlock).
nextDiff := nextDiffBig.Int64()
estimatedSupply := estimateSupply(params, nextHeight)
maximumStakeDiff := estimatedSupply / ticketPoolSize
if nextDiff > maximumStakeDiff {
nextDiff = maximumStakeDiff
}
if nextDiff < params.MinimumStakeDiff {
nextDiff = params.MinimumStakeDiff
}
return nextDiff
}
// calcNextRequiredStakeDifficultyV2 calculates the required stake difficulty
// for the block after the passed previous block node based on the algorithm
// defined in DCP0001.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) calcNextRequiredStakeDifficultyV2(curNode *blockNode) (int64, error) {
// Stake difficulty before any tickets could possibly be purchased is
// the minimum value.
nextHeight := int64(0)
if curNode != nil {
nextHeight = curNode.height + 1
}
stakeDiffStartHeight := int64(b.chainParams.CoinbaseMaturity) + 1
if nextHeight < stakeDiffStartHeight {
return b.chainParams.MinimumStakeDiff, nil
}
// Return the previous block's difficulty requirements if the next block
// is not at a difficulty retarget interval.
intervalSize := b.chainParams.StakeDiffWindowSize
curDiff := curNode.header.SBits
if nextHeight%intervalSize != 0 {
return curDiff, nil
}
// Get the pool size and number of tickets that were immature at the
// previous retarget interval.
//
// NOTE: Since the stake difficulty must be calculated based on existing
// blocks, it is always calculated for the block after a given block, so
// the information for the previous retarget interval must be retrieved
// relative to the block just before it to coincide with how it was
// originally calculated.
var prevPoolSize int64
prevRetargetHeight := nextHeight - intervalSize - 1
prevRetargetNode, err := b.ancestorNode(curNode, prevRetargetHeight)
if err != nil {
return 0, err
}
if prevRetargetNode != nil {
prevPoolSize = int64(prevRetargetNode.header.PoolSize)
}
ticketMaturity := int64(b.chainParams.TicketMaturity)
prevImmatureTickets, err := b.sumPurchasedTickets(prevRetargetNode,
ticketMaturity)
if err != nil {
return 0, err
}
// Return the existing ticket price for the first few intervals to avoid
// division by zero and encourage initial pool population.
prevPoolSizeAll := prevPoolSize + prevImmatureTickets
if prevPoolSizeAll == 0 {
return curDiff, nil
}
// Count the number of currently immature tickets.
immatureTickets, err := b.sumPurchasedTickets(curNode, ticketMaturity)
if err != nil {
return 0, err
}
// Calculate and return the final next required difficulty.
curPoolSizeAll := int64(curNode.header.PoolSize) + immatureTickets
return calcNextStakeDiffV2(b.chainParams, nextHeight, curDiff,
prevPoolSizeAll, curPoolSizeAll), nil
}
// sdiffAlgoDeploymentVersion returns the deployment vesion for the stake
// difficulty algorithm change as defined in DCP0001 for the provided network.
//
// This function is safe for concurrent access.
func sdiffAlgoDeploymentVersion(network wire.CurrencyNet) uint32 {
if network != wire.MainNet {
return 5
}
return 4
}
// calcNextRequiredStakeDifficulty calculates the required stake difficulty for
// the block after the passed previous block node based on the active stake
// difficulty retarget rules.
//
// This function differs from the exported CalcNextRequiredDifficulty in that
// the exported version uses the current best chain as the previous block node
// while this function accepts any block node.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) calcNextRequiredStakeDifficulty(curNode *blockNode) (int64, error) {
// Use the new stake difficulty algorithm if the stake vote for the new
// algorithm agenda is active.
//
// NOTE: The choice field of the return threshold state is not examined
// here because there is only one possible choice that can be active
// for the agenda, which is yes, so there is no need to check it.
deploymentVersion := sdiffAlgoDeploymentVersion(b.chainParams.Net)
state, err := b.deploymentState(curNode, deploymentVersion,
chaincfg.VoteIDSDiffAlgorithm)
if err != nil {
return 0, err
}
if state.State == ThresholdActive {
return b.calcNextRequiredStakeDifficultyV2(curNode)
}
// Use the old stake difficulty algorithm in any other case.
return b.calcNextRequiredStakeDifficultyV1(curNode)
}
// CalcNextRequiredStakeDifficulty calculates the required stake difficulty for
// the block after the end of the current best chain based on the active stake