Hi 游客

更多精彩,请登录!

比特池塘 区块链前沿 正文

比特币工作证明与挖矿

天然灵凡
105 0 0
工作证明1 M! c( M) H6 y! R6 {/ V
工作证明(Proof Of Work,简称POW),顾名思义,即工作量的证明。通常来说只能从结果证明,因为监测工作过程通常是繁琐与低效的。
8 H9 u8 U* r# K% w比特币在Block的生成过程中使用了POW机制,一个符合要求的Block Hash由N个前导零构成,零的个数取决于网络的难度值。要得到合理的Block Hash需要经过大量尝试计算,计算时间取决于机器的哈希运算速度。当某个节点提供出一个合理的Block Hash值,说明该节点确实经过了大量的尝试计算,当然,并不能得出计算次数的绝对值,因为寻找合理hash是一个概率事件。当节点拥有占全网n%的算力时,该节点即有n/100的概率找到Block Hash。* u0 _: I6 W+ }* A5 w+ w1 }( t" T
工作证明机制看似很神秘,其实在社会中的应用非常广泛。例如,毕业证、学位证等证书,就是工作证明,拥有证书即表明你在过去投入了学习与工作。生活大部分事情都是通过结果来判断的。
" i# @  j0 d6 |挖矿0 L4 A" J! x: i' ?( G! l
挖矿即不断接入新的Block延续Block Chain的过程。1 K: `; S! J, I% C* U9 ^. g

' B$ u) i( L$ R+ s- i挖矿为整个系统的运转提供原动力,是比特币的发动机,没有挖矿就没有比特币。挖矿有三个重要功能:
8 F+ @: K+ h  i: R  h* z发行新的货币(总量达到之前)维系货币的支付功能通过算力保障系统安全7 s  X. J" v, {) W+ A5 L, }1 C
金矿消耗资源将黄金注入流通经济,比特币通过“挖矿”完成相同的事情,只不过消耗的是CPU时间与电力。当然,比特币的挖矿意义远大于此。! y9 W( _7 Q4 y1 {5 [, {3 P' }

! E$ a" w9 A! uBlock Hash算法
" T. h: e, i; R, oBlock头部信息的构成:: c: ~  @: P8 K* Q' K
" J% I+ V% n4 v
下面采用高度为125552的block数据为例,演示block hash的计算过程:$ c9 ]% d: i8 Q
- {; F) B7 {7 }0 v
该计算过程简单明了:首先将数个字段合并成一块数据,然后对这块数据进行双SHA256运算。. V5 b6 s* O. _4 b
产量调节+ }7 u5 H# g( m
Block的产量为大约每两周2016个,即每10分钟一块。该规则在每个节点的代码里都固定了。
$ A2 \  X5 \- ?/ A! `$ P// 目标时间窗口长度:两周
  u' X& g0 U# B7 }* V# q# Y9 V4 Mstatic const int64 nTargetTimespan = 14 * 24 * 60 * 60;
, ~$ z* g! J# q2 k// block频率,每10分钟一块. ]/ g8 b4 ?- j0 |- z+ i
static const int64 nTargetSpacing  = 10 * 60;
2 T  o5 \" }$ c// 每两周的产量2016,也是调节周期
% H$ C/ F* F* K  }static const int64 nInterval       = nTargetTimespan / nTargetSpacing;
8 ]2 R+ g' w, j4 ^5 c* _7 X但由于实际算力总是不断变化的(目前一直是快速上升的),所以需根据最近2016个块的耗费时间来调整难度值,维持每10分钟一个block的频率.
, V" @/ p  T( g; Z" Z. g8 W$ H$ d// Only change once per interval( u# R: J4 V5 A8 x& Y8 f$ B
if ((pindexLast->nHeight+1) % nInterval != 0) {
! z& m9 H/ p. U9 F% m# E3 R+ M    // 未达到周期个数,无需调节
; @9 r" [4 L! V. R$ n8 F    return pindexLast->nBits;
# d8 o( E; |* T* F8 b  w, L1 Z, B}5 T( B$ K. Z5 n0 [
// Go back by what we want to be 14 days worth of blocks3 j7 D2 E* Y6 h1 h7 S7 ?$ {" f
const CBlockIndex* pindexFirst = pindexLast;
, ]  h+ q* O$ |& d/ @$ Bfor (int i = 0; pindexFirst && i pprev;1 ~! W1 p8 S9 t4 \% H
// 计算本次2016个块的实际产生时间
! A0 z5 d8 e: \0 V5 f! @5 _// Limit adjustment step
* J, l# W* m) j7 pint64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();8 c4 J& ^6 D8 ]/ ?
// 限定幅度,最低为1/4,最高为4倍* Q( C! y. ?9 p$ h
if (nActualTimespan  nTargetTimespan*4)
: f- [4 G, v/ M, F3 Y) g% Z    nActualTimespan = nTargetTimespan*4;1 S$ @7 g: M- i8 U: I$ l7 t
// 根据最近2016个块的时间,重新计算目标难度
- ^6 |+ \& T  f) _// Retarget
5 r" ~/ R$ O0 LCBigNum bnNew;. A- ], y8 O7 ?" ?7 G; Y
bnNew.SetCompact(pindexLast->nBits);
/ }% |" W3 X/ w; UbnNew *= nActualTimespan;
5 n$ P8 L# r4 ^4 m* K. e" }% g6 }bnNew /= nTargetTimespan;% w9 h; b& ^5 u% `! W. \

2 t6 Z- F4 l5 o5 ]8 z  nif (bnNew > bnProofOfWorkLimit)2 ~- b( `8 `8 Y# C2 h0 e  Y
    bnNew = bnProofOfWorkLimit;/ a3 d/ f$ @9 @. n6 h

+ a+ ~9 X$ x) S) G) |return bnNew.GetCompact();4 m3 L/ G( @3 l$ y1 t$ e0 ?+ B! p
Block字段详解1 ~# x1 L% e* W  H7 y1 M) W2 ?
Version,版本号,很少变动,一般用于软件全网升级时做标识hashPrevBlock,前向Block Hash值,该字段强制多个Block之间形成链接hashMerkleRoot,交易Hash树的根节点Hash值,起校验作用,保障Block在网络传输过程中的数据一致性,有新交易加入即发生变化Time,Unix时间戳,每秒自增一,标记Block的生成时间,同时为block hash探寻引入一个频繁的变动因子Bits,可以推算出难度值,用于验证block hash难度是否达标Nonce,随机数,在上面数个字段都固定的情况下,不停地更换随机数来探寻
5 S5 |9 p4 d6 W% z  q# o+ ~7 i最为关键的字段是hashPrevBlock,该字段使得Block之间链接起来,形成一个巨大的“链条”。Block本是稀松平常的数据结构,但以链式结构组织起来后却使得它们具有非常深远的意义:  o+ l% v$ K8 t( M' J
  K! Q& y# V4 h0 L8 G0 S
形成分支博弈,使得算力总是在主分支上角逐算力攻击的概率难度呈指数上升(泊松分布)( h+ P+ f1 Z/ K. V" t  D
6 L/ v8 ^( R! F6 K6 H, Z: G
每个block都必须指向前一个block,否则无法验证通过。追溯至源头,便是高度为零的创世纪块(Genesis Block),这里是Block Chain的起点,其前向block hash为零,或者说为空。
& {* {- J& ?# d2 e! E% T# l新block诞生过程0 V. N8 A- `2 N9 ~7 M" {7 T
下面是一个简单的步骤描述,实际矿池运作会有区别,复杂一些:
6 H- N( o0 b  b2 m: B& y& a节点监听全网交易,通过验证的交易进入节点的内存池(Tx Mem Pool),并更新交易数据的Merkle Hash值更新时间戳尝试不同的随机数(Nonce),进行hash计算重复该过程至找到合理的hash打包block:先装入block meta信息,然后是交易数据对外部广播出新block其他节点验证通过后,链接至Block Chain,主链高度加一,然后切换至新block后面挖矿
# {2 G6 D2 ^$ r# b% l7 T( F由于hashPrevBlock字段的存在,使得大家总是在最新的block后面开挖,稍后会分析原因。" P: f" b9 {* I1 o$ Q
* a4 O' q+ k! [' K0 }0 z
主链分叉2 q1 Z, L) T: y4 S
从block hash算法我们知道,合理的block并不是唯一的,同一高度存在多个block的可能性。那么,当同一个高度出现多个时,主链即出现分叉(Fork)。遇到分叉时,网络会根据下列原则选举出Best Chain:4 k( X& @$ K! M6 K$ d' ~
不同高度的分支,总是接受最高(即最长)的那条分支
* n6 L' u; F, ]- f* q& O* Y相同高度的,接受难度最大的$ A# h1 F  K1 Y& w
高度相同且难度一致的,接受时间最早的& |% k/ K4 p4 ]6 R: ~# ^
若所有均相同,则按照从网络接受的顺序
3 m3 ]. G2 Q0 G等待Block Chain高度增一,则重新选择Best Chain8 V" H7 a: ?  ~+ l2 D  l' J
# h* L/ v8 @$ R% q: W/ P
按照这个规则运作的节点,称为诚实节点(Honest Nodes)。节点可以诚实也可以不诚实。7 x6 t" |) f% u5 a- h
分支博弈
0 J0 }0 G; O  T( R; [- D我们假设所有的节点:6 T& N& Q# U, t% b
都是理性的,追求收益最大化都是不诚实的,且不惜任何手段获取利益5 S0 p  s3 a& Y& m# x. F1 R

7 s; K6 C8 C1 @所有节点均独自挖矿不理会其他节点,并将所得收益放入自己口袋,现象就是一个节点挖一个分支。由于机器的配置总是有差别的,那么算力最强的节点挖得的分支必然是最长的,如果一个节点的分支不是最长的,意味其收益存在不被认可的风险(即零收益)。为了降低、逃避此风险,一些节点肯定会联合起来一起挖某个分支,试图成为最长的分支或保持最长分支优势。' }7 P3 Q) [$ S1 V* p8 B( Y' y
一旦出现有少量的节点联合,那么其他节点必然会效仿,否则他们收益为零的风险会更大。于是,分支迅速合并汇集,所有节点都会选择算力更强的分支,只有这样才能保持收益风险最小。最终,只会存在一个这样的分支,就是主干分支(Best/Main Chain)。
7 Z1 Y- w; p. s9 D+ ?# w对于不诚实节点来说,结局是无奈的:能且只能加入主干挖矿。不加入即意味被抛弃,零收益;加入就是老实干活,按占比分成。
0 S/ [8 ?' P4 _1 H2 OHash Dance. m) d9 ~/ |9 k: r% k2 \, Y: k
Block hash的计算是随机概率事件,当有节点广播出难度更高的block后,大家便跑到那个分支。在比特币系统运行过程中,算力经常在分支间跳来跳去,此现象称为Hash Dance。一般情况下,分支的高度为1~2,没有大的故障很难出现高于2的分支。
* @/ ?  t) [8 uHash Dance起名源于Google Dance.1 T3 z+ }) {  r! _4 z
算力攻击的概率
' l. j8 Q/ u7 t' s本节内容参考:Bitcoin: A Peer-to-Peer Electronic Cash System1 e" I) q/ X4 v0 _2 [5 k) Z# b; N
算力攻击是一个概率问题,这里作简单叙述:
. I3 H, G3 a; P: D! K/ u6 lp = 诚实节点挖出block概率q = 攻击者挖出block概率,q = 1 - pqz = 攻击者从z个block追上的概率
4 M5 S' t, ^2 t7 @  I6 p$ u& L
2 B2 c5 \+ I  Y  n# W0 L5 B9 E3 D8 R" X! O

$ c$ V  N6 V' t0 R. Z我们假设p>q,否则攻击者掌握了一半以上的算力,那么概率上永远是赢的。该事件(攻击者胜出)的概率是固定,且N次事件之间是相互独立的,那么这一系列随机过程符合泊松分布(Poisson Distribution)。Z个块时,攻击者胜出的期望为lambda:
! r* S" R! i+ P! C! M% R2 [
# f% [6 O# D. ]5 |, M- v" R$ X攻击者在攻击时已经偷偷的计算了k个块,那么这k个块概率符合泊松分布(下图左侧部分),若k
+ a( ]& }! V: H3 P9 Q$ B" b) }. w9 @' A7 o4 q; {! y
展开为如下形式:5 q4 Z3 D3 l" b! Q+ f! w* a7 y( G
% w% `' ^) ^2 W. r
计算该过程的C语言代码如下:( e6 O2 a0 |0 h. _( C- P2 M6 U' C
#include
, n$ R: D, G+ ?7 s4 udouble AttackerSuccessProbability(double q, int z)
6 V  w5 C  a, f2 U: C{# P  N6 g9 D- `- W" \$ u0 T% X$ ^( B
    double sum    = 1.0;% ~4 n: |9 t; q1 X
    double p      = 1.0 - q;! b0 C% o' _' x2 D6 S0 H" J- L+ X
    double lambda = z * (q / p);9 A! f* l+ H5 X6 I8 h& `  y
    int i, k;
- V" A/ ^' A5 \, O& y5 L" y' Y: u    for (k = 0; k
6 Z& e+ g' e9 I4 p; x% `我们选取几个值,结果如下:8 r" W" r# f+ k- @

7 W5 d9 u4 Z, {4 Z* |- d4 l可以看到,由于block的链式形式,随着块数的上升,攻击者赢得的概率呈指数下降。这是很多应用等待六个甚至六个以上确认的原因,一旦超过N个确认,攻击者得逞的可能微乎其微,概率值快速趋近零。
1 y8 C2 I9 G7 a5 `" }7 ^( h( ^当攻击者的算力超过50%时,便可以控制Block Chain,俗称51%攻击。, v; w/ G( k) @/ N8 G
算力攻击的危害" w4 S* @, u- @# v1 ]
攻击者算出block后,block&Txs必须能够通过验证,否则其他节点都会拒掉,攻击便无意义。攻击者无法做出下列行为:" U  S  Q; b* c0 I
偷盗他人的币。消费某个地址的币时,需要对应的ECDSA私钥签名,而私钥是无法破解的。凭空制造比特币。每个block奖励的币值是统一的规则,篡改奖励币值会导致其他节点会拒绝该block。) s* b( M' P* g, o9 @5 i
7 D- Z. h3 s- X
唯一的益处是可以选择性的收录进入block的交易,对自己的币进行多重消费(Double Spending)。+ R, [1 z% ~$ E, C( l; g4 }
过程是这样的:假设现在block高度为100,攻击者给商户发了一个交易10BTC,记作交易A,通常这笔交易会被收录进高度101的block中,当商户在101块中看到这笔交易后,就把货物给了攻击者。此时,攻击者便开始构造另一个高度为101的block,但用交易B替换了交易A,交易B中的输入是同一笔,使得发给商户的那笔钱发给他自己。同时,攻击者需要努力计算block,使得他的分支能够赶上主分支,并合并(Merge)被大家接受,一旦接受,便成功地完成了一次Double Spending。9 W0 J3 P7 W# ]
攻击难度呈指数上升,所以成功的Double Spending通常是一个极小概率事件。
1 @+ T5 j* c8 ?% s算力巨头
6 Y) y8 O3 Z& D3 y9 T4 r- a9 e3 z全网算力的上升对比特币是极其有利的,这是毫无疑问的。但目前大矿池与矿业巨头使得算力高度集中化,这与中本聪所设想的一CPU一票(one-CPU-one-vote)的分散局面背道而驰,或许是他未曾预料的。! P) @8 ?5 D3 m' A/ S$ v
挖矿是一项专业劳动,最后必然会交给最专业的人或团队,因为这样才能实现资源配置最优,效率最高。普通投资人通过购买算力巨头的股票:1. 完成投资;2. 分享算力红利。看似中心化的背后其实依然是分散的:
1 f) Y( a+ P' j  T1.矿业公司的背后是无数分散的投资人/ k- O1 D: J4 Q% d$ A# N9 k9 B% ]
2.矿池背后是无数分散的个体算力: z. ^9 U! S. M# C& v3 H
既得利益使得算力巨头倾向于维护系统而不是破坏,因其收益均建立在比特币系统之上,既得利益者断然不会搬石头砸自己脚。甚至很多巨头在达到一定算力占比后会主动控制算力增长,使得低于某阈值内。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

天然灵凡 初中生
  • 粉丝

    0

  • 关注

    0

  • 主题

    33