主页 > imtoken钱包不能安装 > 以太坊难度调整算法

以太坊难度调整算法

imtoken钱包不能安装 2023-05-09 06:29:17

关于以太坊的难度调整算法,可以在block_validator.go文件中找到相关表述。 该算法的主要目的是将挖矿时间保持在10-19s的范围内。 如果挖矿时间在0到9s之间,Geth会增加挖矿难度; 如果挖矿时间大于20s,Geth会降低难度。

以太经典和以太坊统一_以太坊联盟和以太坊的关系_以太坊减产周期

在block_validator.go文件中,CalcDifficulty函数用于调整挖矿难度。 函数的输入是以太坊的版本号、父块的难度值、父块的时间、当前时间和父块的编号。 该函数返回将要创建的下一个块的难度值。

下表显示了一些相应的输入参数。

输入参数说明

时间

建议的新区块形成时间。

家长时间

父块的形成时间。

家长号码

父块,块号。

父差异

父块难度

首先根据版本号选择对应的难度计算函数。 如果是Frontier,调用calcDifficultyFrontier; 如果是 Homestead,调用 calcDifficultyHomestead。

难度调整算法在以太坊硬分叉期间发生了变化。

更改当前公式的难度调整算法:block_diff = parent_diff + parent_diff // 2048 * (1 if block_timestamp - parent_timestamp < 13 else -1) + int(2**((block.number // 100000) - 2)) (其中 + int(2**((block.number // 100000) - 2)) 表示指数难度调整分量)到 block_diff = parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99) + int(2**((block.number // 100000) - 2)),其中 // 是整数除法运算符,例如。

6 // 2 = 3, 7 // 2 = 3, 8 // 2 = 4. minDifficulty 仍然定义了允许的最小难度,任何调整都不能低于这个。 边界公式的问题和更改的原因是边界版本没有考虑出块时间与 13 秒之间的差距。 前一个区块后 1 秒开采的区块与 12 秒后开采的区块对难度的影响相同。 这导致块难度调整到中位数块时间而不是平均值。

calcDifficultyHomestead 函数:

func calcDifficultyHomestead(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.mediawiki
    // algorithm:
    // diff = (parent_diff +
    //         (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
    //        ) + 2^(periodCount - 2)
    bigTime := new(big.Int).SetUint64(time)
    bigParentTime := new(big.Int).SetUint64(parentTime)
    // holds intermediate values to make the algo easier to read & audit
    x := new(big.Int)
    y := new(big.Int)
    // 1 - (block_timestamp -parent_timestamp) // 10
    x.Sub(bigTime, bigParentTime)
    x.Div(x, big10)
    x.Sub(common.Big1, x)
    // max(1 - (block_timestamp - parent_timestamp) // 10, -99)))
    if x.Cmp(bigMinus99) < 0 {
        x.Set(bigMinus99)
    }
    // (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
    y.Div(parentDiff, params.DifficultyBoundDivisor)
    x.Mul(y, x)
    x.Add(parentDiff, 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(parentNumber, common.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)
        x.Add(x, y)
    }
    return x
}

calcDifficultyFrontier 函数:

func calcDifficultyFrontier(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
    diff := new(big.Int)
    adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor)
    bigTime := new(big.Int)
    bigParentTime := new(big.Int)
    bigTime.SetUint64(time)
    bigParentTime.SetUint64(parentTime)
    if bigTime.Sub(bigTime, bigParentTime).Cmp(params.DurationLimit) < 0 {
        diff.Add(parentDiff, adjust)
    } else {
        diff.Sub(parentDiff, adjust)
    }
    if diff.Cmp(params.MinimumDifficulty) < 0 {
        diff.Set(params.MinimumDifficulty)
    }
    periodCount := new(big.Int).Add(parentNumber, common.Big1)
    periodCount.Div(periodCount, ExpDiffPeriod)
    if periodCount.Cmp(common.Big1) > 0 {
        // diff = diff + 2^(periodCount - 2)
        expDiff := periodCount.Sub(periodCount, common.Big2)
        expDiff.Exp(common.Big2, expDiff, nil)
        diff.Add(diff, expDiff)
        diff = math.BigMax(diff, params.MinimumDifficulty)
    }
    return diff
}

以下是如何创建新区块难度的分步过程。

首先,计算父块和新块形成时间之间的差异。

然后将步骤 1 的输出除以 10 并存储它的整数。 这样做是为了创建范围。 如果第 1 步的输出在 1 – 9 之间,则此步骤的输出将为 0。如果第 1 步的输出在 10 – 19 之间,则此步骤的输出将为 1。如果第 1 步的输出在 20 – 29 之间,则输出这一步将是 2 等等。

从上面的步骤创建各种范围。 现在为了创建三个范围,我们将从步骤 2 的输出中减去 1。这三个范围将是 +ve、零或 –ve。 如果你仔细观察,那么当第 1 步的输出在 0 – 9 之间时,这一步的输出将为 +ve,当第 1 步的输出在 10 – 19 之间时为 0,当第 1 步的输出大于 20 时为 –ve。

现在将上一步的输出与 -99 进行比较以太坊减产周期,如果它甚至小于 -99,则将其设置为 -99。 这样做是为了限制第 3 步的最小可能值,否则保持上一步的输出值不变。

接下来,我们将父区块难度除以难度界限除数,其值为 2048。

将步骤 4 的输出与步骤 5 相乘。这将给出新块与旧父块的难度差异。 取决于这个值是+ve然后难度会增加,如果这个值是-ve那么新的难度会降低。

现在将第 6 步的输出添加到父难度,结果将是新块的难度。

一旦计算出难度,就会进行检查以确保计算出的难度至少大于最小阈值 131072。

在返回难度之前,检查如果块数超过 200,000,则应用“炸弹”逻辑以指数方式增加难度。

为了以指数方式增加难度,通过将父块号加一来计算新块号。

现在新的块数除以 100,000。

如果新块数大于 200,000,则从 2 中减去步骤 11 的输出。

现在通过以下计算计算出指数增加的难度增量:2 ^ 步骤 12 的输出。

并且通过将上一步的输出添加到步骤 7 中计算的难度来计算新的难度。

概括

如果时间戳差(block_timestamp - parent_timestamp)是:

这与 ethdocs.org - Ethereum Homestead - The Homestead Release 中的声明是一致的:

EIP-2/4 消除了将时间戳差异精确设置为 1 以创建一个难度稍高的区块的过度激励,从而保证击败任何可能的分叉。 这保证了将区块时间保持在 10 -20 范围内,并且根据模拟恢复目标 15 秒区块时间(而不是当前有效的 17 秒)。

而从以太坊网络状态来看,目前平均出块时间为 13.86 秒。

细节

难度调整公式:

    block_diff = parent_diff + parent_diff // 2048 * 
      max(1 - (block_timestamp - parent_timestamp) // 10, -99) + 
      int(2**((block.number // 100000) - 2))

其中 // 是整数除法运算符,例如。 6 // 2 = 3, 7 // 2 = 3, 8 // 2 = 4。

可以分解为以下几个部分:

子公式 B - 难度炸弹部分,每 100,000 个区块以指数方式增加难度。

+ int(2**((block.number // 100000) - 2))

难度炸弹不会在这里讨论,因为它已经在以下问答中进行了介绍:

子公式 A - 难度调整部分,根据当前区块时间戳和父区块时间戳之间的时间来增加或减少区块难度:

+ parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)

子公式 A1 - 让我们分离出子公式 A 的一部分

+ max(1 - (block_timestamp - parent_timestamp) // 10, -99)

并考虑由于当前块与父块之间的时间戳差异而导致的调整效果:

当 (block_timestamp - parent_timestamp) 是

10, 11, 12, ..., 18, 19 秒20, 21, 22, ..., 28, 29 秒30, 31, 32, ..., 38, 39 秒1000, 1001, 1002, ..., 1008 , 1009 秒 > 1009 秒

因此,如果时间戳差异 (block_timestamp - parent_timestamp) 是:

所以,这基本上就是以太坊试图将挖矿时间差保持在 10 到 19 秒之间的方式。 现在,如果我们仔细看一下第 2 步,就会发现除以 10 有助于创建三个范围。 如果值落在第一个范围内,则增加难度,如果值落在第二个范围内,则难度保持不变,最后,如果范围落在第三个范围内,则难度降低。

现在如果我们想改变难度范围,我们可以通过在步骤 2 中将它除以另一个数字来实现。这意味着,如果我们想将挖矿时间差保持在 0-4 秒之间。 如果挖矿时间差在 5-9 秒之间以太坊减产周期,则增加难度。 然后保持难度不变,如果挖矿时间为 10 秒或更长时间。 然后尝试降低难度,然后在步骤 2 中将值除以 5 而不是除以 10。这样您可以轻松管理挖矿难度的范围。

下面是显示以太坊主网络区块难度增长的图表。

以太经典和以太坊统一_以太坊联盟和以太坊的关系_以太坊减产周期

*来源-*