• 北大肖臻老师《区块链技术与应用》系列课程学习笔记[19]以太坊-难度调整


    目录

    一、以太坊的难度调整原理

            1.难度调整公式

    二、以太坊发展的四个阶段

    三、代码实现

            1.Byzantium阶段,挖矿难度调整的代码

            2.计算基础部分的难度调整

            3.难度炸弹的计算

    四、以太坊实际统计统计

            1.以太坊中的难度统计

            2.出块时间统计

            3.两个区块 

    一、以太坊的难度调整原理

            为了维持出块时间在十分钟左右,比特币是每隔2016个区块会调整一下挖矿难度。以太坊是每个区块都有可能调整挖矿难度,调整的方法也比较复杂。也改过好几个版本,以太坊的黄皮书和实际代码也有一些出入,这里遵循以代码为准的原则,进行学习。

    1.难度调整公式

    图1-1

             这是难度调整的公式,这里的H是指当前这个区块,Hi是这个区块的序号,D(H)是这个区块当前的难度,那么这个难度调整的公式有两部分,这个max括号里的是第一部分,管它叫基础部分,目的是为了维持出块时间大概在十五秒左右,后面跟的∈是第二部分,也称为难度炸弹,主要是为了向权益证明过渡,以太坊想把共识机制从工作量证明逐步转入权益证明。

    图1-2
    图1-3

            难度炸弹这部分的取值,是从指数形式增长的。以太坊刚刚上线不久的时候,区块号都比较小,难度炸弹这部分算出来的值是很小的,基本上可以忽略不计,所以难度调整主要还是由基础部分(系统中的出块时间)来决定的。随着区块号越来越大,难度炸弹的威力开始显现。当初设计的思想是等难度炸弹的威力开始发挥时,以太坊就可以从工作量证明转入权益证明(挖矿变得越来越难了,大家也就原意转入权益证明)。但实际情况:基于权益证明的共识机制还有很多问题要解决,远没有当初想象那么顺利,所以转入权益证明的时间点一再推迟,难度炸弹的威力已经显现,但是大家还是得继续挖,因为没有别的方法可以达成共识。

            本来担心大家不愿意转,现在变成了想转也没法转,这个情况到2017年四五月的时候就已经很明显了,出块时间已经逐渐开始增长,从15秒最后增加到30s左右,而且如果不采取措施,还会继续增长上去。以太坊最后决定计算难度炸弹的时候,把区块号回退三百万个区块,即把真实的区块号减去三百万,算出一个假的区块号,然后再算难度炸弹,给权益证明的上限争取了一些时间。

    图1-4

            难度炸弹的作用如图1-4所示,可以看到早期的时候,基本可以忽略不计,难度调整基本上是根据系统中的出块时间进行调整的。大概是370万个区块左右,难度炸弹的威力开始指数上升,到上面这个尖峰(就是以太坊决定回调这个难度炸弹的时候),减了三百万个区块,这个难度炸弹的取值一下就掉下来了,后面看上去好像是个平的直线,其实也是在增长,只不过是因为那个尖峰的位置太高了,所以看不出来。

    二、以太坊发展的四个阶段

            以太坊的发展被分成了四个阶段,Frontier,Homestead,Metropolis,Serenity,其中Metropolis又分为两个阶段,Byzantium和Constantinople,我们处于Byzantium阶段,难度炸弹的回调就是在Byzantium阶段进行的,如图2-1所示。EIP(Ethereum Improvement Proposal),BIP(BitCoin Improvement Proposal)。

    图2-1

            以太坊系统在难度回调的同时,把出块奖励从5ETH降到了3ETH(如果不调的话,对于回调之前的矿工是不公平的),而且从系统当中获益的总供应量来说要维护总供应量的稳定,挖矿变得容易,就应该相应将出块奖励减少一些。比特币当中每隔一段时间出块奖励减半,这种做法在以太坊中是没有的,像这个把5ETH降到了3ETH是一次性的,并不是说以后定期都要这么做。

    三、代码实现

            

    1.Byzantium阶段,挖矿难度调整的代码

            输入是父区块的时间戳和父区块的难度,计算出当前挖的这个区块的难度。代码中的BigTime就是当前区块的时间戳,bigParentTime就是父区块的时间戳

    1. //calcDifficultyByzantium is the difficulty adjustment algorithm.It returns
    2. //the difficulty that a new block should have when created at time given the
    3. //parent block's time and difficulty.The calculation uses the Byzantium rules.
    4. func calcDifficultyByzantium(time-uint64,parent *types.Header) *big.Int {
    5. //https://github.com/ ethereum/EIPs/issues/100.
    6. //algorithm:
    7. //diff = (parent_diff +
    8. // (parent_diff [ 2048*
    9. // max((2 if len(parent.uncles) else 1) - ((timestamp -parent.timestamp)// 9),-99))
    10. // ) + 2^(periodCount - 2)
    11. bigTime := new(big.Int).Setuint64(time)
    12. bigParentTime := new(big.Int).Set(parent.Time)
    13. × := new(big.Int)
    14. y := new(big.Int)

    2.计算基础部分的难度调整

    1. //(2 if len(parent_uncles) else 1) - (timestamp - parent_timestamp) //9
    2. x.Sub(bigTime,bigParentTime)
    3. x.Div(x,big9)
    4. if parent.UncleHash == types.EmptyUncleHash {
    5. x.Sub(big1,x)
    6. } else {
    7. x.Sub(big2,x)
    8. }
    9. //max((2-if-len(parent_uncles) else 1) - (timestamp - -parent_timestamp)//9, -99)
    10. if x.cmp(bigMinus99) < 0 {
    11. x.Set(bigMinus99)
    12. }
    13. //parent_diff + (parent_diff / 2848 *,
    14. //max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp)// 9),-99))
    15. y.Div(parent.Difficulty, params.DifficultyBoundDivisor)
    16. x.Mul(y,x)
    17. x.Add(parent.Difficulty, x)
    18. //minimum difficulty can ever be (before exponential factor)
    19. if x Cmp(params.MinimumDifficulty) < 0 {
    20. x.Set(params.MinimumDifficulty)
    21. }

            注:DifficultyBoundDivisor = big.NewInt(2048), inimumDifficulty= big.NewInt(131072)。

            第一行就是把当前时间戳减去父区块的时间戳算出出块时间,然后第二行除以9向下取整。判断一下是不是有叔父区块,有的话,是用2减去前面这个数x,没有的话用1减去前面这个数x,然后接下来跟负的99相比,往下调有一个节限,不能比-99还要小,接下来算的是难度调整的力度,父区块的难度除以这个DifficultyBoundDivisor实际上就是2048,然后跟前面算出的系数相乘,加到父区块的难度上面去,基础部分的难度调整有一个下限,难度再小也不能小于那个D0,这个MinimumDifficulty就是那个D0=131072。

    3.难度炸弹的计算

    1. //calculate a fake block number for the ice age delay:
    2. // https : /lgithub.com/ ethereum/EIPs/pull/669
    3. // fake_block_number = min(0,block.number - 3000000
    4. fakeBlockNumber := new(big.Int)
    5. if parent.Number.Cmp(big2999999) >= 0 {
    6. fakeBlockNumber = fakeBlockNumber.Sub(parent.Number , big2999999)}
    7. //for the exponential factor
    8. periodCount := fakeBlockNumber
    9. periodCount.Div(periodCount,expDiffPeriod)
    10. //the exponential factor, commonly referred to as "the bomb"
    11. //diff = diff + 2^(periodCount - 2)
    12. if periodCount.Cmp(big1) > 0 {
    13. y.Sub(periodCount,big2)
    14. y.Exp( big2,y,nil)
    15. x.Add(x,y)
    16. }

            注:expDiffPeriod = big.NewInt(100000)。

    四、以太坊实际统计统计

    1.以太坊中的难度统计

            看到这一部分的曲线,看上去像是指数形状,到尖峰的位置就是以太坊决定回滚难度炸弹,回滚三百万个区块,所以挖矿难度一下就掉下来了,目前以太坊的挖矿难度基本上是区域稳定的。

    图4-1

     

    2.出块时间统计

            不考虑个别波动,总体来说,出块时间稳定在15s左右。说明以太坊在早期的时候,挖矿难度额调整主要以稳定出块时间为主,达到预期的效果。同样是在2017年中旬的时候,出块时间出现了大幅度增长,就是这个难度炸弹的效应。

    图4-2

    3.两个区块 

            最长合法链对于以太坊来说,其实应该叫做最难合法链,就是总难度最大额合法链,每个区块的难度,反应的是挖出这个区块所需要的工作量,总难度最大,就是挖出这条链上的所有区块需要的总工作量最大,一般来说,靠后的区块挖出来需要的工作量比较大。

    图4-3
  • 相关阅读:
    minio对象存储
    vulnhub靶机corrosion1
    CSS鼠标悬浮变小手
    用C++语言写一个可读的回调函数
    C++ 多态:(使用Shape类层次结构的多态性的屏幕管理器)开发一个基本图形软件包
    iOS脱壳之frida-ios-dump
    Linux怎么设置中文语言? centos中文乱码的解决办法
    linux常用命令(7):chmod命令(给文件赋读写权限/chmod 777)
    蓝牙Mesh系统开发五 ble mesh设备增加与移除
    如果后端返回了十万条数据要你插入到页面中,你会怎么处理?
  • 原文地址:https://blog.csdn.net/YSL_Lsy_/article/details/126482714