Hi 游客

更多精彩,请登录!

比特池塘 区块链前沿 正文

比特币工作证明与挖矿

天然灵凡
207 0 0
工作证明+ S# e) u$ F, Z' F
工作证明(Proof Of Work,简称POW),顾名思义,即工作量的证明。通常来说只能从结果证明,因为监测工作过程通常是繁琐与低效的。( y3 d, U  n) P
比特币在Block的生成过程中使用了POW机制,一个符合要求的Block Hash由N个前导零构成,零的个数取决于网络的难度值。要得到合理的Block Hash需要经过大量尝试计算,计算时间取决于机器的哈希运算速度。当某个节点提供出一个合理的Block Hash值,说明该节点确实经过了大量的尝试计算,当然,并不能得出计算次数的绝对值,因为寻找合理hash是一个概率事件。当节点拥有占全网n%的算力时,该节点即有n/100的概率找到Block Hash。
5 p: |8 |) f8 P7 r工作证明机制看似很神秘,其实在社会中的应用非常广泛。例如,毕业证、学位证等证书,就是工作证明,拥有证书即表明你在过去投入了学习与工作。生活大部分事情都是通过结果来判断的。# ~. n1 V9 M+ b- F4 z' @& Z+ Q; C
挖矿! g! S8 P% I0 o( |8 a
挖矿即不断接入新的Block延续Block Chain的过程。
0 @1 i8 {, s# A  x
& ~' u7 c3 }% P$ h( L$ N# _挖矿为整个系统的运转提供原动力,是比特币的发动机,没有挖矿就没有比特币。挖矿有三个重要功能:
6 O( Z2 ^5 @2 \8 w发行新的货币(总量达到之前)维系货币的支付功能通过算力保障系统安全
* c. i4 B7 y' x, p- v2 B) ?金矿消耗资源将黄金注入流通经济,比特币通过“挖矿”完成相同的事情,只不过消耗的是CPU时间与电力。当然,比特币的挖矿意义远大于此。
- y& \( N! }3 x4 m
0 z1 {! i+ k( W# g2 XBlock Hash算法' p! w+ A, y2 _9 t1 f
Block头部信息的构成:
. U! E  q+ ]' U/ f# |. U& P
2 K8 b) {2 h4 E下面采用高度为125552的block数据为例,演示block hash的计算过程:
: D* b2 V2 h4 s. m; F9 [) Y( M" G
该计算过程简单明了:首先将数个字段合并成一块数据,然后对这块数据进行双SHA256运算。" W3 I& O3 u0 Y' [/ T) P
产量调节
- L9 H! [3 n% H8 MBlock的产量为大约每两周2016个,即每10分钟一块。该规则在每个节点的代码里都固定了。
) H; @3 O) l% n8 L0 u// 目标时间窗口长度:两周! Z( |- Q& U& }1 n
static const int64 nTargetTimespan = 14 * 24 * 60 * 60;
8 E5 U! I3 T9 U& [) k// block频率,每10分钟一块2 J9 k% v  S* D' p7 H5 [% k  U
static const int64 nTargetSpacing  = 10 * 60;
6 i/ @' v. B8 u' N" T8 P// 每两周的产量2016,也是调节周期
- O/ _9 @8 x& [& ?static const int64 nInterval       = nTargetTimespan / nTargetSpacing;
/ Z/ {0 H7 C( D( k& |6 {- k但由于实际算力总是不断变化的(目前一直是快速上升的),所以需根据最近2016个块的耗费时间来调整难度值,维持每10分钟一个block的频率.( f/ ]4 C0 u0 @" L) U1 Y
// Only change once per interval
! a+ ?% A* l# Q1 [5 rif ((pindexLast->nHeight+1) % nInterval != 0) {
5 I# M4 e( D3 ], f- Z$ v    // 未达到周期个数,无需调节
! k( S7 q0 ~; p( P% s3 d3 _9 Z    return pindexLast->nBits;
& @1 @& o* ^0 L3 Y}
, E: S( D( P" j* @// Go back by what we want to be 14 days worth of blocks
9 q% r" M( n  x" k1 R% W/ ~const CBlockIndex* pindexFirst = pindexLast;; m8 E+ |8 D8 z( D. L3 P
for (int i = 0; pindexFirst && i pprev;: \+ E1 a$ S, p& q  D
// 计算本次2016个块的实际产生时间
+ K8 f* O3 U/ `9 H2 p' j- r7 w// Limit adjustment step6 K" L! t2 v2 j# M, j4 j- x
int64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
6 d/ Y- R& O+ `. S3 p% u5 M4 a  x1 g, x// 限定幅度,最低为1/4,最高为4倍& R) i. {% G6 Q: E6 r* K
if (nActualTimespan  nTargetTimespan*4)
+ u- ?" {% R9 N4 n    nActualTimespan = nTargetTimespan*4;
7 f# o2 h' G7 W// 根据最近2016个块的时间,重新计算目标难度
& W# I' q5 |  `. `' M4 o: B// Retarget5 ]' F. g; V* x- y# {- `% G- V
CBigNum bnNew;
' ]* v' R! a1 d4 ?9 dbnNew.SetCompact(pindexLast->nBits);: J* R. B) y: p2 |: N% R" F; f/ c
bnNew *= nActualTimespan;
; \; s& Z$ E* P: jbnNew /= nTargetTimespan;
0 [1 y  h+ p7 Q) E6 S- \2 _
. }/ z3 f4 a6 hif (bnNew > bnProofOfWorkLimit)5 z6 M3 ^$ K6 P0 c) X
    bnNew = bnProofOfWorkLimit;# M3 T. y& \/ R( c/ t
2 G9 I3 S, [; S
return bnNew.GetCompact();
( t$ c, P( j9 L* M/ `Block字段详解$ q& p# i& C* y1 x
Version,版本号,很少变动,一般用于软件全网升级时做标识hashPrevBlock,前向Block Hash值,该字段强制多个Block之间形成链接hashMerkleRoot,交易Hash树的根节点Hash值,起校验作用,保障Block在网络传输过程中的数据一致性,有新交易加入即发生变化Time,Unix时间戳,每秒自增一,标记Block的生成时间,同时为block hash探寻引入一个频繁的变动因子Bits,可以推算出难度值,用于验证block hash难度是否达标Nonce,随机数,在上面数个字段都固定的情况下,不停地更换随机数来探寻, t( M2 B3 }/ l+ k6 f
最为关键的字段是hashPrevBlock,该字段使得Block之间链接起来,形成一个巨大的“链条”。Block本是稀松平常的数据结构,但以链式结构组织起来后却使得它们具有非常深远的意义:
! y6 d) L: O7 e1 m" r1 }

/ R8 g0 h3 j6 @( Z* T形成分支博弈,使得算力总是在主分支上角逐算力攻击的概率难度呈指数上升(泊松分布). f" C2 f7 p0 ]# \0 K) J
% n$ }3 Q0 u# t$ q4 A: b2 F
每个block都必须指向前一个block,否则无法验证通过。追溯至源头,便是高度为零的创世纪块(Genesis Block),这里是Block Chain的起点,其前向block hash为零,或者说为空。9 Y/ J+ [7 N* G' P& u
新block诞生过程
7 Y/ C( U; ^4 ?5 r0 R. B$ U下面是一个简单的步骤描述,实际矿池运作会有区别,复杂一些:9 w% K# j+ T3 m. H6 X  k; _  g  G
节点监听全网交易,通过验证的交易进入节点的内存池(Tx Mem Pool),并更新交易数据的Merkle Hash值更新时间戳尝试不同的随机数(Nonce),进行hash计算重复该过程至找到合理的hash打包block:先装入block meta信息,然后是交易数据对外部广播出新block其他节点验证通过后,链接至Block Chain,主链高度加一,然后切换至新block后面挖矿
3 h7 b' o' g. B; r由于hashPrevBlock字段的存在,使得大家总是在最新的block后面开挖,稍后会分析原因。
! ]: t0 P3 _% t2 @+ _/ i- a( |5 X' b& ^7 X$ H
主链分叉6 u+ B, U  S7 K0 p' T
从block hash算法我们知道,合理的block并不是唯一的,同一高度存在多个block的可能性。那么,当同一个高度出现多个时,主链即出现分叉(Fork)。遇到分叉时,网络会根据下列原则选举出Best Chain:
2 W8 `% _2 s: ~, J  p3 t不同高度的分支,总是接受最高(即最长)的那条分支
* q/ B4 u; J$ t, _7 G相同高度的,接受难度最大的, D- T: b% R" E' ?1 ~
高度相同且难度一致的,接受时间最早的
# m2 {# N" r3 t9 z5 t! G  p& ^若所有均相同,则按照从网络接受的顺序
) p* D5 V# I' ]) D/ R+ B1 F等待Block Chain高度增一,则重新选择Best Chain$ _6 A9 k2 l6 m& c$ g! e0 _
3 |  V& l' _' A9 X0 l
按照这个规则运作的节点,称为诚实节点(Honest Nodes)。节点可以诚实也可以不诚实。
4 m# v$ p" \% L7 V1 h; p+ @" ^分支博弈- @" }, e7 j# K5 `5 C$ m; i8 o
我们假设所有的节点:
0 O: B9 E9 L: b; B, I都是理性的,追求收益最大化都是不诚实的,且不惜任何手段获取利益
! Q* D' q# z, Y
& R9 P# s* C$ w6 Y所有节点均独自挖矿不理会其他节点,并将所得收益放入自己口袋,现象就是一个节点挖一个分支。由于机器的配置总是有差别的,那么算力最强的节点挖得的分支必然是最长的,如果一个节点的分支不是最长的,意味其收益存在不被认可的风险(即零收益)。为了降低、逃避此风险,一些节点肯定会联合起来一起挖某个分支,试图成为最长的分支或保持最长分支优势。
, \' E) J  G8 G' b一旦出现有少量的节点联合,那么其他节点必然会效仿,否则他们收益为零的风险会更大。于是,分支迅速合并汇集,所有节点都会选择算力更强的分支,只有这样才能保持收益风险最小。最终,只会存在一个这样的分支,就是主干分支(Best/Main Chain)。- S; m4 {7 Z9 x- B. z
对于不诚实节点来说,结局是无奈的:能且只能加入主干挖矿。不加入即意味被抛弃,零收益;加入就是老实干活,按占比分成。) \# _/ ]1 u5 x. O' j- Y
Hash Dance
- D% z# [: O8 z: @: kBlock hash的计算是随机概率事件,当有节点广播出难度更高的block后,大家便跑到那个分支。在比特币系统运行过程中,算力经常在分支间跳来跳去,此现象称为Hash Dance。一般情况下,分支的高度为1~2,没有大的故障很难出现高于2的分支。4 n& ^6 j8 ]7 i/ w' P9 C
Hash Dance起名源于Google Dance.
7 i- N% {6 y( @6 J, H+ U5 ~$ R算力攻击的概率1 G4 g2 ^. d1 P' M8 h
本节内容参考:Bitcoin: A Peer-to-Peer Electronic Cash System
9 n& `0 C9 E& S0 a' C2 B8 o" r算力攻击是一个概率问题,这里作简单叙述:
: s2 B# L# f! R$ \. r5 e9 _p = 诚实节点挖出block概率q = 攻击者挖出block概率,q = 1 - pqz = 攻击者从z个block追上的概率
9 h# \3 C( N" ~1 u  {

& Y( |9 D5 S6 E. A+ m! d" T+ f4 B0 x, `. b5 K, ~
我们假设p>q,否则攻击者掌握了一半以上的算力,那么概率上永远是赢的。该事件(攻击者胜出)的概率是固定,且N次事件之间是相互独立的,那么这一系列随机过程符合泊松分布(Poisson Distribution)。Z个块时,攻击者胜出的期望为lambda:- s  ?2 j) {. z5 h( w
" E/ i2 ^/ V' d, q2 N
攻击者在攻击时已经偷偷的计算了k个块,那么这k个块概率符合泊松分布(下图左侧部分),若k
3 D0 @, \. [) \, M4 Q! Q8 e1 i2 C* [3 m4 x9 Q6 M7 i
展开为如下形式:
% [: l$ A$ l# i* L- g7 ?
. r: L. N- J; w) H* U计算该过程的C语言代码如下:' H& L( w" ~6 w8 c3 N) K8 @
#include
* G- v0 U  I# i8 e( e+ ddouble AttackerSuccessProbability(double q, int z)
* y" z0 r* P1 k4 A/ ~{7 R: q$ S/ h5 v& J  F9 s$ \
    double sum    = 1.0;
( U8 K+ N! b) X2 A+ E+ w4 |2 l    double p      = 1.0 - q;
& k6 V5 N5 e/ H    double lambda = z * (q / p);3 ^! M1 {6 D8 [# G- N4 z
    int i, k;
1 y; e  f7 c; V6 R" l8 X    for (k = 0; k ( T7 P( Z0 E- q
我们选取几个值,结果如下:2 y, u; C6 ]9 ^" ^
/ F( |# i- M1 ]- {' O; b
可以看到,由于block的链式形式,随着块数的上升,攻击者赢得的概率呈指数下降。这是很多应用等待六个甚至六个以上确认的原因,一旦超过N个确认,攻击者得逞的可能微乎其微,概率值快速趋近零。0 ]9 _. r9 U7 R8 e% e) n
当攻击者的算力超过50%时,便可以控制Block Chain,俗称51%攻击。
& c$ N6 B7 h4 o$ f9 v7 j算力攻击的危害
4 _+ R% y9 r, p  u: _攻击者算出block后,block&Txs必须能够通过验证,否则其他节点都会拒掉,攻击便无意义。攻击者无法做出下列行为:
8 [8 t* D# t' z. S偷盗他人的币。消费某个地址的币时,需要对应的ECDSA私钥签名,而私钥是无法破解的。凭空制造比特币。每个block奖励的币值是统一的规则,篡改奖励币值会导致其他节点会拒绝该block。& W! N3 ~( V1 q3 h3 x

6 g  ?1 S/ \" [6 v# G1 |唯一的益处是可以选择性的收录进入block的交易,对自己的币进行多重消费(Double Spending)。
: s- P1 H6 L6 v过程是这样的:假设现在block高度为100,攻击者给商户发了一个交易10BTC,记作交易A,通常这笔交易会被收录进高度101的block中,当商户在101块中看到这笔交易后,就把货物给了攻击者。此时,攻击者便开始构造另一个高度为101的block,但用交易B替换了交易A,交易B中的输入是同一笔,使得发给商户的那笔钱发给他自己。同时,攻击者需要努力计算block,使得他的分支能够赶上主分支,并合并(Merge)被大家接受,一旦接受,便成功地完成了一次Double Spending。
" x5 W' ~; G% A5 k2 T攻击难度呈指数上升,所以成功的Double Spending通常是一个极小概率事件。! T( ^  T% E' Y* n
算力巨头
- ]' a, I. |  ^5 g# j全网算力的上升对比特币是极其有利的,这是毫无疑问的。但目前大矿池与矿业巨头使得算力高度集中化,这与中本聪所设想的一CPU一票(one-CPU-one-vote)的分散局面背道而驰,或许是他未曾预料的。; @* s% ?3 P% z( J3 H
挖矿是一项专业劳动,最后必然会交给最专业的人或团队,因为这样才能实现资源配置最优,效率最高。普通投资人通过购买算力巨头的股票:1. 完成投资;2. 分享算力红利。看似中心化的背后其实依然是分散的:
3 `9 w( y" ]* G1.矿业公司的背后是无数分散的投资人, U% H, i# g. |" |0 l
2.矿池背后是无数分散的个体算力# A5 [$ ], @( X( b. z4 [* V- }) H
既得利益使得算力巨头倾向于维护系统而不是破坏,因其收益均建立在比特币系统之上,既得利益者断然不会搬石头砸自己脚。甚至很多巨头在达到一定算力占比后会主动控制算力增长,使得低于某阈值内。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

天然灵凡 初中生
  • 粉丝

    0

  • 关注

    0

  • 主题

    33