@@ -20,11 +20,17 @@ import (
20
20
)
21
21
22
22
const (
23
- // Minimum difficulty level
24
- minimumDifficulty = 1000000
25
- // More aggressive difficulty adjustment for blocks before 45,000.
26
- // Note: from block 45,000 onward the divisor is set to 11.
27
- difficultyBoundDivisor = 512
23
+ // Custom difficulty parameters (used for blocks before hardfork)
24
+ minimumDifficulty = 1000000
25
+ difficultyBoundDivisor = 512
26
+ // R5 difficulty parameters (used for blocks >= hardfork)
27
+ r5MinimumDifficulty = 1000000
28
+ r5DifficultyBoundDivisor = 11
29
+ // Hardfork block number
30
+ hardForkBlock = 45000
31
+ // Block time target (in seconds) for both calculations;
32
+ // note: for R5 (post-hardfork) this replaces original target.
33
+ targetBlockTime = 7
28
34
)
29
35
30
36
func roundRat (r * big.Rat ) * big.Int {
@@ -37,23 +43,32 @@ func roundRat(r *big.Rat) *big.Int {
37
43
return quotient
38
44
}
39
45
46
+ // CalcDifficultyFrontierU256 calculates the block difficulty using the Frontier rules.
47
+ // For blocks with parent.Number >= hardForkBlock the calculation uses the R5 new formula
40
48
func CalcDifficultyFrontierU256 (time uint64 , parent * types.Header ) * big.Int {
41
- // Enforce the 3-second gap rule starting from block 45,000.
42
- if parent .Number .Uint64 () >= 45000 && (time - parent .Time ) < 3 {
43
- panic ("block rejected: parent's time gap is less than 3 seconds" )
44
- }
45
-
46
- // Determine the divisor based on block number.
47
- divisor := difficultyBoundDivisor
48
- if parent .Number .Uint64 () >= 45000 {
49
- divisor = 11
49
+ // If past the hardfork block, use R5 difficulty calculation.
50
+ if parent .Number .Uint64 () >= hardForkBlock {
51
+ pDiff , _ := uint256 .FromBig (parent .Difficulty )
52
+ adjust := pDiff .Clone ()
53
+ adjust .Rsh (adjust , r5DifficultyBoundDivisor )
54
+ // With a 7-second target, add difficulty if block time is less than 7 sec.
55
+ if time - parent .Time < targetBlockTime {
56
+ pDiff .Add (pDiff , adjust )
57
+ } else {
58
+ pDiff .Sub (pDiff , adjust )
59
+ }
60
+ if pDiff .LtUint64 (r5MinimumDifficulty ) {
61
+ pDiff .SetUint64 (r5MinimumDifficulty )
62
+ }
63
+ return pDiff .ToBig ()
50
64
}
51
65
66
+ // Custom (pre-hardfork) calculation.
52
67
pDiff , _ := uint256 .FromBig (parent .Difficulty )
53
68
adjust := pDiff .Clone ()
54
- adjust .Rsh (adjust , uint ( divisor ) )
69
+ adjust .Rsh (adjust , difficultyBoundDivisor )
55
70
diffSec := int64 (time - parent .Time )
56
- x := new (big.Rat ).SetFrac64 (diffSec , 7 )
71
+ x := new (big.Rat ).SetFrac64 (diffSec , targetBlockTime )
57
72
58
73
cVal := int64 (1 )
59
74
if parent .UncleHash != types .EmptyUncleHash {
@@ -88,23 +103,44 @@ func CalcDifficultyFrontierU256(time uint64, parent *types.Header) *big.Int {
88
103
return newDiff
89
104
}
90
105
106
+ // CalcDifficultyHomesteadU256 calculates the block difficulty using the Homestead rules.
107
+ // For blocks with parent.Number >= hardForkBlock the calculation uses the R5 formula.
91
108
func CalcDifficultyHomesteadU256 (time uint64 , parent * types.Header ) * big.Int {
92
- // Enforce the 3-second gap rule starting from block 45,000.
93
- if parent .Number .Uint64 () >= 45000 && (time - parent .Time ) < 3 {
94
- panic ("block rejected: parent's time gap is less than 3 seconds" )
95
- }
96
-
97
- // Determine the divisor based on block number.
98
- divisor := difficultyBoundDivisor
99
- if parent .Number .Uint64 () >= 45000 {
100
- divisor = 11
109
+ // R5 calculation for post-hardfork blocks.
110
+ if parent .Number .Uint64 () >= hardForkBlock {
111
+ pDiff , _ := uint256 .FromBig (parent .Difficulty )
112
+ adjust := pDiff .Clone ()
113
+ adjust .Rsh (adjust , r5DifficultyBoundDivisor )
114
+ // Replace the original divisor of 10 with our targetBlockTime (7 seconds)
115
+ x := (time - parent .Time ) / targetBlockTime
116
+ neg := true
117
+ if x == 0 {
118
+ x = 1
119
+ neg = false
120
+ } else if x >= 100 {
121
+ x = 99
122
+ } else {
123
+ x = x - 1
124
+ }
125
+ z := new (uint256.Int ).SetUint64 (x )
126
+ adjust .Mul (adjust , z )
127
+ if neg {
128
+ pDiff .Sub (pDiff , adjust )
129
+ } else {
130
+ pDiff .Add (pDiff , adjust )
131
+ }
132
+ if pDiff .LtUint64 (r5MinimumDifficulty ) {
133
+ pDiff .SetUint64 (r5MinimumDifficulty )
134
+ }
135
+ return pDiff .ToBig ()
101
136
}
102
137
138
+ // Custom (pre-hardfork) calculation.
103
139
pDiff , _ := uint256 .FromBig (parent .Difficulty )
104
140
adjust := pDiff .Clone ()
105
- adjust .Rsh (adjust , uint ( divisor ) )
141
+ adjust .Rsh (adjust , difficultyBoundDivisor )
106
142
diffSec := int64 (time - parent .Time )
107
- x := new (big.Rat ).SetFrac64 (diffSec , 7 )
143
+ x := new (big.Rat ).SetFrac64 (diffSec , targetBlockTime )
108
144
109
145
oneRat := new (big.Rat ).SetInt64 (1 )
110
146
factor := new (big.Rat ).Sub (x , oneRat )
@@ -135,42 +171,67 @@ func CalcDifficultyHomesteadU256(time uint64, parent *types.Header) *big.Int {
135
171
if parent .Number .Uint64 () < 300 {
136
172
newDiff .Mul (newDiff , big .NewInt (3 ))
137
173
newDiff .Div (newDiff , big .NewInt (2 ))
138
- }
174
+ }
139
175
return newDiff
140
176
}
141
177
178
+ // MakeDifficultyCalculatorU256 returns a function to calculate difficulty.
179
+ // For blocks with parent.Number >= hardForkBlock the returned function uses the R5 formula.
142
180
func MakeDifficultyCalculatorU256 () func (time uint64 , parent * types.Header ) * big.Int {
143
181
return func (time uint64 , parent * types.Header ) * big.Int {
144
- // Enforce the 3-second gap rule starting from block 45,000.
145
- if parent .Number .Uint64 () >= 45000 && (time - parent .Time ) < 3 {
146
- panic ("block rejected: parent's time gap is less than 3 seconds" )
147
- }
148
-
149
- // Determine the divisor based on block number.
150
- divisor := difficultyBoundDivisor
151
- if parent .Number .Uint64 () >= 45000 {
152
- divisor = 11
182
+ // R5 calculation for post-hardfork blocks.
183
+ if parent .Number .Uint64 () >= hardForkBlock {
184
+ x := (time - parent .Time ) / targetBlockTime
185
+ c := uint64 (1 )
186
+ if parent .UncleHash != types .EmptyUncleHash {
187
+ c = 2
188
+ }
189
+ xNeg := x >= c
190
+ if xNeg {
191
+ x = x - c
192
+ } else {
193
+ x = c - x
194
+ }
195
+ if x > 99 {
196
+ x = 99
197
+ }
198
+ y := new (uint256.Int )
199
+ y .SetFromBig (parent .Difficulty )
200
+ pDiff := y .Clone ()
201
+ z := new (uint256.Int ).SetUint64 (x )
202
+ y .Rsh (y , r5DifficultyBoundDivisor )
203
+ z .Mul (y , z )
204
+ if xNeg {
205
+ y .Sub (pDiff , z )
206
+ } else {
207
+ y .Add (pDiff , z )
208
+ }
209
+ if y .LtUint64 (r5MinimumDifficulty ) {
210
+ y .SetUint64 (r5MinimumDifficulty )
211
+ }
212
+ return y .ToBig ()
153
213
}
154
214
215
+ // Custom (pre-hardfork) calculation.
155
216
diffSec := int64 (time - parent .Time )
156
- x := new (big.Rat ).SetFrac64 (diffSec , 7 )
217
+ xRat := new (big.Rat ).SetFrac64 (diffSec , targetBlockTime )
157
218
158
219
cVal := int64 (1 )
159
220
if parent .UncleHash != types .EmptyUncleHash {
160
221
cVal = 2
161
222
}
162
223
cRat := new (big.Rat ).SetInt64 (cVal )
163
224
164
- delta := new (big.Rat ).Sub (new (big.Rat ).Quo (x , cRat ), big .NewRat (1 , 1 ))
225
+ delta := new (big.Rat ).Sub (new (big.Rat ).Quo (xRat , cRat ), big .NewRat (1 , 1 ))
165
226
166
227
y := new (uint256.Int )
167
228
y .SetFromBig (parent .Difficulty )
168
- y .Rsh (y , uint ( divisor ) )
229
+ y .Rsh (y , difficultyBoundDivisor )
169
230
170
231
prod := new (big.Rat ).Mul (new (big.Rat ).SetInt (y .ToBig ()), delta )
171
232
adjAmount := roundRat (prod )
172
233
173
- if x .Cmp (cRat ) >= 0 {
234
+ if xRat .Cmp (cRat ) >= 0 {
174
235
newDiff := new (big.Int ).Sub (parent .Difficulty , adjAmount )
175
236
if newDiff .Cmp (big .NewInt (minimumDifficulty )) < 0 {
176
237
newDiff .SetUint64 (minimumDifficulty )
0 commit comments