Skip to content

Commit

Permalink
consensus, core: EIP 100 polishes, fix chain maker diff
Browse files Browse the repository at this point in the history
This PR polishes the EIP 100 difficulty adjustment algorithm
to match the same mechanisms as the Homestead was implemented
to keep the code uniform. It also avoids a few memory allocs
by reusing big1 and big2, pulling it out of the common package
and into ethash.

The commit also fixes chain maker to forward the uncle hash
when creating a simulated chain (it wasn't needed until now
so we just skipped a copy there).
  • Loading branch information
karalabe committed Jun 30, 2017
1 parent c4d28ae commit 8c313ee
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 29 deletions.
67 changes: 38 additions & 29 deletions consensus/ethash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *
// given the parent block's time and difficulty.
// TODO (karalabe): Move the chain maker into this package and make this private!
func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int {
next := new(big.Int).Add(parent.Number, common.Big1)
next := new(big.Int).Add(parent.Number, big1)
switch {
case config.IsMetropolis(next):
return calcDifficultyMetropolis(time, parent)
Expand All @@ -301,53 +301,62 @@ func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Heade
// Some weird constants to avoid constant memory allocs for them.
var (
expDiffPeriod = big.NewInt(100000)
big1 = big.NewInt(1)
big2 = big.NewInt(2)
big9 = big.NewInt(9)
big10 = big.NewInt(10)
bigMinus99 = big.NewInt(-99)
)

// calcDifficultyMetropolis 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 Metropolis rules.
func calcDifficultyMetropolis(time uint64, parent *types.Header) *big.Int {
// 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)

bigTime := new(big.Int).SetUint64(time)
bigParentTime := new(big.Int).Set(parent.Time)

// adj_factor = max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99)
var x *big.Int
// holds intermediate values to make the algo easier to read & audit
x := new(big.Int)
y := new(big.Int)

// (2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // 9
x.Sub(bigTime, bigParentTime)
x.Div(x, big9)
if parent.UncleHash == types.EmptyUncleHash {
x = big.NewInt(1)
x.Sub(big1, x)
} else {
x = big.NewInt(2)
x.Sub(big2, x)
}
z := new(big.Int).Sub(bigTime, bigParentTime)
z.Div(z, big9)
x.Sub(x, z)

// max(1 - (block_timestamp - parent_timestamp) // 10, -99)))
// max((2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // 9, -99)
if x.Cmp(bigMinus99) < 0 {
x.Set(bigMinus99)
}

// (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
y := new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisor)
y.Div(parent.Difficulty, params.DifficultyBoundDivisor)
x.Mul(y, x)
x.Add(parent.Difficulty, x)

// minimum difficulty can ever be (before exponential factor)
if x.Cmp(params.MinimumDifficulty) < 0 {
x.Set(params.MinimumDifficulty)
}

// for the exponential factor
periodCount := new(big.Int).Add(parent.Number, common.Big1)
periodCount := new(big.Int).Add(parent.Number, big1)
periodCount.Div(periodCount, expDiffPeriod)

// the exponential factor, commonly referred to as "the bomb"
// diff = diff + 2^(periodCount - 2)
if periodCount.Cmp(common.Big1) > 0 {
y.Sub(periodCount, common.Big2)
y.Exp(common.Big2, y, nil)
if periodCount.Cmp(big1) > 0 {
y.Sub(periodCount, big2)
y.Exp(big2, y, nil)
x.Add(x, y)
}

return x
}

Expand All @@ -368,12 +377,12 @@ func calcDifficultyHomestead(time uint64, parent *types.Header) *big.Int {
x := new(big.Int)
y := new(big.Int)

// 1 - (block_timestamp -parent_timestamp) // 10
// 1 - (block_timestamp - parent_timestamp) // 10
x.Sub(bigTime, bigParentTime)
x.Div(x, big10)
x.Sub(common.Big1, x)
x.Sub(big1, x)

// max(1 - (block_timestamp - parent_timestamp) // 10, -99)))
// max(1 - (block_timestamp - parent_timestamp) // 10, -99)
if x.Cmp(bigMinus99) < 0 {
x.Set(bigMinus99)
}
Expand All @@ -387,14 +396,14 @@ func calcDifficultyHomestead(time uint64, parent *types.Header) *big.Int {
x.Set(params.MinimumDifficulty)
}
// for the exponential factor
periodCount := new(big.Int).Add(parent.Number, common.Big1)
periodCount := new(big.Int).Add(parent.Number, big1)
periodCount.Div(periodCount, expDiffPeriod)

// the exponential factor, commonly referred to as "the bomb"
// diff = diff + 2^(periodCount - 2)
if periodCount.Cmp(common.Big1) > 0 {
y.Sub(periodCount, common.Big2)
y.Exp(common.Big2, y, nil)
if periodCount.Cmp(big1) > 0 {
y.Sub(periodCount, big2)
y.Exp(big2, y, nil)
x.Add(x, y)
}
return x
Expand All @@ -421,12 +430,12 @@ func calcDifficultyFrontier(time uint64, parent *types.Header) *big.Int {
diff.Set(params.MinimumDifficulty)
}

periodCount := new(big.Int).Add(parent.Number, common.Big1)
periodCount := new(big.Int).Add(parent.Number, big1)
periodCount.Div(periodCount, expDiffPeriod)
if periodCount.Cmp(common.Big1) > 0 {
if periodCount.Cmp(big1) > 0 {
// diff = diff + 2^(periodCount - 2)
expDiff := periodCount.Sub(periodCount, common.Big2)
expDiff.Exp(common.Big2, expDiff, nil)
expDiff := periodCount.Sub(periodCount, big2)
expDiff.Exp(big2, expDiff, nil)
diff.Add(diff, expDiff)
diff = math.BigMax(diff, params.MinimumDifficulty)
}
Expand Down
1 change: 1 addition & 0 deletions core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St
Number: parent.Number(),
Time: new(big.Int).Sub(time, big.NewInt(10)),
Difficulty: parent.Difficulty(),
UncleHash: parent.UncleHash(),
}),
GasLimit: CalcGasLimit(parent),
GasUsed: new(big.Int),
Expand Down

0 comments on commit 8c313ee

Please sign in to comment.