1 package blockchain
2 3 import (
4 "encoding/hex"
5 bits2 "github.com/p9c/p9/pkg/bits"
6 "github.com/p9c/p9/pkg/fork"
7 "math/big"
8 "strings"
9 "time"
10 11 "github.com/p9c/p9/pkg/chainhash"
12 )
13 14 var (
15 // ScryptPowLimit is
16 ScryptPowLimit = scryptPowLimit
17 // ScryptPowLimitBits is
18 ScryptPowLimitBits = bits2.BigToCompact(&scryptPowLimit)
19 // bigOne is 1 represented as a big.Int. It is defined here to avoid the overhead of creating it multiple times.
20 bigOne = big.NewInt(1)
21 // oneLsh256 is 1 shifted left 256 bits. It is defined here to avoid the overhead of creating it multiple times.
22 oneLsh256 = new(big.Int).Lsh(bigOne, 256)
23 scryptPowLimit = func() big.Int {
24 mplb, _ := hex.DecodeString(
25 "000000039fcaa04ac30b6384471f337748ef5c87c7aeffce5e51770ce6283137,",
26 )
27 return *big.NewInt(0).SetBytes(mplb) // AllOnes.Rsh(&AllOnes, 0)
28 }()
29 )
30 31 // CalcNextRequiredDifficulty calculates the required difficulty for the block after the end of the current best chain
32 // based on the difficulty retarget rules. This function is safe for concurrent access.
33 func (b *BlockChain) CalcNextRequiredDifficulty(algo string) (difficulty uint32, e error) {
34 b.ChainLock.Lock()
35 difficulty, e = b.CalcNextRequiredDifficultyFromNode(
36 b.BestChain.
37 Tip(), algo, false,
38 )
39 // F.Ln("CalcNextRequiredDifficulty", difficulty)
40 b.ChainLock.Unlock()
41 return
42 }
43 44 // calcEasiestDifficulty calculates the easiest possible difficulty that a block can have given starting difficulty bits
45 // and a duration.
46 //
47 // It is mainly used to verify that claimed proof of work by a block is sane as compared to a known good checkpoint.
48 func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 {
49 // Convert types used in the calculations below.
50 durationVal := int64(duration / time.Second)
51 adjustmentFactor := big.NewInt(b.params.RetargetAdjustmentFactor)
52 // Since easier difficulty equates to higher numbers, the easiest difficulty for a given duration is the largest
53 // value possible given the number of retargets for the duration and starting difficulty multiplied by the max
54 // adjustment factor.
55 newTarget := bits2.CompactToBig(bits)
56 for durationVal > 0 && newTarget.Cmp(b.params.PowLimit) < 0 {
57 newTarget.Mul(newTarget, adjustmentFactor)
58 durationVal -= b.maxRetargetTimespan
59 }
60 // Limit new value to the proof of work limit.
61 if newTarget.Cmp(b.params.PowLimit) > 0 {
62 newTarget.Set(b.params.PowLimit)
63 }
64 return bits2.BigToCompact(newTarget)
65 }
66 67 // CalcNextRequiredDifficultyFromNode calculates the required difficulty for the block after the passed previous block node
68 // based on the difficulty retarget rules.
69 //
70 // This function differs from the exported CalcNextRequiredDifficulty in that the exported version uses the current best
71 // chain as the previous block node while this function accepts any block node.
72 func (b *BlockChain) CalcNextRequiredDifficultyFromNode(lastNode *BlockNode, algoname string, l bool,) (
73 newTargetBits uint32,
74 e error,
75 ) {
76 nH := lastNode.height + 1
77 cF := fork.GetCurrent(nH)
78 newTargetBits = fork.GetMinBits(algoname, nH)
79 // Tracef("CalcNextRequiredDifficultyFromNode %08x", newTargetBits)
80 switch cF {
81 // Legacy difficulty adjustment
82 case 0:
83 // F.Ln("before hardfork")
84 return b.CalcNextRequiredDifficultyHalcyon(lastNode, algoname, l)
85 // Plan 9 from Crypto Space
86 case 1:
87 bits, ok := lastNode.Diffs.Load().(Diffs)
88 if bits == nil || !ok {
89 lastNode.Diffs.Store(make(Diffs))
90 }
91 version := fork.GetAlgoVer(algoname, lastNode.height+1)
92 if bits[version] == 0 {
93 bits, e = b.CalcNextRequiredDifficultyPlan9Controller(lastNode)
94 if e != nil {
95 E.Ln(e)
96 return
97 }
98 // D.Ln(bits, reflect.TypeOf(bits))
99 b.DifficultyBits.Store(bits)
100 // D.F("got difficulty %d %08x %+v", version, (*b.DifficultyBits)[version], *bits)
101 }
102 newTargetBits = bits[version]
103 return
104 }
105 return
106 }
107 108 // RightJustify takes a string and right justifies it by a width or crops it
109 func RightJustify(s string, w int) string {
110 sw := len(s)
111 diff := w - sw
112 if diff > 0 {
113 s = strings.Repeat(" ", diff) + s
114 } else if diff < 0 {
115 s = s[:w]
116 }
117 return s
118 }
119 120 // CalcWork calculates a work value from difficulty bits.
121 // Bitcoin increases the difficulty for generating a block by decreasing the
122 // value which the generated hash must be less than.
123 // This difficulty target is stored in each block header using a compact
124 // representation as described in the documentation for CompactToBig.
125 // The main chain is selected by choosing the chain that has the most proof
126 // of work (highest difficulty).
127 // Since a lower target difficulty value equates to higher actual difficulty,
128 // the work value which will be accumulated must be the inverse of the
129 // difficulty. Also,
130 // in order to avoid potential division by zero and really small floating
131 // point numbers, the result adds 1 to the denominator and multiplies the
132 // numerator by 2^256.
133 func CalcWork(bits uint32, height int32, algover int32) *big.Int {
134 // Return a work value of zero if the passed difficulty bits represent a negative number. Note this should not
135 // happen in practice with valid blocks, but an invalid block could trigger it.
136 difficultyNum := bits2.CompactToBig(bits)
137 // To make the difficulty values correlate to number of hash operations, multiply this difficulty base by the
138 // nanoseconds/hash figures in the fork algorithms list
139 if difficultyNum.Sign() <= 0 {
140 return big.NewInt(0)
141 }
142 denominator := new(big.Int).Add(difficultyNum, bigOne)
143 r := new(big.Int).Div(oneLsh256, denominator)
144 return r
145 }
146 147 // HashToBig converts a chainhash.Hash into a big. Int that can be used to perform math comparisons.
148 func HashToBig(hash *chainhash.Hash) *big.Int {
149 // A Hash is in little-endian, but the big package wants the bytes in big-endian, so reverse them.
150 buf := *hash
151 blen := len(buf)
152 for i := 0; i < blen/2; i++ {
153 buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i]
154 }
155 // buf := hash.CloneBytes()
156 return new(big.Int).SetBytes(buf[:])
157 }
158