55package blockchain
66
77import (
8+ "errors"
89 "math/big"
910 "time"
1011
@@ -19,14 +20,31 @@ var (
1920 // oneLsh256 is 1 shifted left 256 bits. It is defined here to avoid
2021 // the overhead of creating it multiple times.
2122 oneLsh256 = new (big.Int ).Lsh (bigOne , 256 )
23+
24+ // anchorNode is the node used for the asert difficult algorithm. This is the
25+ // block just prior to the fork. After the fork this will be hardcoded, but for
26+ // now it will be set at runtime.
27+ anchorNode * blockNode
2228)
2329
24- // DifficultyAdjustmentWindow is the size of the window used by the DAA adjustment
25- // algorithm when calculating the current difficulty. The algorithm requires fetching
26- // a 'suitable' block out of blocks n-144, n-145, and n-146. We set this value equal
27- // to n-144 as that is the first of the three candidate blocks and we will use it
28- // to fetch the previous two.
29- const DifficultyAdjustmentWindow = 144
30+ const (
31+ // difficultyAdjustmentWindow is the size of the window used by the DAA adjustment
32+ // algorithm when calculating the current difficulty. The algorithm requires fetching
33+ // a 'suitable' block out of blocks n-144, n-145, and n-146. We set this value equal
34+ // to n-144 as that is the first of the three candidate blocks and we will use it
35+ // to fetch the previous two.
36+ difficultyAdjustmentWindow = 144
37+
38+ // idealBlockTime is used by the Asert difficulty adjustment algorithm. It equals
39+ // 10 minutes between blocks.
40+ idealBlockTime = 600
41+
42+ // radix is used by the Asert difficulty adjustment algorithm.
43+ radix = 65536
44+
45+ // rbits is the number of bits after the radix for fixed-point math
46+ rbits = 16
47+ )
3048
3149// The DifficultyAlgorithm specifies which algorithm to use and is passed into
3250// the calcNextRequiredDifficulty function.
@@ -44,15 +62,21 @@ const (
4462 // right after the August 1st, 2017 hardfork and lasted until November 15th, 2017.
4563 DifficultyEDA DifficultyAlgorithm = 1
4664
47- // DifficultyDAA (Difficulty Adjustment Algorithm) is the current Bitcoin Cash
48- // difficulty algorithm in effect since Novemeber 15th, 2017.
65+ // DifficultyDAA (Difficulty Adjustment Algorithm) is the Bitcoin Cash difficulty
66+ // algorithm in effect between November 15th, 2017 and November 15, 2020 .
4967 DifficultyDAA DifficultyAlgorithm = 2
68+
69+ // DifficultyAsert is the aserti3-2d algorithm in effect as of November 15, 2020.
70+ DifficultyAsert DifficultyAlgorithm = 3
5071)
5172
5273// SelectDifficultyAdjustmentAlgorithm returns the difficulty adjustment algorithm that
5374// should be used when validating a block at the given height.
54- func (b * BlockChain ) SelectDifficultyAdjustmentAlgorithm (height int32 ) DifficultyAlgorithm {
55- if height > b .chainParams .UahfForkHeight && height <= b .chainParams .DaaForkHeight {
75+ func (b * BlockChain ) SelectDifficultyAdjustmentAlgorithm (prevNode * blockNode ) DifficultyAlgorithm {
76+ height := prevNode .height + 1
77+ if uint64 (prevNode .CalcPastMedianTime ().Unix ()) >= b .chainParams .AxionActivationTime {
78+ return DifficultyAsert
79+ } else if height > b .chainParams .UahfForkHeight && height <= b .chainParams .DaaForkHeight {
5680 return DifficultyEDA
5781 } else if height > b .chainParams .DaaForkHeight {
5882 return DifficultyDAA
@@ -254,11 +278,96 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
254278 return lastNode .bits , nil
255279 }
256280
257- // If we're still using a legacy algorithm
258- if algorithm != DifficultyDAA {
281+ switch algorithm {
282+ case DifficultyLegacy , DifficultyEDA :
259283 return b .calcLegacyRequiredDifficulty (lastNode , newBlockTime , algorithm )
284+ case DifficultyDAA :
285+ return b .calcDAARequiredDifficulty (lastNode , newBlockTime )
286+ case DifficultyAsert :
287+ if anchorNode == nil {
288+ // If block 1 has a median timestamp less than the activation time and..
289+ // block 2 has a median timestamp greater than or equal to the activation time,
290+ // then block 3 is the first block to contain the new rules and block 2 is the
291+ // "reference block".
292+ node := b .bestChain .Tip ()
293+ for {
294+ if uint64 (node .CalcPastMedianTime ().Unix ()) < b .chainParams .AxionActivationTime {
295+ anchorNode = b .bestChain .next (node )
296+ break
297+ }
298+ node = node .parent
299+ }
300+ }
301+ return b .calcAsertRequiredDifficulty (lastNode , anchorNode .height , anchorNode .parent .timestamp , anchorNode .bits , newBlockTime )
260302 }
303+ return 0 , errors .New ("unknown difficulty algorithm" )
304+ }
305+
306+ func (b * BlockChain ) calcAsertRequiredDifficulty (lastNode * blockNode , anchorBlockHeight int32 , anchorBlockTime int64 , anchorBlockBits uint32 , evalTimestamp time.Time ) (uint32 , error ) {
307+ // For networks that support it, allow special reduction of the
308+ // required difficulty once too much time has elapsed without
309+ // mining a block.
310+ if b .chainParams .ReduceMinDifficulty {
311+ // Return minimum difficulty when more than the desired
312+ // amount of time has elapsed without mining a block.
313+ reductionTime := int64 (b .chainParams .MinDiffReductionTime /
314+ time .Second )
315+ allowMinTime := lastNode .timestamp + reductionTime
316+ if evalTimestamp .Unix () > allowMinTime {
317+ return b .chainParams .PowLimitBits , nil
318+ }
319+ }
320+
321+ target := CompactToBig (anchorBlockBits )
322+
323+ tDelta := lastNode .timestamp - anchorBlockTime
324+ hDelta := lastNode .height - anchorBlockHeight
325+ bigRadix := big .NewInt (radix )
326+
327+ // exponent = int(((time_diff - IDEAL_BLOCK_TIME * (height_diff + 1)) * RADIX) / HALFLIFE)
328+ exponent := new (big.Int ).Sub (big .NewInt (tDelta ), new (big.Int ).Mul (big .NewInt (int64 (idealBlockTime )), new (big.Int ).Add (big .NewInt (int64 (hDelta )), big .NewInt (1 ))))
329+ exponent .Mul (exponent , bigRadix )
330+ exponent .Quo (exponent , big .NewInt (b .chainParams .AsertDifficultyHalflife ))
331+
332+ // shifts = exponent >> RBITS
333+ shifts := new (big.Int ).Rsh (exponent , rbits )
334+
335+ // exponent -= shifts * RADIX
336+ exponent .Sub (exponent , new (big.Int ).Mul (shifts , bigRadix ))
337+
338+ // target *= RADIX + ((195766423245049 * exponent + 971821376 * exponent**2 + 5127 * exponent**3 + 2**47) >> (RBITS * 3))
339+ factor := new (big.Int ).Mul (big .NewInt (195766423245049 ), exponent )
340+ factor .Add (factor , new (big.Int ).Mul (big .NewInt (971821376 ), new (big.Int ).Exp (exponent , big .NewInt (2 ), nil )))
341+ factor .Add (factor , new (big.Int ).Mul (big .NewInt (5127 ), new (big.Int ).Exp (exponent , big .NewInt (3 ), nil )))
342+ factor .Add (factor , new (big.Int ).Exp (big .NewInt (2 ), big .NewInt (47 ), nil ))
343+ factor .Rsh (factor , rbits * 3 )
344+
345+ target .Mul (target , new (big.Int ).Add (bigRadix , factor ))
346+
347+ // if shifts < 0: target >>= -shifts else: target <<= shifts
348+ if shifts .Cmp (big .NewInt (0 )) < 0 {
349+ target = target .Rsh (target , uint (- shifts .Int64 ()))
350+ } else {
351+ target = target .Lsh (target , uint (shifts .Int64 ()))
352+ }
353+
354+ // target >>= RBITS
355+ target .Rsh (target , rbits )
356+
357+ // If target is zero
358+ if target .Cmp (big .NewInt (0 )) == 0 {
359+ return BigToCompact (big .NewInt (1 )), nil
360+ }
361+
362+ if target .Cmp (b .chainParams .PowLimit ) > 0 {
363+ // Return softest target
364+ return b .chainParams .PowLimitBits , nil
365+ }
366+
367+ return BigToCompact (target ), nil
368+ }
261369
370+ func (b * BlockChain ) calcDAARequiredDifficulty (lastNode * blockNode , newBlockTime time.Time ) (uint32 , error ) {
262371 // For networks that support it, allow special reduction of the
263372 // required difficulty once too much time has elapsed without
264373 // mining a block.
@@ -274,7 +383,7 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
274383 }
275384
276385 // Get the block node at the beginning of the window (n-144)
277- firstNode := lastNode .RelativeAncestor (DifficultyAdjustmentWindow )
386+ firstNode := lastNode .RelativeAncestor (difficultyAdjustmentWindow )
278387 if firstNode == nil {
279388 return 0 , AssertError ("unable to obtain previous retarget block" )
280389 }
@@ -441,7 +550,7 @@ func (b *BlockChain) CalcNextRequiredDifficulty(timestamp time.Time) (uint32, er
441550 b .chainLock .Lock ()
442551 tip := b .bestChain .Tip ()
443552 difficulty , err := b .calcNextRequiredDifficulty (tip , timestamp ,
444- b .SelectDifficultyAdjustmentAlgorithm (tip . height ))
553+ b .SelectDifficultyAdjustmentAlgorithm (tip ))
445554 b .chainLock .Unlock ()
446555 return difficulty , err
447556}
0 commit comments