主页 > imtoken钱包app安卓版 > 理解和计算比特币难度难度
理解和计算比特币难度难度
挖矿其实是一场激烈的猜谜游戏,猜的次数取决于全网共识的一个难度值。只有猜出一个使块的哈希与难度相匹配的数字才是正确的谜题答案。
那么,随着越来越多的人加入到这个猜谜游戏中,势必猜得更快。所以为了保持恒定的游戏时间(两周),每场比赛的难度都会根据上一场比赛的时间重新计算。
游戏难度越来越大,如何抢先猜?因此开启了团战模式(矿池)加入游戏,让解谜变得更快更难。速度和难度总是权衡取舍。这也是为什么难度值在 2014 年和 2015 年之后呈指数级增长的原因。当然,解谜设备(矿机)的更新换代越来越快。
比特币难度难度
难度值并没有记录在区块中,它只是一个浮点数进化出来的,供人类直观感受解决问题的难度。公式如下:
这里的难度_1_target 是一个常数,一个非常大的数字。表示矿池中挖矿的最大难度。目标值越小,出块难度越大。
难度值如何存储在块中
块中存储的是Target,但Target是一种类似于浮点数的压缩表示,字段是bits。例如,如果block bits记录是0x1b0404cb,那么他所代表的16进制Target值是:
0x0404cb * 2**(8*(0x1b - 3)) = 0x00000000000404CB000000000000000000000000000000000000000000000000
计算时以后3个字节0x0404cb为基数,前1个字节0x1b代表功率数。具体压缩过程如下:
比如压缩数字1000,先转换成256
1000 = 0x03 * 256 + 0xe8 * 1
然后它由两个数字组成:
03 e8
如果第一个数字不超过0x7f,则不需要填0,但两位数的长度小于三位,后面加0,最终表达式为:
0x0203e800
例如,数字 2^(256-32)-1,转换为 256 十六进制为:
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
第一位已经超过 0x7f,前面加了零:
00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
现在长度为28+1=29(0x1d),最终压缩结果为:0x1d00ffffff。此时精度缺失,丢弃后面的26个ff,因为一共只有4个字节,前两个字节已经被长度和加的0占用了,只剩下2个字节用来存放数字。如果我们解压压缩结果0x1d00ffffff,会是原来的值吗?实际结果是:
0x00ffff *256** (0x1d - 3) = ff ff 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
这个数字是比特币的最大目标值,最小难度是1。在其结果前面加上4个零比特币如何计算出来,结果是:
0x00000000FFFFFF0000000000000000000000000000000000000000000000000000
最小难度值为1,保留尾巴的FF一般用在矿机上,即:
0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
上述数字称为池难度1和池难度1,池难度称为pdiff。比特币客户端可能很难表达这样的精度,所以最后的FF没有保留,结果是:
0x00000000FFFFFF0000000000000000000000000000000000000000000000000000
此值在客户端上称为 bdiff。
如何查看当前难度值
当前的难度值、图表数据可以在多个服务网站上查看:
最大难度值是多少
根据公式,当current_target=0时,难度是无限的,也就是说很难计算。其实current_target不会为0。当current_traget=1时,难度值最大,接近2^(256-32).
什么是最低难度值
current_target=difficulty_1_target为最大值时,难度值为最小值1
如何根据难度值计算网络哈希率
网络计算能力,表示根据难度值找到一个随机数使区块哈希值低于目标值需要多少次。
当前难度值由当前目标值Target决定。如果当前难度为D,那么根据公式:
因此,要找到一个难度为 D 的区块,我们需要计算哈希值的次数为:
目前难度计算速度要求是10分钟内找到,也就是600秒内完成计算,也就是说最低网络算力必须是:
根据上面的计算,当难度值D=1时,每秒需要计算7158278个哈希值,即:7.15Mhahs/s。挖矿每秒算力计算单位:
比特币区块目标值
目标值是一个全网统一的256字节的数字,非常大。最大目标值为 0x1d00ffff。
比特币区块被设计为平均每 10 分钟生成一个新区块。那么我们如何才能保持出块速度呢?区块难度需要动态调整,可以通过定期自动更新目标值来调整难度。因此,比特币被设计成每 2016 个区块,全网会自动统计过去 2016 个区块的生成时间,并重新计算下一个 2016 个区块的目标值。
按10分钟一个区块生成速度,2016个区块生成时间为2016*10分钟=14天。
目标值计算详情
计算目标值的公式如下,但在实际计算中有一些特殊处理,将目标值控制在一定范围内。
新目标值= 当前目标值 * 实际2016个区块出块时间 / 理论2016个区块出块时间(2周)。
计算过程比特币如何计算出来,Go代码如下。点击查看
var (
bigOne = big.NewInt(1)
// 最大难度:00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff,2^224,0x1d00ffff
mainPowLimit = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 224), bigOne)
powTargetTimespan = time.Hour * 24 * 14 // 两周
)
func CalculateNextWorkTarget(prev2016block, lastBlock Block) *big.Int {
// 如果新区块(+1)不是2016的整数倍,则不需要更新,仍然是最后一个区块的 bits
if (lastBlock.Head.Height+1)%2016 != 0 {
return CompactToBig(lastBlock.Head.Bits)
}
// 计算 2016个区块出块时间
actualTimespan := lastBlock.Head.Timestamp.Sub(prev2016block.Head.Timestamp)
if actualTimespan < powTargetTimespan/4 {
actualTimespan = powTargetTimespan / 4
} else if actualTimespan > powTargetTimespan*4 {
// 如果超过8周,则按8周计算
actualTimespan = powTargetTimespan * 4
}
lastTarget := CompactToBig(lastBlock.Head.Bits)
// 计算公式: target = lastTarget * actualTime / expectTime
newTarget := new(big.Int).Mul(lastTarget, big.NewInt(int64(actualTimespan.Seconds())))
newTarget.Div(newTarget, big.NewInt(int64(powTargetTimespan.Seconds())))
//超过最多难度,则重置
if newTarget.Cmp(mainPowLimit) > 0 {
newTarget.Set(mainPowLimit)
}
return newTarget
}
测试代码如下,计算块高为497951+1时计算的新目标值。
func TestGetTarget(t *testing.T) {
firstTime, _ := time.Parse("2006-01-02 15:04:05", "2017-11-25 03:53:16")
lastTime, _ := time.Parse("2006-01-02 15:04:05", "2017-12-07 00:22:42")
prevB := Block{Head: BlockHeader{Height: 497951, Bits: 0x1800d0f6, Timestamp: lastTime}}
prev2016B := Block{Head: BlockHeader{Height: 495936, Bits: 0x1800d0f6, Timestamp: firstTime}}
result := CalculateNextWorkTarget(prev2016B, prevB)
bits := BigToCompact(result)
if bits != 0x1800b0ed {
t.Fatalf("expect 0x1800b0ed,unexpected %x", bits)
}
}