forkhalcyon.go raw
1 package blockchain
2
3 import (
4 "fmt"
5 "github.com/p9c/p9/pkg/bits"
6 "github.com/p9c/p9/pkg/fork"
7 "math/big"
8 )
9
10 // CalcNextRequiredDifficultyHalcyon calculates the required difficulty for the block after the passed previous block
11 // node based on the difficulty retarget rules. This function differs from the exported CalcNextRequiredDifficulty in
12 // that the exported version uses the current best chain as the previous block node while this function accepts any
13 // block node.
14 func (b *BlockChain) CalcNextRequiredDifficultyHalcyon(
15 lastNode *BlockNode,
16 algoname string,
17 l bool,
18 ) (newTargetBits uint32, e error) {
19 nH := lastNode.height + 1
20 if lastNode == nil {
21 if l {
22 D.Ln("lastNode is nil")
23 }
24 return newTargetBits, nil
25 }
26 // this sanitises invalid block versions according to legacy consensus quirks
27 algo := fork.GetAlgoVer(algoname, nH)
28 algoName := fork.GetAlgoName(algo, nH)
29 newTargetBits = fork.GetMinBits(algoName, nH)
30 prevNode := lastNode.GetLastWithAlgo(algo)
31 if prevNode == nil {
32 if l {
33 D.Ln("prevNode is nil")
34 }
35 return newTargetBits, nil
36 }
37 firstNode := prevNode
38 for i := int32(0); firstNode != nil &&
39 i < fork.GetAveragingInterval(nH)-1; i++ {
40 firstNode = firstNode.RelativeAncestor(1)
41 firstNode = firstNode.GetLastWithAlgo(algo)
42 }
43 if firstNode == nil {
44 return newTargetBits, nil
45 }
46 actualTimespan := prevNode.timestamp - firstNode.timestamp
47 adjustedTimespan := actualTimespan
48 if l {
49 T.F("actual %d", actualTimespan)
50 }
51 if actualTimespan < b.params.MinActualTimespan {
52 adjustedTimespan = b.params.MinActualTimespan
53 } else if actualTimespan > b.params.MaxActualTimespan {
54 adjustedTimespan = b.params.MaxActualTimespan
55 }
56 if l {
57 T.F("adjusted %d", adjustedTimespan)
58 }
59 oldTarget := bits.CompactToBig(prevNode.bits)
60 newTarget := new(big.Int).
61 Mul(oldTarget, big.NewInt(adjustedTimespan))
62 newTarget = newTarget.
63 Div(newTarget, big.NewInt(b.params.AveragingTargetTimespan))
64 if newTarget.Cmp(bits.CompactToBig(newTargetBits)) > 0 {
65 newTarget.Set(bits.CompactToBig(newTargetBits))
66 }
67 newTargetBits = bits.BigToCompact(newTarget)
68 if l {
69 T.F(
70 "difficulty retarget at block height %d, old %08x new %08x",
71 lastNode.height+1,
72 prevNode.bits,
73 newTargetBits,
74 )
75 }
76 if l {
77 T.C(func() string {
78 return fmt.Sprintf(
79 "actual timespan %v, adjusted timespan %v, target timespan %v"+
80 "\nOld %064x\nNew %064x",
81 actualTimespan,
82 adjustedTimespan,
83 b.params.AveragingTargetTimespan,
84 oldTarget,
85 bits.CompactToBig(newTargetBits),
86 )
87 },
88 )
89 }
90 return newTargetBits, nil
91 }
92