This PR adds re-written difficulty calculators, which are based on uint256. It also adds a fuzzer + oss-fuzz integration for the new fuzzer. It does differential fuzzing between the new and old calculators. Note: this PR does not actually enable the new calculators.
		
			
				
	
	
		
			194 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			194 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2020 The go-ethereum Authors
 | |
| // This file is part of the go-ethereum library.
 | |
| //
 | |
| // The go-ethereum library is free software: you can redistribute it and/or modify
 | |
| // it under the terms of the GNU Lesser General Public License as published by
 | |
| // the Free Software Foundation, either version 3 of the License, or
 | |
| // (at your option) any later version.
 | |
| //
 | |
| // The go-ethereum library is distributed in the hope that it will be useful,
 | |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | |
| // GNU Lesser General Public License for more details.
 | |
| //
 | |
| // You should have received a copy of the GNU Lesser General Public License
 | |
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | |
| 
 | |
| package ethash
 | |
| 
 | |
| import (
 | |
| 	"math/big"
 | |
| 
 | |
| 	"github.com/ethereum/go-ethereum/core/types"
 | |
| 	"github.com/holiman/uint256"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	// frontierDurationLimit is for Frontier:
 | |
| 	// The decision boundary on the blocktime duration used to determine
 | |
| 	// whether difficulty should go up or down.
 | |
| 	frontierDurationLimit = 13
 | |
| 	// minimumDifficulty The minimum that the difficulty may ever be.
 | |
| 	minimumDifficulty = 131072
 | |
| 	// expDiffPeriod is the exponential difficulty period
 | |
| 	expDiffPeriodUint = 100000
 | |
| 	// difficultyBoundDivisorBitShift is the bound divisor of the difficulty (2048),
 | |
| 	// This constant is the right-shifts to use for the division.
 | |
| 	difficultyBoundDivisor = 11
 | |
| )
 | |
| 
 | |
| // CalcDifficultyFrontierU256 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 CalcDifficultyFrontierU256(time uint64, parent *types.Header) *big.Int {
 | |
| 	/*
 | |
| 		Algorithm
 | |
| 		block_diff = pdiff + pdiff / 2048 * (1 if time - ptime < 13 else -1) + int(2^((num // 100000) - 2))
 | |
| 
 | |
| 		Where:
 | |
| 		- pdiff  = parent.difficulty
 | |
| 		- ptime = parent.time
 | |
| 		- time = block.timestamp
 | |
| 		- num = block.number
 | |
| 	*/
 | |
| 
 | |
| 	pDiff := uint256.NewInt()
 | |
| 	pDiff.SetFromBig(parent.Difficulty) // pDiff: pdiff
 | |
| 	adjust := pDiff.Clone()
 | |
| 	adjust.Rsh(adjust, difficultyBoundDivisor) // adjust: pDiff / 2048
 | |
| 
 | |
| 	if time-parent.Time < frontierDurationLimit {
 | |
| 		pDiff.Add(pDiff, adjust)
 | |
| 	} else {
 | |
| 		pDiff.Sub(pDiff, adjust)
 | |
| 	}
 | |
| 	if pDiff.LtUint64(minimumDifficulty) {
 | |
| 		pDiff.SetUint64(minimumDifficulty)
 | |
| 	}
 | |
| 	// 'pdiff' now contains:
 | |
| 	// pdiff + pdiff / 2048 * (1 if time - ptime < 13 else -1)
 | |
| 
 | |
| 	if periodCount := (parent.Number.Uint64() + 1) / expDiffPeriodUint; periodCount > 1 {
 | |
| 		// diff = diff + 2^(periodCount - 2)
 | |
| 		expDiff := adjust.SetOne()
 | |
| 		expDiff.Lsh(expDiff, uint(periodCount-2)) // expdiff: 2 ^ (periodCount -2)
 | |
| 		pDiff.Add(pDiff, expDiff)
 | |
| 	}
 | |
| 	return pDiff.ToBig()
 | |
| }
 | |
| 
 | |
| // CalcDifficultyHomesteadU256 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 CalcDifficultyHomesteadU256(time uint64, parent *types.Header) *big.Int {
 | |
| 	/*
 | |
| 		https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.md
 | |
| 		Algorithm:
 | |
| 		block_diff = pdiff + pdiff / 2048 * max(1 - (time - ptime) / 10, -99) + 2 ^ int((num / 100000) - 2))
 | |
| 
 | |
| 		Our modification, to use unsigned ints:
 | |
| 		block_diff = pdiff - pdiff / 2048 * max((time - ptime) / 10 - 1, 99) + 2 ^ int((num / 100000) - 2))
 | |
| 
 | |
| 		Where:
 | |
| 		- pdiff  = parent.difficulty
 | |
| 		- ptime = parent.time
 | |
| 		- time = block.timestamp
 | |
| 		- num = block.number
 | |
| 	*/
 | |
| 
 | |
| 	pDiff := uint256.NewInt()
 | |
| 	pDiff.SetFromBig(parent.Difficulty) // pDiff: pdiff
 | |
| 	adjust := pDiff.Clone()
 | |
| 	adjust.Rsh(adjust, difficultyBoundDivisor) // adjust: pDiff / 2048
 | |
| 
 | |
| 	x := (time - parent.Time) / 10 // (time - ptime) / 10)
 | |
| 	var neg = true
 | |
| 	if x == 0 {
 | |
| 		x = 1
 | |
| 		neg = false
 | |
| 	} else if x >= 100 {
 | |
| 		x = 99
 | |
| 	} else {
 | |
| 		x = x - 1
 | |
| 	}
 | |
| 	z := new(uint256.Int).SetUint64(x)
 | |
| 	adjust.Mul(adjust, z) // adjust: (pdiff / 2048) * max((time - ptime) / 10 - 1, 99)
 | |
| 	if neg {
 | |
| 		pDiff.Sub(pDiff, adjust) // pdiff - pdiff / 2048 * max((time - ptime) / 10 - 1, 99)
 | |
| 	} else {
 | |
| 		pDiff.Add(pDiff, adjust) // pdiff + pdiff / 2048 * max((time - ptime) / 10 - 1, 99)
 | |
| 	}
 | |
| 	if pDiff.LtUint64(minimumDifficulty) {
 | |
| 		pDiff.SetUint64(minimumDifficulty)
 | |
| 	}
 | |
| 	// for the exponential factor, a.k.a "the bomb"
 | |
| 	// diff = diff + 2^(periodCount - 2)
 | |
| 	if periodCount := (1 + parent.Number.Uint64()) / expDiffPeriodUint; periodCount > 1 {
 | |
| 		expFactor := adjust.Lsh(adjust.SetOne(), uint(periodCount-2))
 | |
| 		pDiff.Add(pDiff, expFactor)
 | |
| 	}
 | |
| 	return pDiff.ToBig()
 | |
| }
 | |
| 
 | |
| // MakeDifficultyCalculatorU256 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 MakeDifficultyCalculatorU256(bombDelay *big.Int) func(time uint64, parent *types.Header) *big.Int {
 | |
| 	// Note, the calculations below looks at the parent number, which is 1 below
 | |
| 	// the block number. Thus we remove one from the delay given
 | |
| 	bombDelayFromParent := bombDelay.Uint64() - 1
 | |
| 	return func(time uint64, parent *types.Header) *big.Int {
 | |
| 		/*
 | |
| 			https://github.com/ethereum/EIPs/issues/100
 | |
| 			pDiff = parent.difficulty
 | |
| 			BLOCK_DIFF_FACTOR = 9
 | |
| 			a = pDiff + (pDiff // BLOCK_DIFF_FACTOR) * adj_factor
 | |
| 			b = min(parent.difficulty, MIN_DIFF)
 | |
| 			child_diff = max(a,b )
 | |
| 		*/
 | |
| 		x := (time - parent.Time) / 9 // (block_timestamp - parent_timestamp) // 9
 | |
| 		c := uint64(1)                // if parent.unclehash == emptyUncleHashHash
 | |
| 		if parent.UncleHash != types.EmptyUncleHash {
 | |
| 			c = 2
 | |
| 		}
 | |
| 		xNeg := x >= c
 | |
| 		if xNeg {
 | |
| 			// x is now _negative_ adjustment factor
 | |
| 			x = x - c // - ( (t-p)/p -( 2 or 1) )
 | |
| 		} else {
 | |
| 			x = c - x // (2 or 1) - (t-p)/9
 | |
| 		}
 | |
| 		if x > 99 {
 | |
| 			x = 99 // max(x, 99)
 | |
| 		}
 | |
| 		// parent_diff + (parent_diff / 2048 * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99))
 | |
| 		y := new(uint256.Int)
 | |
| 		y.SetFromBig(parent.Difficulty)    // y: p_diff
 | |
| 		pDiff := y.Clone()                 // pdiff: p_diff
 | |
| 		z := new(uint256.Int).SetUint64(x) //z : +-adj_factor (either pos or negative)
 | |
| 		y.Rsh(y, difficultyBoundDivisor)   // y: p__diff / 2048
 | |
| 		z.Mul(y, z)                        // z: (p_diff / 2048 ) * (+- adj_factor)
 | |
| 
 | |
| 		if xNeg {
 | |
| 			y.Sub(pDiff, z) // y: parent_diff + parent_diff/2048 * adjustment_factor
 | |
| 		} else {
 | |
| 			y.Add(pDiff, z) // y: parent_diff + parent_diff/2048 * adjustment_factor
 | |
| 		}
 | |
| 		// minimum difficulty can ever be (before exponential factor)
 | |
| 		if y.LtUint64(minimumDifficulty) {
 | |
| 			y.SetUint64(minimumDifficulty)
 | |
| 		}
 | |
| 		// calculate a fake block number for the ice-age delay
 | |
| 		// Specification: https://eips.ethereum.org/EIPS/eip-1234
 | |
| 		var pNum = parent.Number.Uint64()
 | |
| 		if pNum >= bombDelayFromParent {
 | |
| 			if fakeBlockNumber := pNum - bombDelayFromParent; fakeBlockNumber >= 2*expDiffPeriodUint {
 | |
| 				z.SetOne()
 | |
| 				z.Lsh(z, uint(fakeBlockNumber/expDiffPeriodUint-2))
 | |
| 				y.Add(z, y)
 | |
| 			}
 | |
| 		}
 | |
| 		return y.ToBig()
 | |
| 	}
 | |
| }
 |