-
概述:
- 前⽂介绍了⽐特币每隔2016个区块调整难度,从⽽达到维持出块时间10min的⽬标。以太坊与之不同,每个区块都有可能会进⾏难度调整。以太坊难度调整较为复杂,存在多个版本,⽹络上存在诸多不⼀致,这⾥遵循以代码逻辑为准的原则,从代码中查看以太坊难度调整算法
- 区块难度D(H):
- D(H)为本区块的难度,由基础部分和难度炸弹部分相加得到
- P(H)为⽗区块的难度,每个区块的难度都在⽗区块难度的基础上进⾏调整
- ⽤于⾃适应调节出块难度,维持稳定的出块速度
- x是调整的单位,西格玛是调整的系数
- y和⽗区块的uncle数有关
- 如果⽗区块中包括了uncle,则y为2,否则为1
- ⽗块包含uncle时难度会⼤⼀个单位,因为包含uncle时新发⾏的货币量⼤,需要适当提⾼难度以保持货币发⾏量稳定
- 难度降低的上届设置为-99,主要是应对被⿊客攻击或其它⽬前想不到的⿊天鹅事件
- Hs为本区块的时间戳,P(H)hs为⽗区块的时间戳,均以秒为单位,并规定Hs>P(H)hs
- 此部分是稳定出块速度的最重要部分:出块时间过短则调⼤难度,出块时间过⻓则调⼩难度
- 基础部分有下界,为最⼩值D0=131072
- 炸弹部分epsilon:
- 根据以上以太坊难度调整算法可以看到,该算法可以很好地动态调整挖矿难度,从⽽保障系统整体出块时间维持在15s左右
- 然⽽,以太坊在设计之初就计划要逐步从POW(⼯作量证明)转向POS(权益证明),⽽权益证明不需要挖矿,这种转变需要硬分叉实现
- 以太坊本身为⼀个分布式系统,其转⼊POS必须经过系统中⼤多数矿⼯认可才⾏,如果届时矿⼯联合起来抗议转⼊POS,那么这⼀设计初衷就失效了
- 设置难度炸弹的原因是要降低迁移到POS协议时发⽣分叉的⻛险,因为到时挖矿难度⾮常⼤,所以矿⼯有意愿迁移到POS协议
- 具体代码实现,源码在
/go-ethereum/consensus/ethash/consensus.go
:// calcDifficultyByzantium 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 Byzantium rules. func calcDifficultyByzantium(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) x := new(big.Int) y := new(big.Int) // (2 if len (parent uncles) else 1) - (timestamp - parent timestamp) // 9 x.Sub(bigTime, bigParentTime) x.Div(x, big9) if parent.UncleHash == types.EmptyUncleHash { x.Sub(bigl, X) } else { x.Sub(big2, X) } // max((2 if len (parent uncles) else 1) - (timestamp-parent_timestamp)//-9,-99) if x.Cmp(bigMinus99) < 0 { x.Set(bigMinus99) } // parent_diff + (parent_diff / 2048 * // max ((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99)) // DifficultyBoundDivisor = big.NewInt(131072) y.Div(parent.Difficulty, params.DifficultyBoundDivisor) x.Mul(y, X) x.Add(parent.Difficulty, x) // minimum difficulty can ever be (before exponential factor) // MinimumDifficulty = big.NewInt(131072) if x.Cmp(params.MinimumDifficulty) < 0 { x.Set(params.MinimumDifficulty) } } // 难度炸弹的计算 // calculate a fake block number for the ice-age delay: // https://github.com/ethereum/EIPs/pull/669 // fake_block_number = min(0, block.number - 3,000,000 fakeBlockNumber := new(big.Int) if parent.Number.Cmp(big2999999) >= 0 { fakeBlockNumber = fakeBlockNumber.Sub(parent.Number, big2999999) } // for the exponential factor periodCount := fakeBlockNumber // expDiffPeriod = big.NewInt(100000) periodCount.Div(periodCount, expDiffPeriod) // the exponential factor, commonly referred to as "the bomb" // diff = diff + 2^(periodCount - 2) if periodCount.Cmp(big1) > 0 { y.Sub(periodCount, big2) y.Exp(big2, y, nil) x.Add(x, y) }
-
以太坊发展:
- Frontier
- Homestead
- Metropolis,分为2个⼦阶段:
- Byzantium:难度炸弹回调发⽣在这⼀阶段,在EIP (
Ethereum Improvement Proposal
)中决定 - Constantinople
- Byzantium:难度炸弹回调发⽣在这⼀阶段,在EIP (
- Serenity