比特币开发者指南(一)--- 区块链

作者: lovetianyats | 来源:发表于2017-08-28 09:14 被阅读1092次

    申明:本文为译文,原文档地址为官网

    开发者指南旨在提供有助于理解比特币以及开始构建比特币应用所需的应用程序所需的信息,但这不是规格说明。为了最有效的利用此文档,你可能想要安装最新的比特币客户端(Bitcoin-Core,可以从源代码直接构建或者下载预编译版本)。

    有关于比特币开发的问题最好到比特币开发社区里面提问。此文档(Bitcoin.org上的)的错误或者疑问可以提交到比特币文档的邮件列表里。

    区块链

    区块链提供了比特币的公开账簿---一个有序的、带有时间戳的交易记录。这个系统被用来防止双重消费和篡改交易记录的问题。

    比特币网络中的每一个全结点都会存储一个整个区块链的备份,其中每个块都经过了验证。当一些结点拥有同样的区块时,它们被称之为达成了“一致”。本节描述比特币使用的一些一致性规则

    区块链概览


    上面的图展示了一个区块链的简化版本。一个或多个交易信息被收集到了区块的交易部分。交易信息通过默克尔树的形式组织起来,默克尔树的树根被存储到了区块的头部中。区块头部中还存储了前面一个块的哈希,这样就可以将区块连接成一个有序的串。这样就可以保证一个若要修改一个交易信息,不但要修改当前块,而且要修改当前块之后的所有块。

    交易通过区块,也形成了一个隐形的串。比特币钱包软件存储了发送到或者从钱包中发出的‘’(比特币的单位),这里虽然从用户角度来看‘聪’是从一个一个用户转移到了另一个用户,但是比特币的‘聪’实际上是从一笔交易被转移到另一笔交易的。(译者注:这里在了解完比特币的原理之后就可以理解)。每一笔交易将之前交易中输出的’聪‘作为下一笔交易的输入,下一笔交易的输出又被作为下下笔交易的输入,以此类推。可以看下图:


    一笔交易可以产生多个输出,如在将‘聪’发送到多个地址的情况,但是每一个输出在整个区块链中只能被花一次。任何对一个输出的第二次引用是被禁止的,因为这会造成双重消费问题。

    输出(outputs)被绑定到了交易标识符(TXIDs),也就是真个交易信息的哈希值。

    由于每一笔交易的输出只能被花一次,因此整个区块链上的输出可以被分为没有被花的(Unspent Transaction Outputs: UTXO)和已经被花的。一个支付信息只有在输入是UTXO的时候才是合法的。

    除了coinbase交易(后面会描述),如果一笔交易的输出超过了他的输入,它会被拒绝。但是如果输入超过了输出,这之间的差值会被用作交易费用用来奖励下一个产生区块的用户。举例来说,在上面的图中,每一笔交易的输入都比他的输出多了10000聪,这10000聪就被作为交易费了。

    工作量证明(PoW)

    区块链有网络上所有的匿名结点共同维护着,因此比特币需要每一个块证明它在被“铸造”出来的时候消耗了足够多的工作量。这是为了确保哪些不值得信任的节点如果想要篡改区块链的信息必须消耗比诚实节点更多的工作量,因为诚实节点只需要增加新的区块(译者注:而妄图篡改旧区块的结点却需要额外付出创造被篡改区块的工作量)。

    区块链的这种一个连接着一个的有序结构使得想要篡改一个区块必须要篡改该区块之后所有的区块。这样修改一个区块的开销就变成了,修改该区块及其之后所有区块的工作量,这就放大了工作量证明的影响。

    区块链的工作量证明利用了密码学中哈希函数的随机性。一个好的密码学哈希算法会将任意数据转化为一个看似随机的数。只要数据中任何一个比特被改变了,那么数据的哈希就会变得完全不一样,因此无论怎么改变数据,其哈希值改变的规律是无法把握的。

    为了证明你为了创建一个区块确实付出了一定的工作量,你必须找出一个比特定阈值小的哈希。举例来说,如果最大可能的哈希值是$2{256}-1$,那么需要产生一个比$2{255}$小的哈希值,平均只需要$2 = 2 ^ {256 - 255} = 2 ^ {1}$次尝试不同类型的组合。

    在上面的例子中平均每两次尝试就会产生一个有效的哈希值。在目标哈希值已知的情况下,你甚至可以预测每次计算哈希值达到阈值成功的概率。比特币每次计算哈希值达到阈值的概率与其尝试的次数是成线性关系的(译者注:就是尝试次数越多,成功的概率越大---废话 o|||)。

    新的块只有在它所包含的哈希值达到目标值的时候才会被夹到区块链中去。这个目标值是通过一致性协议得到的。每2016个区块,比特币网络会使用存储在这2016个区块头部中的时间戳来计算生成这2016个区块的第一个到最后一个区块所花费的时间。理想值是1209600s(也就是两星期)。

    • 如果花了少于两星期,那么难度就会做相应的增加(最多300%),这样下一批2016个区块,在全网的计算哈希的能力没变的情况下,就会在精确的两星期的时间内产生(译者注:实际上没有那么精确)。

    • 如果画了多于两星期的时间来产生区块,那么难度就会按比例下降(最多75%)。

    (注意:Bitcoin Core实现中的一个差一错误会引起难度的更新重原本的每2016个块更新一次难度变成了每2015个块更新一次,这产生了一个小小的偏差)

    因为每一个区块的头部的哈希必须小于一个目标阈值,同时一个区块被连接到现前一个区块的后面,如果要传播一个被更改的区块,在平均情况下,就需要付出从那个区块开始到当前最新区块全网付出的所有哈希计算量。只有在你拥有了全网大部分计算能力,你就可以轻易的发动51%攻击(可以改变比特币区块链的交易历史,已经有工作表明这种攻击在没大于全网的50%的计算能力下,也很有可能攻击成功)。

    区块头部提供了一些可以被更改的字段,比如一个专用的nonce字段,因此为了获得一个新的哈希值不笔在等待新的交易到来,只需要改变一下nonce字段就好了。再有,只有80字节的区块头部才会被用于计算用于证明工作量的哈希值,因此,包含大量的交易并不会增加计算哈希所需的IO,增加额外的交易只需要重新计算默克尔树的根哈希就行了。

    区块链高度和分叉

    任何一个矿工在成功将区块头部的哈希调整到一个目标阈值之下的时候,都可以将整个区块添加到区块链上(当然是在区块有效的情况下)。这些区块可以通过区块高度(该区块到创始块区块的数量)来索引,创世块的高度为0。比如,块2016是区块链难度系数第一次调整的地方。

    当两个或多个矿工在同一个区块上都挖出了新的区块之后,那么就可能产生多个区块高度一样的情况。这样就会在区块链上产生一个分支(如上图)。

    当矿工在区块链尾部同时产生区块时,那么每个矿工会自由选择在哪一个区块上继续工作。在没有其他考虑的情况下,像下面讨论的那样,结点通常选择它们首次发现的区块。

    最终某个矿工会在同样高度的某个分叉上产生一个新的区块,这样这个分支就会比其他分支工作量多。假设一个分支只包含有效块,一般的结点都会在工作量最大的链上继续寻找新的区块,而将旧的分支区块抛弃。(哪些旧的区块通常被称之为孤儿或者孤块,这些属于也被用作描述真正的孤块(就是在它前面没有区块))。

    分叉长期存在是又可能的,比如说不同的矿工的工作目的不一样。比如:诚实的矿工们在勤奋的为了拓展区块链的时候,一些矿工却在为了篡改交易历史在发动51%攻击。

    由于在有分枝存在的情况下,多个区块可能有同样的高度,区块高度不应该作为一个全局唯一的标识符。取而代之的是区块头部的哈希值(通常是16进制形式的,并且是反字节序的)。

    交易数据

    每一个区块必须包含一个或者多个交易。而区块所包含交易集合中的第一个一定是coinbase交易,这个交易也被称作生成交易(generation transaction),这个交易中包含了一定数额的比特币奖励以及交易费用的奖励。

    Coinbase 交易的输出(UTXo)(就是全新出炉的比特币)是不能被立即花掉的,而必须等待其后产生了100个新的区块。这可以防止矿工花了之后被证明是孤块中的比特币。

    虽然区块没有被要求一定要包含coinbase交易,但是几乎所有的矿工都总会包含这样一个交易用来收集它们的交易费及额外的交易奖励。

    包括coinbase交易之内的所有交易都被以未经处理的二进制形式编码进区块中去。

    这种未经处理的形式的交易信息的哈希被用作交易标识符。这些交易标识符被用来构建默克尔树。由于构建默克尔树需要偶数数量的叶子结点,如果存在基数数量的交易,那么最后一个交易就会产生一个自身的副本。

    一个包含五个交易的默克尔树如下图所示:

           ABCDEEEE ....... 默克尔树的树根
          /        \
       ABCD        EEEE
      /    \      /
     AB    CD    EE ....... E和他自己组成一组
    /  \  /  \  /
    A  B  C  D  E ......... 5个交易
    

    在简单支付验证(SPV)那一章中,摩尔棵树可以让客户端自己验证一笔交易已经被包含到区块中去了(通过区块头部中的默克尔树来证明)。全结点没有不笔是可信的:假冒一个区块头部的代价是昂贵的,而默克尔树的中间结点的哈希是无法篡改的,不然验证就会失败。

    举例来说,为了验证交易D已经被添加到了区块中去,一个SPV客户端只需要C,AB和EEEE的哈希加上默克尔树的根哈希就行了。客户端不需要知道其他交易的任何信息。如果这个块中的5个交易所在的区块是当前允许的最大大小500000字节(译者注:现在是4M),那么下载整个区块的需要500K的数据量而下载我们验证交易的信息只需要140字节(包括区块头在内)。

    注意:(译者注:这个是比特币客户端的一个Bug,感兴趣的点这里查看详情)

    一致性规则变更

    为了维持区块链的一致性,所有的全结点(译者注:相对于SPV客户端而言的)使用同样的规则来验证区块的有效性。但是,有时候一致性规则需要被改变来引进新的特性或者放置网络被滥用。新的规则被实现之后,需要一定时间来让使用旧规则的结点更新到新的结点,在此过程当中一致性就会被打破。

    译者注:这里有几段内容主要是为了解释软分叉和硬分叉,但是就我看来,不知所云,所以就没有翻译。这里简单讲一下译者个人理解:软分叉就是老用户对升级之后用户发出的交易虽然无法识别但是不拒绝,也会接受,因此不会产生分叉;而硬分叉是指老用户直接拒绝了新的交易,这样显然会产生分叉。另外一点就是:硬分叉应该会产生永久的分叉。(不知道理解对不对)


    一致性协议的改变会以不同的方式被激活。在比特币的头两年里,中本聪通过一些在客户端的后向兼容的改变来立即强制执行新的规则,这进行了几次软分叉。多个软分叉(比如:BIP30)在某一个预先设置好的某一天或者比特币区块链达到固定高度的时候被激活。这些通过某个预设的时间点导致的分叉被称为用户激活软分叉(User Activated Soft Forks (UASF)),这些软分叉依赖于大量的有效的全结点的共同努力来在某一个时间点之后强制执行某些新的规则。

    之后,软分叉就等待大部分(典型的是75%和95%)哈希计算力释放出接受新规则的信号。一旦达到了阈值(75%或95%),所有节点就强制执行新规则。这种分叉被称为矿工激活软分叉(Miner Activated Soft Forks (MASF))。

    其他资源BIP16, BIP30BIP34 这些改进措施也是为了辅助软分叉的。BIP50描述了一个可以通过将升级结点降级暂时降级的方法来解决意外出现的硬分叉,同时还描述了一个人为的当临时降级被去除时出现的分叉。Gavin Andresen的给出了一个文档《未来规则变更如何实现》

    分叉检测

    未升级的节点可能会在两种类型的分支中使用和分发不正确的信息,从而创建可能导致经济损失的几种情况。特别地,未升级的节点可以中继和接受被升级的节点认为无效的交易,因此这些包含这些交易的区块永远不会成为普遍认可的最佳块链(最长的)的一部分。未升级的节点还可以拒绝中继已被添加到或者即将被添加到最佳块链中的区块或交易,并且因此提供不完整的信息(译者注:这里应该是指那些升级之后的交易信息被抛弃了,所以信息时不完整的)。

    Bitcoin Core中包含了检测硬叉的代码,这段代码会检查区块链的工作量证明。如果未升级的结点收到区块链头部信息中可以证明至少有连续的六个块比其认为有效的最佳链更多的工作证明(译者注:就是网络上的最长链已经超过他本地的链至少6个了),则该节点在getnetworkinfoRPC结果中报告警告,并且运行-alertnotify命令(需要配置)。这警告操作者,未升级的节点不能切换到最可能的最佳块链。

    全节点也可以检查区块和交易的版本号。如果在几个最近的块中看到的区块或交易的版本号高于本节点使用的版本号,就会认为它并没有使用当前(最新)的一致性规则。Bitcoin Core通过getnetworkinfoRPC和-alertnotify命令(如果设置了)来报告这种情况。

    不管在什么情况下,交易和区块数据都不应该依赖其是否来自使用最新规则的结点还是来自使用旧规则的结点。

    SPV客户端可以通过连接到几个全结点来检测硬分叉,并确保它们都位于具有相同块高度(加上或减去几个可能由于网络延迟带来的不一致)的同一条链上。一旦检测到了不一致,客户端就可以和弱链断开连接,而去连接强的链。

    SPV客户端还应监控区块和交易版本号的增加,以确保他们使用当前最新的一致性规则处理接收到的以及创建新的事务。

    相关文章

      网友评论

        本文标题:比特币开发者指南(一)--- 区块链

        本文链接:https://www.haomeiwen.com/subject/apswdxtx.html