比特币技术栈

比特币设计原理

比特币网络是一个分布式的点对点网络,网络中的矿工通过“挖矿”来完成对交易记录的记账过程,维护网络的正常运行。

区块链网络提供一个公共可见的记账本,通过共识机制所有节点共同维护同一份账本,该记账本并非记录每个账户的余额,而是用来记录发生过的交易的历史信息。该设计可以避免重放攻击,即某个合法交易被多次重新发送造成攻击。

其交易是通过销毁“未被花费的交易输出”(即UTXO), 和创建新的UTXO来实现资金的流转;

比特币可以理解为: BTC = UTXO + 共识机制 + 区块链账本

比特币交易

比特币交易系统—状态转移系统

比特币中没有账户的概念。因此,每次发生交易,用户需要将交易记录写到比特币网络账本中,等网络确认后即可认为交易完成。

除了挖矿获得奖励的 coinbase 交易只有输出,正常情况下每个交易需要包括若干输入和输出,未经使用(引用)的交易的输出(Unspent Transaction Outputs,UTXO)可以被新的交易引用作为其合法的输入。被使用过的交易的输出(Spent Transaction Outputs,STXO),则无法被引用作为合法输入。

因此,比特币网络中一笔合法的交易,必须是引用某些已存在交易的 UTXO(必须是属于付款方才能合法引用)作为新交易的输入,并生成新的 UTXO(将属于收款方)。

那么,在交易过程中,付款方如何证明自己所引用的 UTXO 合法?比特币中通过“签名脚本”来实现,并且指定“输出脚本”来限制将来能使用新 UTXO 者只能为指定收款方。对每笔交易,付款方需要进行签名确认。并且,对每一笔交易来说,总输入不能小于总输出。总输入相比总输出多余的部分称为交易费用(Transaction Fee),为生成包含该交易区块的矿工所获得。目前规定每笔交易的交易费用不能小于 0.0001 BTC,交易费用越高,越多矿工愿意包含该交易,也就越早被放到网络中。交易费用在奖励矿工的同时,也避免了网络受到大量攻击。

交易中金额的最小单位是“聪”,即一亿分之一(10^-8)比特币。

下图展示了一些简单的示例交易。更一般情况下,交易的输入、输出可以为多方。

交易 目的 输入 输出 签名 差额
T0 A 转给 B 他人向 A 交易的输出 B 账户可以使用该交易 A 签名确认 输入减输出,为交易服务费
T1 B 转给 C T0 的输出 C 账户可以使用该交易 B 签名确认 输入减输出,为交易服务费
X 转给 Y 他人向 X 交易的输出 Y 账户可以使用该交易 X 签名确认 输入减输出,为交易服务费

需要注意,刚放进网络中的交易(深度为 0)并非是实时得到确认的。进入网络中的交易存在被推翻的可能性,一般要再生成几个新的区块后(深度大于 0)才认为该交易被确认。

下面分别介绍比特币网络中的重要概念和主要设计思路。

账户(地址)

比特币采用了非对称的加密算法,用户自己保留私钥,对自己发出的交易进行签名确认,并公开公钥。

比特币的账户地址其实就是用户公钥经过一系列 Hash(HASH160,或先进行 SHA256,然后进行 RIPEMD160)及编码运算后生成的 160 位(20 字节)的字符串。

一般地,也常常对账户地址串进行 Base58Check 编码,并添加前导字节(表明支持哪种脚本)和 4 字节校验字节,以提高可读性和准确性。

注:账户并非直接是公钥内容,而是 Hash 后的值,避免公钥过早公开后导致被破解出私钥。

UTXO基本概念

在比特币中,一比交易’’在黑盒子里” 实际运作的方式是: 花费一种东西的集合,这种东西被称为“未被花费的交易输出”(即UTXO) , 这些输出由一个或多个之前的交易所创造,并在其后制造出一比或多笔新的UTXO,可以在未来的交易中花费。每一笔UTXO他有面额、所有者。

而且,一笔交易若要有效,必须满足的两个规则是:

1)该交易必须包含一个有效的签名,来自它所花费的 UTXO 的拥有者;

2)被花费的 UTXO 的总面额必须等于或者大于该交易产生的 UTXO 的总面额。一个用户的余额因此并不是作为一个数字储存起来的;而是用他占有的 UTXO 的总和计算出来的。

如果一个用户想要发送一笔交易,发送 X 个币到一个特定的地址,有时候,他们拥有的 UTXO 的一些子集组合起来面值恰好是 X,在这种情况下,他们可以创造一个交易:花费他们的 UTXO 并创造出一笔新的、价值 X 的 UTXO ,由目标地址占有。当这种完美的配对不可能的时候,用户就必须打包其和值 大于 X 的 UTXO 输入集合,并添加一笔拥有第二个目标地址的 UTXO ,称为“零钱输出”,分配剩下的币到一个由他们自己控制的地址。

UTXO具有如下性质

  • UTXO, 用比特币拥有者的公钥(锁定)(加密)的一个数字
  • UTXO == 比特币
  • 比特币系统里没有比特币, 只有UTXO
  • 比特币系统中没有账户,只有UTXO(公钥锁定)
  • 比特币系统里没有账户余额, 只有UTXO( 账户余额只是比特币钱包的概念 )
  • UTXO存在前节点的数据库里
  • 转账将消耗掉属于你自己的UTXO, 同时生成新的UTXO, 并用接受者的公钥锁定。

交易的原理

一笔交易包含的信息
  • 交易的输入的交易 ID(UTXO)

  • 交易的金额: 多少钱,和输入的差额为交易的服务费

  • 时间戳: 交易合适能生效

  • 锁定脚本(用接受者的公钥哈希)- 将比特币地址锁定到接收者

  • 解锁脚本(发送者用私钥对交易的数字签名, 发送者的公钥)- 用来证明比特币确实属于发送者,并保证内容不被篡改

交易的生成和验证过程

1547459880076

1)钱包软件生成交易,并想临近节点传播

2)节点对收到的交易进行验证,并丢弃不合法的交易

  • 交易是否已经处理过

  • 交易的size要小于区块size的上限 (比如比特币之前的大小限制是1M )

  • 交易的输入UTXO是存在的

  • 交易输入UTXO没有被其他交易引用-防止双花(Double Spending)

  • 输入总金额 > 输出的总金额

  • 解锁脚本的验证

  • 将合格的交易加入到本地的Transaction数据库中,并将合法的交易转给临近节点

3)旷工将合格的交易打包进区块

交易脚本

脚本系统

即便没有任何扩展,比特币的协议实际上却是促进了一个弱化版的”智能合约”的概念。。UTXO 在比特币中不是只被一个公钥持有, 而是还被在一个基于堆栈的程序语言组成的复杂的脚本所持有着。 在这个范例中,一个交易消耗的 UTXO 必须提供满足脚本的数据。实际上,这最基本的公钥所有权机制也是通过一个脚本来实现的:这个脚本使用一个椭圆曲线签名作为一个输入,验证拥有这个 UTXO 的交易和地址,如果验证成功,则返回 1,不然则返回 0。其他,更加复杂的脚本存在于各种复杂的用例中。 例如,你可以构造一个脚本,它要求从给定的三个私钥中,至少要选其中的 2 个来做签名验证(“多重签名”),这个对公司账本,储蓄账户等来说非常有用。脚本也能用来对解决计算问题的用户支付报酬。人们甚至可以创建这样的脚本“如果你能够提供你已经发送一定数额的的狗币给我的简化确认支付证明,这一比特币就是你的了”,本质上,比特币系统允许不同的密码学货币进行去中心化的兑换。
然而,在比特币中的脚本语言有几个重要的限制:

  • 缺乏图灵-完备
    • 那就是说,虽然比特币脚本语言支持的计算方式很多,但是它不是所有的都支持。在主要类别中缺失循环。 它这样做的目的是为了防止对交易的验证出现死循环;理论上,它的脚本是可以克服这个障碍的,因为任何的循环都可以通过 if 语句重复多次底层代码来模拟,但是这样的脚本运行效率非常低下。
  • 值的盲区
    • 一个 UTXO 脚本没有办法提供资金的颗粒度可控的出金操作。比如, 一个预言合约(oracle contract )的其中一个强大的用例就是一个套期保值的合约,A 和 B 都把价值1000$的 BTC 放到合约中,30 天后,这个合约把价值 1000$的 BTC 发给了 A,剩下的发给了B。 这就需要合约要确定 1BTC 以美元计值多少钱。然而,因为 UTXO 是不可分割的,为实现此合约,唯一的方法是非常低效地采用许多有不同面值的 UTXO(例如有 2^k 的 UTXO,其中 K可以最大到 30)并使预言合约挑出正确的 UTXO 发送给 A 和 B。
  • 状态缺失
    • UTXO 要么被使用了,要么没有被使用;这会使得多阶段的合约和脚本没有机会保持任何其他的内部状态。这使得制作多阶段的期权合约、去中心化的交换协议或两阶段加密承诺协议变得困难(对于安全计算奖金来说是必要的)。这也意味着,UTXO 只能用于构建简单的、一次性的合约,而不是更复杂的“有状态”的合约,比如去中心化的组织,并且使得元协议难以实现。
  • 区块链盲区
    • UTXO 对某些区块链数据视而不见,比如随机数和之前的区块的哈希。这严重限制了博彩和其他一些类别的应用,因为它剥夺了一种潜在的有价值的脚本语言:随机数!也就是在比特币的脚本中是没有随机数的。

因此,我们看到了在加密货币之上构建高级应用程序的三种方法:一,构建一个新的区块链,二,在比特币之上使用脚本,三,在比特币之上构建一个元协议。 构建一个新的区块链可以无限制扩展功能集,但是这样做非常消耗时间。使用脚本很容易实现和标准化,但在其功能上非常有限,而元协议虽然容易,但在可伸缩性方面却存在缺陷。在以太坊中,我们打算建立一个替代性的框架,它提供了更大的开发和更强大的轻客户属性,同时允许应用程序共享一个经济环境和区块链安全。

比特币的锁定脚本和解锁脚本

脚本(Script)是保障交易完成(主要用于检验交易是否合法)的核心机制,当所依附的交易发生时被触发。通过脚本机制而非写死交易过程,比特币网络实现了一定的可扩展性。比特币脚本语言是一种非图灵完备的语言。

一般每个交易都会包括两个脚本:负责输入的解锁脚本(scriptSig)和负责输出的锁定脚本(scriptPubKey)。

输出脚本一般由付款方对交易设置锁定,用来对能动用这笔交易的输出(例如,要花费该交易的输出)的对象(收款方)进行权限控制,例如限制必须是某个公钥的拥有者才能花费这笔交易。

认领脚本则用来证明自己可以满足交易输出脚本的锁定条件,即对某个交易的输出(比特币)的拥有权。

输出脚本目前支持两种类型:

  • P2PKH:Pay-To-Public-Key-Hash,允许用户将比特币发送到一个或多个典型的比特币地址上(证明拥有该公钥),前导字节一般为 0x00;
  • P2SH:Pay-To-Script-Hash,支付者创建一个输出脚本,里边包含另一个脚本(认领脚本)的哈希,一般用于需要多人签名的场景,前导字节一般为 0x05;

以 P2PKH 为例,输出脚本的格式为

1
scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

其中,OP_DUP 是复制栈顶元素;OP_HASH160 是计算 hash 值;OP_EQUALVERIFY 判断栈顶两元素是否相等;OP_CHECKSIG 判断签名是否合法。这条指令实际上保证了只有 pubKey 的拥有者才能合法引用这个输出。

另外一个交易如果要花费这个输出,在引用这个输出的时候,需要提供认领(输入)脚本格式为

1
scriptSig: <sig> <pubKey>

其中, 是拿 pubKey 对应的私钥对交易(全部交易的输出、输入和脚本)Hash 值进行签名,pubKey 的 Hash 值需要等于 pubKeyHash。

进行交易验证时,会按照先 scriptSig 后 scriptPubKey 的顺序进行依次入栈处理,即完整指令为:

1
<sig> <pubKey> OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

读者可以按照栈的过程来进行推算,理解整个脚本的验证过程。

引入脚本机制带来了灵活性,但也引入了更多的安全风险。比特币脚本支持的指令集十分简单,基于栈的处理方式,并且非图灵完备,此外还添加了额外的一些限制(大小限制等)。

比特币脚本语言-基于栈的脚本语言
  • 栈(stack)- 操作数据的一种结构

    • 只能从一端操作数据,后进先出LIFO
    • 如同子弹匣, 先压如的子弹最后打出
    • 压栈(PUSH), 出栈(POP)
  • 基于栈的脚本语言

    • 对栈的操作: OP_DUP
    • 逻辑运算符: OP_EQUALIVERIFY
    • 加密运算符: OP_HASH160, OP_CHECKSIG
    • 算数运算符: OP_ADD, OP_SUB, OP_MUL, OP_DIV
  • 交易验证-锁定脚本和解锁脚本

    • 锁定脚本
      • OP_DUP OP_HASH160 <发送者的公钥哈希> OP_EQUALVERIFY OP_CHECKSIG
    • 解锁脚本
      • <发送者的签名> <发送者的公钥>
    • 交易验证
      • 运行解锁脚本 + 锁定脚本 => True

    1547461481461

比特币区块

区块的基本信息

比特币一个区块大小不能超过1MB, 主要包括以下内容:

  • 区块大小:4 字节;
  • 区块头:80 字节:
  • 交易个数计数器:1~9 字节;
  • 所有交易的具体内容,可变长,匹配 Merkle 树叶子节点顺序。

区块头包含信息

  • 版本号:4 字节;
  • 上一个区块头的 Hash 值:链接到上一个合法的块上,对其区块头进行两次 SHA256 操作,32 字节;
  • 本区块所包含的所有交易的 Merkle 树根的哈希值:两次 SHA256 操作,32 字节;
  • 时间戳:4 字节;
  • 难度指标:4 字节;
  • Nonce:4 字节,PoW 问题的答案。

可见,要对区块链的完整性进行检查,只需要检验各个区块头部信息即可,无需获取到具体的交易内容,这也是简单交易验证(Simple Payment Verification,SPV)的基本原理。另外,通过头部的链接,提供时序关系的同时加大了对区块中数据进行篡改的难度。

区块的生成

  1. 旷工在挖矿前要组件区块
    • 将coinbase交易打包进区块
    • 将交易池中高优先级的交易打包进去快
      • 优先级 = 交易的额度 * UTXO的深度 / 交易的size
    • 创建去开的头部
      • 1547523455135
  2. 挖矿成功后,将计算出来的随机数nonce填入区块头部, 并向临近节点传播

区块的验证

p2p节点接受到新区块后,立即做以下的检查

  • 验证POW的nonce值是否符合难度值
  • 检查时间戳是否小于当前时间2小时
  • 检查Merkle树根是否正确
  • 检查区块size要小于区块的size上限
  • 第一笔交易必须是coinbase交易
  • 验证每个交易

默克尔树

89 1548214790711

在默克尔树中只要提供少数的介个节点就可以给出 一个分支的有效性证明,比如验证12c5是否有效,只需要提供标记为蓝色的几点就可以证明12c5这个交易是否有效

1548223225047

试图改变默克尔树的任意一部分都会导致链条上在某处放生不一致的情况

比特币的一个重要特性,即区块是存在一个多级数据结构中的 。一个区块的“哈希值”实际上只是这个区块的头信息的哈希值,一个大约 200 个字节的数据,其中包含了时间戳,随机数,上一个区块的哈希和一个存储了这个区块中所有交易的称之为默克尔树的数据结构的根哈希。 默克尔树是一种二叉树,包含了一组节点,它们的含有基础信息的树根有大量的叶子节点,一组中间节点,每一个节点都是它的 2 个子节点的哈希,然后,最终的一个根节点,也是由它的 2 个子节点的哈希形成,代表着这树的“顶端”。 这个默克尔树的目的是允许在一个区块中的数据能够被零散的传递: 一个节点只能从一个源来下载一个区块的头信息,树的一小部分关联着另一个源 ,并且任然可以保证所有的数据都是正确的。之所以这样做行得通,是因为哈希值都是向上传导的: 如果一个恶意的用户试图在默克尔树的底部替换一个假的交易, 这个更改将导致上面的节点发生变化,然后上面的节点的变化又会导致上上面的节点发生变化,最终改变这个数根节点,因此也改变了这区块的哈希,导致这个协议把它注册成一个完全不同的区块 (几乎可以肯定是一个无效的工作证明).这默克尔树协议对比特币的长期可持续发展是必不可少的。比特币网络中的一个“完整节点” , 截止到 2014 年,占用了大约 15G 的磁盘空间,并且每月正在以 10 亿字节的速度递增。目前,这对于电脑来说是没有问题的,但是在手机上却是不现实的。在以后的将来,只有商业的和业余爱好者才能参与玩比特币。一个称之为 “简化支付验证(simplified payment verification)” (SPV)的协议 允许另一种类型的节点存在,这种节点称之为 “轻节点(light nodes)”, 其下载区块的头信息,在这区块头信息上验证工作证明,然后只下载与之交易相关的“分支” 。 这使得轻节点只要下载整个区块链的一小部分,就可以安全地确定任何一笔比特币交易的状态和账户的当前余额。

挖矿

挖矿的基本原理

了解比特币,最应该知道的一个概念就是“挖矿”。挖矿是参与维护比特币网络的节点,通过协助生成新区块来获取一定量新增的比特币的过程。

当用户向比特币网络中发布交易后,需要有人将交易进行确认,形成新的区块,串联到区块链中。在一个互相不信任的分布式系统中,该由谁来完成这件事情呢?比特币网络采用了“挖矿”的方式来解决这个问题。

目前,每 10 分钟左右生成一个不超过 1 MB 大小的区块(记录了这 10 分钟内发生的验证过的交易内容),串联到最长的链尾部,每个区块的成功提交者可以得到系统 12.5 个比特币的奖励(该奖励作为区块内的第一个交易,一定区块数后才能使用),以及用户附加到交易上的支付服务费用。即便没有任何用户交易,矿工也可以自行产生合法的区块并获得奖励。

每个区块的奖励最初是 50 个比特币,每隔 21 万个区块自动减半,即 4 年时间,最终比特币总量稳定在 2100 万个。因此,比特币是一种通缩的货币。

挖矿的过程

1548213468513

如果我们有一个可信任的中央服务器, 那么实现这个系统是一件很简单的事情; 就按照需求所描述的去编写代码即可,把状态记录在中央服务器的硬盘上。 然而,与比特币一样,我们试图去建立一个去中心化的货币系统, 所以,我们需要把状态转移系统和一致性系统结合起来,以确保每个人都同意这交易的顺序。

比特币的去中心化的一致性处理进程要求网络中的节点连续不断的去尝试对交易进行打包,这些被打成的包就称为“区块”。 这个网络会故意的每隔 10 分钟左右就创建一个区块, 每一个区块里都包含一个时间戳,一个随机数,一个对上一个区块的引用 ,和从上一个区块开始的所有交易的列表。随着时间的推移,这会创建一个持久的,不断增长的区块链,这个区块链不断的被更新,使其始终代表着最新的比特币总账的状态。

验证一个区块是否有效的算法如下:

  1. 检查其引用的上一个区块是否存在并且有效.
  2. 检查这个区块的时间戳是否大于上一个区块的时间戳 并且小于 2 小时之内
  3. 检查这区块上的工作证明是否有效.
  4. 让 S[0] 成为上一个区块的最末端的状态.
  5. 假设 TX 是这个区块的交易列表,且有 n 个交易。 做 for 循环,把 i 从 0 加到到 n-1, 设
    置 S[i+1] = APPLY(S[i],TX[i]) 如果任何一个应用(APPLY)返回错误,则退出并且返回。
  6. 返回 true,并且把 S[n] 设置成这个区块最末端的状态。

从本质上说,区块中的每一个交易都必须提供一个有效的状态,从交易执行前的标准状态到执行后的一个新的状态。 注意,状态并没有以任何方式编码进区块中;它纯粹是一个被验证节点所记住的抽象,并且它只能用来被从创世区块起的每一个区块进行安全的计算,然后按照顺序的应用在每一个区块中的每一次交易中。此外,请注意矿工把交易打包进区块的顺序是很重要的; 如果一个区块中有 2 个交易 A 和 B,B 花了一个由 A 创建的 UTXO, 那么如果 A 比 B 更早的进入区块,那么这个区块将是有效的,不然就是无效的。

在上述列出的验证条件中,“工作证明” 这一明确的条件就是每一个区块的 2 次 SHA256 哈希值, 它作为一个 256 位的数字,必须小于一个动态调整的目标值, 截止到本文写作的时间,该动态调整的值的大小大约是 2 的 187 次方。这样做的目的是为了让创建区块的算法变难, 从而,阻止幽灵攻击者从对它们有利的角度出来,来对区块链进行整个的改造。因为 SHA256 被设计成一个完全不可预测的伪随机函数, 这创建一个有效区块的唯一的方法只有是不断的尝试和出错, 不断对随机数进行递增,然后查看新的哈希值是否匹配。

按照当前的目标值 2 的 187 次方,这个网络在找到一个有效的区块前,必须进行 2 的 69 次方次的尝试; 一般来说,每隔 2016 个区块,这个目标值就会被网络调整一次 ,因此网络中平均每隔 10 分钟就会有一些节点产生出一个新的区块。为了补偿这些矿工的计算工作, 每一个区块的矿工有权要求包含一笔发给他们自己的 12.5BTC(不知道从哪来的)的交易。另外,如果任何交易,它的总的输入的面值比总的输出要高,这一差额会作为“交易费用”转给矿工。顺便提一下,对矿工的奖励是比特币发行的唯一途径,创世状态中并没有比特币。

负反馈调解

比特币网络在设计上,很好的体现了负反馈的控制论基本原理。

比特币网络中矿工越多,系统就越稳定,比特币价值就越高,但挖到矿的概率会降低。

反之,网络中矿工减少,会让系统更容易导致被攻击,比特币价值越低,但挖到矿的概率会提高。

因此,比特币的价格理论上应该稳定在一个合适的值(网络稳定性也会稳定在相应的值),这个价格乘以挖到矿的概率,恰好达到矿工的收益预期。

从长远角度看,硬件成本是下降的,但每个区块的比特币奖励每隔 4 年减半,最终将在 2140 年达到 2100 万枚,之后将完全依靠交易的服务费来鼓励矿工对网络的维护。

注:比特币最小单位是“聪”,即 10^(-8) 比特币,总“聪”数为 2.1E15。对于 64 位处理器来说,高精度浮点计数的限制导致单个数值不能超过 2^53 约等于 9E15。

共识机制

共识机制介绍

比特币网络是完全公开的,任何人都可以匿名接入,因此共识协议的稳定性和防攻击性十分关键。

比特币区块链采用了 Proof of Work(PoW)的机制来实现共识,该机制最早于 1998 年在 B-money 设计中提出。

目前,Proof of X 系列中比较出名的一致性协议包括 PoW、PoS 和 DPoS 等,都是通过经济惩罚来限制恶意参与。

工作量证明

工作量证明,通过计算来猜测一个数值(nonce),使得拼凑上交易数据后内容的 Hash 值满足规定的上限(来源于 hashcash)。由于 Hash 难题在目前计算模型下需要大量的计算,这就保证在一段时间内,系统中只能出现少数合法提案。反过来,能够提出合法提案,也证明提案者确实已经付出了一定的工作量。

同时,这些少量的合法提案会在网络中进行广播,收到的用户进行验证后,会基于用户认为的最长链基础上继续难题的计算。因此,系统中可能出现链的分叉(Fork),但最终会有一条链成为最长的链。

Hash 问题具有不可逆的特点,因此,目前除了暴力计算外,还没有有效的算法进行解决。反之,如果获得符合要求的 nonce,则说明在概率上是付出了对应的算力。谁的算力多,谁最先解决问题的概率就越大。当掌握超过全网一半算力时,从概率上就能控制网络中链的走向。这也是所谓 51% 攻击的由来。

参与 PoW 计算比赛的人,将付出不小的经济成本(硬件、电力、维护等)。当没有最终成为首个算出合法 nonce 值的“幸运儿”时,这些成本都将被沉没掉。这也保障了,如果有人尝试恶意破坏,需要付出大量的经济成本。也有设计试图将后算出结果者的算力按照一定比例折合进下一轮比赛考虑。

权益证明

权益证明(Proof of Stake,PoS),最早在 2013 年被提出,类似现实生活中的股东机制,拥有股份越多的人越容易获取记账权(同时越倾向于维护网络的正常工作)。

典型的过程是通过保证金(代币、资产、名声等具备价值属性的物品即可)来对赌一个合法的块成为新的区块,收益为抵押资本的利息和交易服务费。提供证明的保证金(例如通过转账货币记录)越多,则获得记账权的概率就越大。合法记账者可以获得收益。

PoS 试图解决在 PoW 中大量资源被浪费的缺点,受到了广泛关注。恶意参与者将存在保证金被罚没的风险,即损失经济利益。

一般的,对于 PoS 来说,需要掌握超过全网 1/3 的资源,才有可能左右最终的结果。这个也很容易理解,三个人投票,前两人分别支持一方,这时候,第三方的投票将决定最终结果。

PoS 也有一些改进的算法,包括授权股权证明机制(DPoS),即股东们投票选出一个董事会,董事会中成员才有权进行代理记账。这些算法在实践中得到了不错的验证,但是并没有理论上的证明。

2017 年 8 月,来自爱丁堡大学和康涅狄格大学的 Aggelos Kiayias 等学者在论文《Ouroboros: A Provably Secure Proof-of-Stake Blockchain Protocol》中提出了 Ouroboros 区块链共识协议,该协议可以达到诚实行为的近似纳什均衡,认为是首个可证实安全的 PoS 协议。

隔离见证

什么是隔离见证

隔离见证,即 Segregated Witness(简称SegWit),由Pieter Wuille(比特币核心开发人员、Blockstream联合创始人)在2015年12月首次提出。

见证(Witness)

见证,在比特币里指的是对交易合法性的验证。举个例子,Alice发起一笔交易,给Bob支付1个BTC,该笔交易信息由三部分组成:

a.元数据:交易信息格式的版本号;交易锁定时间等

b.付款人:Alice用于付款的BTC来源,一般来源于某历史区块上某笔交易的输出(详 见UTXO);证明Alice拥有该笔交易的输出,即见证(Witness)数据

c.收款人:Bob的收款地址和金额

可见,见证数据包含在交易信息里头。

隔离(Segregated)

指的就是把见证数据从交易信息里抽离出来,单独存放。

隔离见证的来源

为什么要把见证数据隔离出来呢,或者说这样做有什么好处呢?这就涉及到比特币里的另一个概念–扩容。

扩容,指的是增加比特币每秒的交易量。比特币每10分钟左右挖出一个大小小于1MB的区块,每笔交易平均250字节,即每个区块最多放进4000笔交易,这样算下来,比特币每秒处理的交易数不超过7个。对比其它交易平台,PayPal每秒数百笔、Visa每秒数千笔、支付宝能达到每秒数万笔,可见比特币是一个非常低效的交易系统。如果使用人数增多,则会造成比特币的拥堵。

如何解决拥堵呢?

有两种方式,一是简单的增加每个区块的大小,比如将区块大小增加到8M;另一种就是隔离见证+闪电网络啦。

扩容方案一: 增加区块大小

如果将区块大小增至8M,简单思考一下,比特币每秒处理的交易数似乎也增加到原来的8倍,即56笔每秒。如果每个区块1个GB,比特币每秒将处理7000笔交易,拥堵问题不就解决了吗?

中本聪可没那么傻,之所以将区块大小设定为1M,是有重要原因的。比特币白皮书的标题为:一种点对点的电子现金系统,相比于传统货币系统,比特币的核心价值在于实现了一种去中心而且安全的货币。如果区块的大小过大,则会危害到比特币的安全模型,作为一种货币应用,这显然是不能令人接受的。

为什么这么说呢?

POW机制的安全基础,是假设一个人的算力无法超过全网算力的50%。如果增大区块,可能一个人的算力超过全网的1/3,就危害到了比特币的安全。举个例子,为了达到每秒7000笔的交易速度,我们把区块的大小增加到1GB:

a.假设1GB的区块从产生到广播到全网节点需要10分钟;

b.有一个叫Byzantium的节点,拥有的算力超过全网1/3;

c.当Byzantium节点挖出一个新区块时,假设该时间点为0秒,那么Byzantium节点 获取新区块的时间点为0秒;根据假设a,全网最后一个获取新区块的节点的获取时间 为600秒,如果获取速度是线性的,全网其它节点获取新区块的平均时间是300秒。

d.因为在新区块上挖坑的算力才是有效算力;根据c,全网其它节点的有效算力只剩下 一半,也就是说,全网其它节点的有效算力小于1/3

e.根据b和d,这种情况下,Byzantium节点算力超过全网其它节点算力,如果Byzantium 节点在自己挖出的区块上继续挖矿且不公布广播,则Byzantium节点上没公布的区块 长度,会大于全网区块长度;一旦Byzantium节点公布这些区块,则全网其它节点挖 出的区块全部作废。

可见,区块设计过大,会威胁到比特币的安全。换句话说,比特币区块的大小是有上限的,《On Scaling Decentralized Blockchain》这篇论文指出,在目前的互联网环境下,如果十分钟产生一个区块,区块的大小最好不能超过4MB。这样看来,增加区块大小这种扩容方案,效果就十分有限了。

扩容方案二: 隔离见证 + 闪电网络

隔离见证为什么能扩容呢?先来看看比特币区块的数据结构:

1547540363708

每笔交易平均250字节,见证部分的数据约为150字节,其余部分100字节。如果将见证数据隔离出来,原来1MB空间的区块可以放下10000笔交易(原来为4000笔),交易速度约提升2.5倍。隔离出来的见证数据放到了区块末尾,大小为1.5到2MB,所以隔离见证的整个区块大小为2.5到3MB左右。

隔离见证的意义:

  1. 解决了交易延展性问题;
  2. 为闪电网络铺路
  3. 其他优化

交易延展性

中本聪在设计比特币的时候直接把这两个信息直接放在了区块内,所以一个区块就承载不了更多的交易信息,如果隔离了“见证信息”,那么区块链只记录交易信息,那么一个区块可承载的交易更多交易。
中本聪设计比特币时,并没有把两部分资料分开处理,因此导致交易ID的计算混合了交易和见证。因为见证本身包括签名,而签名不可能对其自身进行签名,因此见证可以由任何人在未得到交易双方同意的情况下进行改变,造成所谓的交易可塑性(malleability)。在交易发出后、确认前,交易ID可以被任意更改,因此基于未确认交易的交易是绝对不安全的。在2014年就曾有人利用这个漏洞大规模攻击比特币网络。

指的是一笔交易发起后,交易数据中的见证部分可以被篡改,而且篡改后的交易仍然有效。具体的说,见证的实现依靠一种签名算法,比如椭圆曲线数字签名算法(ECDSA),这种算法下签名(r,s)和签名(r,-s(mod n))都是有效的,所以可以把一种有效见证数据篡改成另一种有效见证数据,该笔交易仍然是有效的。每笔交易有个交易ID,交易ID是对整个交易数据的Hash值,为该笔交易的唯一标识。通过对见证数据的篡改,可以改变Hash值,从而改变该笔交易的唯一标识。隔离见证通过把见证数据隔离移出,生成交易ID时Hash的数据不包括见证数据,因此也就无法改变交易ID值。

从此以后,只有发出交易的人才可以改变交易ID,没有任何第三方可以做到。如果是多重签名交易,就只有多名签署人同意才能改变交易ID。这可以保证一连串的未确认交易的有效性,是双向支付通道或闪电网络所必须的功能。有了双向支付通道或闪电网络,二人或多人之间就可以实际上进行无限次交易,而无需把大量零碎交易放在区块链,大为减低区块空间压力。

闪电网络

通过增加区块大小无法从根本上解决比特币的扩容问题。闪电网络通过在比特币基础上,构建第二层网络,将交易转移到链下的方式,来减轻公链负担,以实现扩容的效果。目前看来,在公链基础上构建协议层网络,是解决公链拥堵问题最合适也是最有前景的方案

隔离见证所带来的改变,为闪电网络的实现提供了一些便利,主要有3点:

a.交易延展性的解决,让交易无法被干扰,闪电网络白皮书中提到的“人质状态” (hostage situation),得以避免;

b.在通道的生命周期上,隔离见证让闪电网络的通道永久开启更方便实现;

c.虽然从理论上系统是安全的,但用户还是要查看区块链中的交易是否广播撤回,防止交易方的欺诈行为,隔离见证使得这项活动可以外包出去,只要给服务器传送少量信息, 就能代替你完成这一过程。

d.此外,隔离见证给比特币带来了一些细节优化,比如增加了脚本版本(Script Version),使得脚本语言可以以一种向后兼容的方式来发展;签名算法复杂度有了较大优化等等。

比特币的缺陷

比特币的缺陷

  • 交易确认时间长,吞吐量低
  • POW挖矿浪费计算资源
  • ASIC矿机出现是全民参与性降低,算力集中
  • 不完全匿名
  • 无法存储太多的数字资产
  • 不支持复杂的脚本语言

缩短交易时间的方法

  • 缩短平均产生区块的时间
  • 中心化服务
  • 信任地址多重签名
  • 开放交易和联合服务器
  • POS和DPOS
  • Segwit与闪电网络
刘小恺(Kyle) wechat
如有疑问可联系博主