从前一节对区块链先驱bitcoin的POW分析,挖矿的本质就是求解一个谜题,给定一个难度(difficulty),他可以动态变化,他决定了难题的题解空间,用穷举的方式,再题解空间中找到解决谜题的解。

以太坊的难度计算公式是

翻译一下就是:

blockDiff = parentDiff + parentDiff / 2048 * max(1 - (blockTimestamp - parentTimestamp)/9, -99) +  2^((blockNumer - 3000000) / 100000 -2)

难度计算对应到以太坊源码:

ChainOperationParams::ChainOperationParams():
    m_blockReward("0x4563918244F40000"),
    minGasLimit(0x1388),
    maxGasLimit("0x7fffffffffffffff"),
    gasLimitBoundDivisor(0x0400),
    networkID(0x0),
    minimumDifficulty(0x020000), // 131072
    difficultyBoundDivisor(0x0800), //2048
    durationLimit(0x0d) // 13
{
}
u256 calculateEthashDifficulty(
    ChainOperationParams const& _chainParams, BlockHeader const& _bi, BlockHeader const& _parent)
{
    const unsigned c_expDiffPeriod = 100000;

    if (!_bi.number())
        throw GenesisBlockCannotBeCalculated(); //创世区块不计算
    auto const& minimumDifficulty = _chainParams.minimumDifficulty; //即创世区块难度131072
    auto const& difficultyBoundDivisor = _chainParams.difficultyBoundDivisor;//2048
    auto const& durationLimit = _chainParams.durationLimit;//13

    bigint target;  // stick to a bigint for the target. Don't want to risk going negative.
    //以太坊有不同的发展阶段,不同的发展阶段适用的难度调整方案不同
    if (_bi.number() < _chainParams.homesteadForkBlock)
        // Frontier-era difficulty adjustment
        // Frontier阶段,难度调整是父区块难度+/- 父区块难度/2048
        target = _bi.timestamp() >= _parent.timestamp() + durationLimit ?
                     _parent.difficulty() - (_parent.difficulty() / difficultyBoundDivisor) :
                     (_parent.difficulty() + (_parent.difficulty() / difficultyBoundDivisor));
    else
    {
        //当前区块与父区块的时间差
        bigint const timestampDiff = bigint(_bi.timestamp()) - _parent.timestamp();
        // 动态平衡调节因子,Homestead阶段和Byzantium阶段不同,Byantium阶段比配到了协议中的公式
        bigint const adjFactor =
            _bi.number() < _chainParams.byzantiumForkBlock ?
                max<bigint>(1 - timestampDiff / 10, -99) :  // Homestead-era difficulty adjustment
                max<bigint>((_parent.hasUncles() ? 2 : 1) - timestampDiff / 9,
                    -99);  // Byzantium-era difficulty adjustment

        target = _parent.difficulty() + _parent.difficulty() / 2048 * adjFactor;
    }

    bigint o = target;
    unsigned exponentialIceAgeBlockNumber = unsigned(_parent.number() + 1);

    // EIP-1234 Constantinople Ice Age delay
    if (_bi.number() >= _chainParams.constantinopleForkBlock)
    {
        if (exponentialIceAgeBlockNumber >= 5000000)
            exponentialIceAgeBlockNumber -= 5000000;
        else
            exponentialIceAgeBlockNumber = 0;
    }
    // EIP-649 Byzantium Ice Age delay
    else if (_bi.number() >= _chainParams.byzantiumForkBlock)
    {
        if (exponentialIceAgeBlockNumber >= 3000000)
            exponentialIceAgeBlockNumber -= 3000000;
        else
            exponentialIceAgeBlockNumber = 0;
    }

    unsigned periodCount = exponentialIceAgeBlockNumber / c_expDiffPeriod;
    //难度符号加到最后的难度值上
    if (periodCount > 1)
        o += (bigint(1) << (periodCount - 2));  // latter will eventually become huge, so ensure
                                                // it's a bigint.

    o = max<bigint>(minimumDifficulty, o);
    return u256(min<bigint>(o, std::numeric_limits<u256>::max()));
}

对于不同的以太坊阶段,有不同的难度调整算法,Byzantium阶段匹配了协议中的算法

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐