比特币nBits计算

转载:比特币源码分析(二十二) - 挖矿和共识

https://blog.csdn.net/yzpbright/article/details/81231351

CalculateNextWorkRequired()方法:

unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)
{
    if (params.fPowNoRetargeting)
        return pindexLast->nBits;

    // Limit adjustment step
    // 计算生成最近的2016个区块实际花费了多少时间
    int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime;
    //这里需要限制调整的步长,即把实际花费的时间限制在0.5周和8周之间
    if (nActualTimespan < params.nPowTargetTimespan/4)//params.nPowTargetTimespan是2周,即20160分钟
        nActualTimespan = params.nPowTargetTimespan/4;
    if (nActualTimespan > params.nPowTargetTimespan*4)
        nActualTimespan = params.nPowTargetTimespan*4;

    // Retarget
    const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
    arith_uint256 bnNew;
    bnNew.SetCompact(pindexLast->nBits);//旧的难度目标值
    bnNew *= nActualTimespan;
    bnNew /= params.nPowTargetTimespan;

    if (bnNew > bnPowLimit)
        bnNew = bnPowLimit;

    return bnNew.GetCompact();
}

计算公式:新的难度目标值 = 旧的难度目标值 * 生成最近2016个区块所花费的实际时间 / 系统期望生成2016个区块的时间 
其中代码中:nBits 即 旧的难度目标值,nActualTimespa 即 生成最近2016个区块所花费的实际时间 , 
params.nPowTargetTimespan 即 系统期望生成2016个区块的时间 。

2.1.3.3难度目标的表示 
上面讲了难度目标的计算方法,这里再进一步讲一下难度目标的表示方法,难度目标值用nBits表示,nBits是一个无符号的32位整数,定义在src/chain.h的CBlockIndex类中:

    uint32_t nBits;

这个无符号整数的最高位的1个字节代表指数(exponent),低位的3个字节代表系数(coefficient),这个记法将工作量证明的target表示为系数/指数(coefficient/exponent)的格式。 
计算难度目标target的公式为:target = coefficient * 2^(8 * (exponent – 3)) 
例如在区块277,316中,nBits的值为 0x1903a30c,在这个区块里,0x19为指数,而 0x03a30c为系数,计算难度值:

target = 0x03a30c * 2^(0x08 * (0x19 - 0x03))
=> target = 0x03a30c * 2^(0x08 * 0x16)
=> target = 0x03a30c * 2^0xB0

按十进制计算为:

=> target = 238,348 * 2^176
=> target = 22,829,202,948,393,929,850,749,706,076,701,368,331,072,452,018,388,575,715,328

转化回十六进制后为:

=> target = 0x0000000000000003A30C00000000000000000000000000000000000000000000

上述过程就是由无符号的32位整数nBits转为难度值的详细步骤。

由无符号的32位整数nBits转为难度值的函数 
(如:0x1903a30c 转为 0x0000000000000003A30C00000000000000000000000000000000000000000000 ):

// This implementation directly uses shifts instead of going
// through an intermediate MPI representation.
arith_uint256& arith_uint256::SetCompact(uint32_t nCompact, bool* pfNegative, bool* pfOverflow)
{
    int nSize = nCompact >> 24;
    uint32_t nWord = nCompact & 0x007fffff;
    if (nSize <= 3) {
        nWord >>= 8 * (3 - nSize);
        *this = nWord;
    } else {
        *this = nWord;
        *this <<= 8 * (nSize - 3);
    }
    if (pfNegative)
        *pfNegative = nWord != 0 && (nCompact & 0x00800000) != 0;
    if (pfOverflow)
        *pfOverflow = nWord != 0 && ((nSize > 34) ||
                                     (nWord > 0xff && nSize > 33) ||
                                     (nWord > 0xffff && nSize > 32));
    return *this;
}

由难度值转为无符号的32位整数nBits的函数 
(如:0x0000000000000003A30C00000000000000000000000000000000000000000000 转为 0x1903a30c ):

uint32_t arith_uint256::GetCompact(bool fNegative) const
{
    int nSize = (bits() + 7) / 8;
    uint32_t nCompact = 0;
    if (nSize <= 3) {
        nCompact = GetLow64() << 8 * (3 - nSize);
    } else {
        arith_uint256 bn = *this >> 8 * (nSize - 3);
        nCompact = bn.GetLow64();
    }
    // The 0x00800000 bit denotes the sign.
    // Thus, if it is already set, divide the mantissa by 256 and increase the exponent.
    if (nCompact & 0x00800000) {
        nCompact >>= 8;
        nSize++;
    }
    assert((nCompact & ~0x007fffff) == 0);
    assert(nSize < 256);
    nCompact |= nSize << 24;
    nCompact |= (fNegative && (nCompact & 0x007fffff) ? 0x00800000 : 0);
    return nCompact;
}

这两个方法定义在src/arith_uint256.h的 arith_uint256类中。

原文地址:https://www.cnblogs.com/timlong/p/9516373.html