北大肖臻老师《区块链技术与应用》系列课程学习笔记[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就是父区块的时间戳

//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)
    × := new(big.Int)
    y := new(big.Int)

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

//(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(big1,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 / 2848 *,
//max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp)// 9),-99))
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)
}

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

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

3.难度炸弹的计算

//calculate a fake block number for the ice age delay:
//    https : /lgithub.com/ ethereum/EIPs/pull/669
//    fake_block_number = min(0,block.number - 3000000
fakeBlockNumber := new(big.Int)
if parent.Number.Cmp(big2999999) >= 0 {
    fakeBlockNumber = fakeBlockNumber.Sub(parent.Number , big2999999)}
//for the exponential factor
periodCount := fakeBlockNumber
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)
}

        注:expDiffPeriod = big.NewInt(100000)。

四、以太坊实际统计统计

1.以太坊中的难度统计

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

图4-1

2.出块时间统计

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

图4-2

3.两个区块 

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

图4-3

猜你喜欢

转载自blog.csdn.net/YSL_Lsy_/article/details/126482714