⽐特币之难度调整算法推导及实现高考报考
⽐特币⼯作证明基本原理:对⽐特币整个区块头进⾏hash 再进⾏⽐较是否在⼀个特定单位内⼀个hash 的取值范围是 22562^{256}2256次⽅⼤⼩。
难度值(difficulty)是矿⼯们在挖矿时候的重要参考指标,它决定了矿⼯⼤约需要经过多少次哈希运算才能产⽣⼀个合法的区块。⽐特币的区块⼤约每10分钟⽣成⼀个,如果要在不同的全⽹算⼒条件下,新区块的产⽣保持都基本这个速率,难度值必须根据全⽹算⼒的变化进⾏调整。简单地说,难度值被设定在⽆论挖矿能⼒如何,新区块产⽣速率都保持在10分钟⼀个。
难度的调整是在每个完整节点中独⽴⾃动发⽣的。每2016个区块,所有节点都会按统⼀的公式⾃动调整难度,这个公式是由最新2016个区块的花费时长与期望时长(期望时长为20160分钟即两周,是按每10分钟⼀个区块的产⽣速率计算出的总时长)⽐较得出的,根据实际时长与期望时长的⽐值,进⾏相应调整(或变难或变易)。也就是说,如果区块产⽣的速率⽐10分钟快则增加难度,⽐10分钟慢则降低难度。
⽐特币是怎么⾃动调整挖矿难度的呢?
⽐特币是通过将交易头 hash256 ⽣成64 位的hash 值满⾜是否在这个区间来判断当前矿⼯是否挖到矿的。假设有0 ~ 15 的10个数你要猜到⼩于 3 的概率是 216=18\frac{2}{16} =\frac{1}{8}162=81
那么学过计算机的⼩伙伴应该知道16进制表⽰法 16 =f 就相当于2/F的概率那如果是 256= 16216^2162 =ff
如上图, 假定⼀个范围为 0~30 概率为 30/256 = 11.54% 如果要随机猜测的话的话平均要 9次左右才能得到想要的hash值⼩于等于 0-30这个区间内。
但对于计算机来说 1GHZ主频⼤约就是每秒10亿次运算来说⼏百以内的猜数字当然是⼩意思了那怎么办其实很简单把数字范围加⼤不就好了吗
sha 256 ⽣成的是 1.157920892373162e+77 这么⼤的范围区间当你要在⼀个 22562^2562256位的数字中⼀个特定的值的概率是 12256\frac{1}{2^{256}}22561⼤概是
8.636168555094445e-78 也⼏乎是不可能的。假设⼀台计算机每秒能猜 100亿个数字 1e10 那么要猜完全部的数字⼤概是 3.67e+59 年与此相⽐宇宙存在150亿年(1.5e10) 。
⽽⽐特币就是通过⽣成这个22562^{256}2256位的hash 值去计算的
⼩于21282^{128}2128都是正确的值此时可以取到的正确值的总数为样本空间点数:21282^{128}2128 概率为按照古典概型计算:样本空间点/全样本空间点 =
21282256\frac{2^{128}}{2^{256}}22562128=2.938735877055719e-39 可以看出这个范围越⼩难度就越⼤。
假定初始的难度0x00000000FFFF0000000000000000000000000000000000000000000000000000 = 2.695953529101131e+67
那概率是多⼤呢有上⾯的公式可以计算 2.695953529101131e+672256≈2.3282709094019083e−10\frac{2.695953529101131e+67}{2^{256}} \approx2.3282709094019083e-1022562.695953529101131e+67≈2.3282709094019083e−10
打个⽐⽅假如你要买你要中奖概率是100万分之1(概率) 那么你就要买 100万次(次数) 假设假设你买 100万次需要 100年那么你的买效率是 100万次/100年 = 1万次/年
由上⾯可以得出公式: 计算次数 * 概率 = 1
计算次数 = 算⼒ * 时间
⽐特币⼀般是10分钟1块这个值是固定的,这样的话每四年衰减⼀般,到2140 就全部挖完了。算⼒ = 计算次数 / 时间
已知了概率 2.3282709094019083e−102.3282709094019083e-102.3282709094019083e−10
那么计算次数 =12.3282709094019083e−10≈\frac{1}{2.3282709094019083e-10} \approx2.3282709094019083e−101≈ =4295032833.000015
算⼒为 : 4295032833.000015 / 60/ 60 / 10 (化为10分钟) =119306.46758333375 次/分钟
但是随着矿机的添加算⼒就会提升算⼒提升了那么在时间不变的情况下根据公式计算次数就会提升计算次数和概率⼜是成反⽐的那么计算次数增加那么概率就会变⼩那么假设全⽹的算⼒由 119306.46758333375到达了 219306.46758333375 那么概率要怎么调整呢。
由公式得: 概率 = 1 / 计算次数
计算次数 = 219306.46758333375 * 10 * 60 * 60 = 7895032833.000015
那么可以反向推出概率 = 1/ 计算次数 = 1.266619178352438e-10
那么剩下的问题就是从 22562^{256}2256空间中选则的哪个样本空间是这个概率呢。
样本空间/全空间= 概率
样本空间 = 概率 * 全空间 = 1.266619178352438e-10 * 22562^{256}2256 = 1.4666448092948163e+67 转成16进制:
0X000000000ded374e381d4b800000000000000000000000000000000000000000 算⼒提升后的难度
0x00000000FFFF0000000000000000000000000000000000000000000000000000 初始难度
0X000000000ded374e381d4b8 = 1.4666448092948163e+67
0x00000000FFFF =2.695953529101131e+67
为了更直观我们舍去后⾯的 0 可以看到调整后的值明显变⼩了⽽如果画在数轴上
就相当于范围变⼩了范围变⼩了就相当于原来你能买⼀百次的现在只能买50次那中奖概率肯定就会降低。假设有个很能买的⼈⼈家每年2万/次每年那么这种⽅法就相当于达到修改概率还是 100 年中奖。
基于以上推理我们得到以下公式 :
概率 = 1 / 计算次数
七夕是几月几日2022年计算次数 = 算⼒ * 时间
⽬标难度 = 样本空间 = 概率 * 全空间
⽬标难度 = 样本空间 = 1 / 算⼒ * 时间 * 全空间
全空间为:22562^{256}2256
时间为:10 * 60 * 60 = 10分钟 (固定)
初始的难度值 tt= 0x00000000FFFF0000000000000000000000000000000000000000000000000000 实际计算是获取前 n(⽐特币⾥是第前2016个block的bints 存储了当时的难度值)个区块中。
算⼒ = 计算次数/时间
计算次数 = 1/概率qq可以发吗
得:算⼒ = 1/概率 /时间 = 1/概率*时间
改变后⽬标难度改变前⽬标难度=1/改变后算⼒∗时间∗全空间1/改变前算⼒∗时间∗全空间\frac{改变后⽬
标难度}{改变前⽬标难度} = \frac{1 / 改变后算⼒ * 时间 * 全空间}{1 / 改变前算⼒ * 时间 * 全空间}改变前⽬标难度改变后⽬标难度=1/改变前算⼒∗时间∗全空间1/改变后算⼒∗时间∗全空间= 改变后算⼒改变前算⼒\frac{改变后算⼒}{改变前算
⼒}改变前算⼒改变后算⼒= 1/调整前概率∗算⼒改变后时间1/调整前概率∗算⼒改变前时间\frac{1/调整前概率*算⼒改变后时间 }{1/调整前概率*算⼒改变前时
间}1/调整前概率∗算⼒改变前时间1/调整前概率∗算⼒改变后时间= 算⼒改变后时间算⼒改变前时间\frac{算⼒改变后时间}{算⼒改变前时间}算⼒改变前时间算⼒改变后时间
所以得出:改变后⽬标难度改变前⽬标难度\frac{改变后⽬标难度}{改变前⽬标难度}改变前⽬标难度改变后⽬标难度=算⼒改变后时间算⼒改变前时间\frac{算⼒改变后时间}{算⼒改变前时间}算⼒改变前时间算⼒改变后时间
改变后⽬标难度 = 改变前⽬标难度∗算⼒改变后时间算⼒改变前时间改变前⽬标难度 *\frac{算⼒改变后时间}{算⼒改变前时间}改变前⽬标难度∗算⼒改变前时间算⼒改变后时间算⼒改变后时间就是前n个⽐特币⾥设定2周每 10分钟⼀个就是2016个块实际运⽤时间
算⼒改变前时间控制在10分钟这个时间
所以总结就是只要知道前特定次的实际花费时间和期望需要花费的时间做个⽐值再乘以第那⼀次的困难度就可以了。
以下是代码:
public static void main(String[] args) {
public final static Integer nTargetTimespan = 14 * 24 * 60 * 60; //过去两周时间
public final static Integer nTargetSpacing = 10 * 60; //期望挖矿时间
public final static Integer nInterval = nTargetTimespan / nTargetSpacing; //过去2周期望达到的区块数 2016个
public final static String num2 =new BigInteger("0FF0000000000000000000000000000000000000000000000000000000000000", 16).toString();//初始难度
BigDecimal numb2 = new BigDecimal(num2);
//实际时间
float timeInterval = 1;
float scale = timeInterval/nTargetTimespan;
System.out.println("缩放⽐例:"+scale+"如果当前的算⼒越⼤花费时间越⼩和预期时间不变并成反⽐缩放⽐例也就越⼩ ");
//假设
int precision = 0; // 0位⼩数
BigDecimal NEWb = new BigDecimal(numb2.multiply(new BigDecimal(scale)).toString()).setScale(precision, RoundingMode.DOWN);
String toHex = String.format("%#x",BigInteger());
StringBuilder zeroHeader = new StringBuilder();
/**
* 下⾯代码⾃动补⾜长度为64位如 0x00028ccccbd8000000000000000000000000000000000000000
0000000000000
*/
for(int i =0;i<64 - place("0x","").length() +1;i++){
zeroHeader.append("0");
}
for(int m =2;m< toHex.length() -1;m++){
zeroHeader.append(toHex.charAt(m));
}
toHex = "0x" + String();
System.out.println(toHex + "\n"+toHex.length() +"0x".length());
}
⽐特币⾥ nbits字段⽤来存放区块难度
Bits:0x18013ce9(以⼗六进制显⽰)
上⾯这个其实是 0x0000000000000000013ce9000000000000000000000000000000000000000000 压缩格式。主要就是将⼀长串00省去了。
⽐特币难度字符串反压缩算法:target = coefficient * 0x02^(0x08 * (exponent – 0x03))
public static String decodeBits(String nbits){
dota常用命令if(nbits.startsWith("0x"))
nbits = nbits.substring(2,nbits.length());
int end= 0;
int begin = 0;
for(int i=0;i<nbits.length()-1;i++){
char ch =nbits.charAt(i);
买正品化妆品if(ch !='0' && begin == 0){
begin= i;//开始标记
}
//如果当前字符是 0且前⼏次都是零
if(ch =='0' && begin ==0)
continue;
if(ch !='0')
//记录最后⼀个⾮0 char的index
end = i;
}
String co = "0"+nbits.substring(begin,end+1);
BigDecimal traget =new BigDecimal(new BigInteger(nbits,16));华北地区
BigDecimal coefficient =new BigDecimal(new BigInteger(co,16));
Double xx = traget.divide(coefficient).doubleValue();
System.out.println(traget.divide(coefficient));
Double mm =Math.log(xx)/Math.log(2) / 0x08 + 0x03;
return "0x" + HexString(mm.intValue()) + co;
}
⽐特币难度字符串压缩算法 :log(traget/coefficient ,0x02) /0x08 + 0x03
public static String unDecodeBits(String nbits){
String a = "0x1903a30c";
String ex = a.substring(2,4);
String co = a.substring(4,a.length());
BigInteger exponent = new BigInteger(ex,16);
BigInteger coefficient = new BigInteger(co,16);
Double xx =exponent.subtract(new BigInteger("3")).multiply(new BigInteger("8")).doubleValue();
System.out.println(xx);
Double ax = Math.pow(2,xx);
BigDecimal res = new BigDecimal(coefficient).multiply(new BigDecimal(ax));
System.out.BigInteger());
String toHex = String.format("%#x.",BigInteger());
System.out.println(autoformat(toHex));
return autoformat(toHex);
}
public static String autoformat(String toHex){
StringBuilder zeroHeader = new StringBuilder();
/**
* 下⾯代码⾃动补⾜长度为64位如 0x00028ccccbd80000000000000000000000000000000000000000000000000000
*/
for(int i =0;i<64 - place("0x","").length() +1;i++){
zeroHeader.append("0");
}
for(int m =2;m< toHex.length() -1;m++){
zeroHeader.append(toHex.charAt(m));
}
toHex = "0x" + String();
UpperCase();
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论