• 比特币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类中。

  • 相关阅读:
    【刷题】Linux修改权限命令
    【刷题】Linux进程通信方式
    【刷题】网络:TCP与UDP
    【刷题】SQL基本操作
    【刷题】数据库三大范式
    【刷题】java会不会内存泄漏
    【刷题】Java-重写和重载
    【刷题】Java面向对象概述
    【刷题】Java垃圾回收常见问题
    测试常见问题合集
  • 原文地址:https://www.cnblogs.com/timlong/p/9516373.html
Copyright © 2020-2023  润新知