nimbus-eth1/nimbus/core/pow/difficulty.nim

201 lines
7.5 KiB
Nim
Raw Normal View History

2023-11-01 03:32:09 +00:00
# Nimbus
# Copyright (c) 2018-2024 Status Research & Development GmbH
2023-11-01 03:32:09 +00:00
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
2020-03-04 09:32:30 +00:00
import
2022-12-02 04:35:41 +00:00
../../common/common
export
common
2019-08-23 15:54:25 +00:00
const
ExpDiffPeriod = 100000.u256
DifficultyBoundDivisorU = 2048.u256
DifficultyBoundDivisorI = 2048.i256
DurationLimit = 13
MinimumDifficultyU = 131072.u256
MinimumDifficultyI = 131072.i256
bigOne = 1.u256
bigTwo = 2.u256
bigNine = 9.i256
bigOneI = 1.i256
bigTwoI = 2.i256
bigTenI = 10.i256
bigMin99 = -99.i256
2022-04-08 04:54:11 +00:00
template difficultyBomb(periodCount: UInt256) =
2019-08-23 15:54:25 +00:00
periodCount = periodCount div ExpDiffPeriod
if periodCount > bigOne:
# diff = diff + 2^(periodCount - 2)
var expDiff = periodCount - bigTwo
expDiff = bigTwo.pow(expDiff)
diff = diff + expDiff
diff = max(diff, MinimumDifficultyU)
# calcDifficultyFrontier is the difficulty adjustment algorithm. It returns the
# difficulty that a new block should have when created at time given the parent
# block's time and difficulty. The calculation uses the Frontier rules.
func calcDifficultyFrontier*(timeStamp: EthTime, parent: Header): DifficultyInt =
2019-08-23 15:54:25 +00:00
var diff: DifficultyInt
let adjust = parent.difficulty div DifficultyBoundDivisorU
let time = timeStamp
let parentTime = parent.timestamp
2019-08-23 15:54:25 +00:00
if time - parentTime < DurationLimit:
diff = parent.difficulty + adjust
else:
diff = parent.difficulty - adjust
diff = max(diff, MinimumDifficultyU)
var periodCount = parent.number.u256 + bigOne
2019-08-23 15:54:25 +00:00
difficultyBomb(periodCount)
result = diff
# calcDifficultyHomestead is the difficulty adjustment algorithm. It returns
# the difficulty that a new block should have when created at time given the
# parent block's time and difficulty. The calculation uses the Homestead rules.
func calcDifficultyHomestead*(timeStamp: EthTime, parent: Header): DifficultyInt =
2019-08-23 15:54:25 +00:00
# https:#github.com/ethereum/EIPs/blob/master/EIPS/eip-2.md
# algorithm:
# diff = (parent_diff +
# (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) # 10, -99))
# ) + 2^(periodCount - 2)
let time = timeStamp
let parentTime = parent.timestamp
2019-08-23 15:54:25 +00:00
let parentDifficulty = cast[Int256](parent.difficulty)
# 1 - (block_timestamp - parent_timestamp) # 10
var x = (time - parentTime).uint64.i256
2019-08-23 15:54:25 +00:00
x = x div bigTenI
x = bigOneI - x
# max(1 - (block_timestamp - parent_timestamp) # 10, -99)
x = max(x, bigMin99)
# (parent_diff + parent_diff # 2048 * max(1 - (block_timestamp - parent_timestamp) # 10, -99))
var y = parentDifficulty div DifficultyBoundDivisorI
x = y * x
x = parentDifficulty + x
# minimum difficulty can ever be (before exponential factor)
2022-04-08 04:54:11 +00:00
var diff = cast[UInt256](max(x, MinimumDifficultyI))
2019-08-23 15:54:25 +00:00
# for the exponential factor
var periodCount = parent.number.u256 + bigOne
2019-08-23 15:54:25 +00:00
difficultyBomb(periodCount)
result = diff
# makeDifficultyCalculator creates a difficultyCalculator with the given bomb-delay.
# the difficulty is calculated with Byzantium rules, which differs from Homestead in
# how uncles affect the calculation
func makeDifficultyCalculator(bombDelay: static[int], timeStamp: EthTime, parent: Header): DifficultyInt =
2019-08-23 15:54:25 +00:00
# Note, the calculations below looks at the parent number, which is 1 below
# the block number. Thus we remove one from the delay given
const
bombDelayFromParent = bombDelay.u256 - bigOne
# https:#github.com/ethereum/EIPs/issues/100.
# algorithm:
# diff = (parent_diff +
# (parent_diff / 2048 * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) # 9), -99))
# ) + 2^(periodCount - 2)
let time = timeStamp
let parentTime = parent.timestamp
2019-08-23 15:54:25 +00:00
let parentDifficulty = cast[Int256](parent.difficulty)
# (2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) # 9
var x = (time - parentTime).uint64.i256
2019-08-23 15:54:25 +00:00
x = x div bigNine
if parent.ommersHash == EMPTY_UNCLE_HASH:
x = bigOneI - x
else:
x = bigTwoI - x
# max((2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) # 9, -99)
x = max(x, bigMin99)
# parent_diff + (parent_diff / 2048 * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) # 9), -99))
var y = parentDifficulty div DifficultyBoundDivisorI
x = y * x
x = parentDifficulty + x
# minimum difficulty can ever be (before exponential factor)
2022-04-08 04:54:11 +00:00
var diff = cast[UInt256](max(x, MinimumDifficultyI))
2019-08-23 15:54:25 +00:00
# calculate a fake block number for the ice-age delay
# Specification: https:#eips.ethereum.org/EIPS/eip-1234
2022-04-08 04:54:11 +00:00
var periodCount: UInt256
if parent.number.u256 >= bombDelayFromParent:
periodCount = parent.number.u256 - bombDelayFromParent
2019-08-23 15:54:25 +00:00
difficultyBomb(periodCount)
result = diff
template calcDifficultyByzantium*(timeStamp: EthTime, parent: Header): DifficultyInt =
## "EIP-649: Metropolis Difficulty Bomb Delay and Block Reward Reduction"
## <https://eips.ethereum.org/EIPS/eip-649>
2019-08-23 15:54:25 +00:00
makeDifficultyCalculator(3_000_000, timeStamp, parent)
template calcDifficultyConstantinople*(timeStamp: EthTime, parent: Header): DifficultyInt =
## "EIP-1234: Constantinople Difficulty Bomb Delay and Block Reward Adjustment"
## <https://eips.ethereum.org/EIPS/eip-1234>
## Keep using Byzantium's rules but offset the bomb 5.0M blocks.
2019-08-23 15:54:25 +00:00
makeDifficultyCalculator(5_000_000, timeStamp, parent)
template calcDifficultyMuirGlacier*(timeStamp: EthTime, parent: Header): DifficultyInt =
## "EIP-2384: Muir Glacier Difficulty Bomb Delay"
## <https://eips.ethereum.org/EIPS/eip-2384>
## Offset the bomb 4.0M more blocks than Constantinople, total 9.0M blocks.
2020-02-20 03:43:47 +00:00
makeDifficultyCalculator(9_000_000, timeStamp, parent)
2020-03-04 09:32:30 +00:00
template calcDifficultyLondon*(timeStamp: EthTime, parent: Header): DifficultyInt =
## "EIP-3554: Difficulty Bomb Delay to December 2021"
## <https://eips.ethereum.org/EIPS/eip-3554>
## Offset the bomb a total of 9.7M blocks.
makeDifficultyCalculator(9_700_000, timeStamp, parent)
template calcDifficultyArrowGlacier*(timeStamp: EthTime, parent: Header): DifficultyInt =
## "EIP-4345: Difficulty Bomb Delay to June 2022"
## <https://eips.ethereum.org/EIPS/eip-4345>
## Offset the bomb a total of 10.7M blocks.
makeDifficultyCalculator(10_700_000, timeStamp, parent)
template calcDifficultyGrayGlacier*(timeStamp: EthTime, parent: Header): DifficultyInt =
## "EIP-4345: Difficulty Bomb Delay to September 2022"
## <https://eips.ethereum.org/EIPS/eip-5133>
## Offset the bomb a total of 11.4M blocks.
makeDifficultyCalculator(11_400_000, timeStamp, parent)
func calcDifficulty*(com: CommonRef, timeStamp: EthTime, parent: Header): DifficultyInt =
2023-10-24 10:39:19 +00:00
let next = com.toHardFork(parent.forkDeterminationInfo.adjustForNextBlock)
2022-12-02 04:35:41 +00:00
if next >= GrayGlacier:
result = calcDifficultyGrayGlacier(timeStamp, parent)
2022-12-02 04:35:41 +00:00
elif next >= ArrowGlacier:
result = calcDifficultyArrowGlacier(timeStamp, parent)
2022-12-02 04:35:41 +00:00
elif next >= London:
result = calcDifficultyLondon(timeStamp, parent)
2022-12-02 04:35:41 +00:00
elif next >= MuirGlacier:
2020-04-12 11:13:22 +00:00
result = calcDifficultyMuirGlacier(timeStamp, parent)
2022-12-02 04:35:41 +00:00
elif next >= Constantinople:
2019-08-26 14:39:41 +00:00
result = calcDifficultyConstantinople(timeStamp, parent)
2022-12-02 04:35:41 +00:00
elif next >= Byzantium:
2019-08-26 14:39:41 +00:00
result = calcDifficultyByzantium(timeStamp, parent)
2022-12-02 04:35:41 +00:00
elif next >= Homestead:
2019-08-23 15:54:25 +00:00
result = calcDifficultyHomestead(timeStamp, parent)
else:
result = calcDifficultyFrontier(timeStamp, parent)