第三章 比特币的实现机制

比特币交易

传统的交易账本大都类似于下图的形式,每一笔交易信息记录了支付者和接收者的信息。
第三章 比特币的实现机制_第1张图片
但是,这种方式有一个问题:我们如何确定每一笔交易都是有效的。假设某笔交易的发起者Alice的资金不足以支付,我们应该如何检查?最直接的方式是回溯交易记录,找到所有与Alice有关的记录,计算并验证Alice的支付信息即可。但是这种方式的开销太大了。

实际上,比特币的账本不是基于上述记账的类型的。交易会记录下一组输入和输出。我们可以把输入看做将要消费的比特币(上一个区块产生的比特币);把输出看成将要生成的比特币。对于新建立的区块来说,没有需要进行消费的比特币。每一笔交易都有一个唯一的标识。输出的后缀从0开始索引,因此第一个输出应该是output[0]。下图的方式就很类似比特币的交易方式。
第三章 比特币的实现机制_第2张图片

在上图中,“交易1”没有输入,因为这是新建立的区块,新建立的区块产生25个比特币,比企鹅这25个比特币归区块创立者Alice所有,并且这笔交易不需要签名。Alice想要给Bob支付17个比特币,那么她需要建立“交易2”,。Alice需要显式指定前一笔交易的比特币的来源。这里,她制定了output[0]作为“交易1”的输入(也是“交易1”唯一的输入来源),这也是ALice获得了25比特币的那个。她也必须指定交易的输出地址,在本例中,她给了Bob地址17个比特币,给了自己地址8个比特币。当然,Alice对整个交易进行了签名。

Change Address。在比特币系统中,整个交易的输出必须是一个新的交易的输入,正如我们之前提到的那样;要么就是整个交易 没有任何输出,即不生成比特币。Alice给Bob17个比特币,但是她拥有一笔价值25比特币的输出。因此她需要创建一个新的输出,把其余的比特币发给自己。这个25个比特币可能是其他地址拥有的25个比特币,但是Alice会拥有这25个比特币。可以这么理解这句话:假设Alice发给Bob17个币之前,有一笔与Alice无关的交易,同样有25个比特币作为输出,那么ALice可以用这个交易的25个比特币作为自己的,并继续执行支付Bob的操作。这种方式称为”Change Address“。

Efficient cerification。哈希指针给我们提供了一个可以高效验证交易是否有效的方案。因为我们只需要根据上一个区块的哈希值,就可以计算出上个区块是否包含25个比特,从而验证本区块的交易的有效性;不再像传统的方式那样,需要从第一区块逐一检测。因此这种方式极大地提高了验证效率。

Consolidating funs,合并资产。一笔交易可能有多个输入和多个输出,那么分割或合并这些价值会变得很容易。假设Bob收到了两笔来,自不同交易的比特币,一个有17个BTC、另一个有2BTC。他只需要重新创建一笔交易,把这两笔交易作为输入,把输出地址写成自己想要的地址即可。

Joint payments。假设Bob和Carlo都要给David支付比特币。它们可以创建一个有两个输入和一个输出的交易,这两笔交易仅需要两个人的签名即可。

Transaction syntax。一笔交易的数据如下所示:
第三章 比特币的实现机制_第3张图片

结构说明:

  • Metadata (元数据)。包含了整个区块的哈希值、交易的尺寸、输入和输出的数量。其中交易的哈希值是真个交易的唯一身份标识,这就是哈希指针的内容。
  • Inputs (输入)。交易的输入是一个数组,每个输出有相同的结构。一个交易指明了前一笔交易,因此它包含了前一个交易的哈希值,也就是我们所说的哈希指针。信息中也包括了前一笔交易输出的索引。之后,这里是一个签名。记住,我们必须签名,用以表示我们用能力来声明这是前一笔交易的输出。
  • Outputs(输出)。输出也是个数组。输出仅有两个域,它们都有一个值。输出的值小于等于输入的值。如果输出值小于输入值,说明差值作为了交易费。第二个是一个比特币脚本。

比特币脚本

实际上,每一个交易的输出不是单独的一个公钥,而是一个脚本。那么,我们需要明白的是:什么是脚本、为什么使用脚本。

比特币交易中最常见的一种交易类型:验证前一笔交易的的输出使用了正确的key。也就是说前一笔交易必须有人签名认证。但是,地址是公钥的哈希值,根据哈希计算的原理,我们不能根据哈希值来推算出公钥实际值,因此也就无法检查签名了。因此比特币脚本就是为了解决上述的签名认证问题。
最常见的哈希输出脚本类型:
第三章 比特币的实现机制_第4张图片

输入的数据也是包含的脚本,而不是仅仅一个签名。为了验证一笔交易的正确性,我们把新的交易输入脚本和之前的输出脚本联合到一起,合并后的脚本必须能正确运行,这样才能保证交易是合法的。这两个脚本分别是”scriptPubKey”和”scriptSig”

比特币脚本语言:一种基于栈的语言,仅支持顺序执行,不支持递归、循环操作。一个简单的例子:
第三章 比特币的实现机制_第5张图片
图中,我们通过把输出交易的”scriptPublicKey”追加到”scriptSig”上,来创建一个联合脚本。脚本执行只有成功和不成功。成功表示通过验证。一下给出一些常用的符号说明:
第三章 比特币的实现机制_第6张图片

脚本的执行
第三章 比特币的实现机制_第7张图片
基本的执行顺序如上图所示,仅需要在最后检查计算的哈希值是否相等即可。

、、、、、、、、、、、、、、、、、、、、、、
还有其他内容暂时不理解,后期添加
、、、、、、、、、、、、、、、、、、、、、、

比特币脚本的应用

托管交易。 假设下面一个场景,Alice想要去Bob的网站购物。Alice想货到付款,Bob想款到付货,那么就要用托管交易来完成这个看似矛盾的过程,引入第三方进行托管。假设有第三方Judy,那么需要使用MULTISIG来完成这个交易。三个人中,只要有两个人对交易进行签名,那么交易就是有效的。假设ALice和Bob都是诚实的,那么Bob会给Alice发货,Alice收到Bob的货物后,会进行签收。假设出现了争端,比如Alice不满意货物,货物运输过程中丢失了,或者Bob不想让Alice退货等,那么Alice和Bob只会有一个人同意。这时候,需要让Judy来裁决到底把钱支付给Alice还是Bob。因此,托管方只有当Alice和Bob出现纠纷的时候才使用。

Green Address。假设Alice向Bob支付的时候,Bob一直不在线。或者Alice订一份外卖之类的,因为区块链为了防止双重支付的攻击,要进行6个区块的价格才能进行确认,这要花费1个小时,对于外卖来说,这是不太现实的。在这里,我们需要引入“银行”的概念。这种类型的支付不通过区块链进行,而是Alice向“银行”支付一定数额的比特币,然后银行把相应的比特币给Bob,银行保证这里没有双重支付攻击。注意,在这里的银行系统的保证就不是比特币系统的保证了,而是现实世界中的一种信任保证。为了系统能正常运作,Bob也需要信任银行。系统的之中地址称为“Green Address。引入这种机制是为了快速支付,但是使用的不是特别多,因为这种方式使人们必须信任银行!

Efficient micro-payments。高效的小型支付。假设Alice使用了Bob的网络服务,而且是计时收费的,就像我们打电话需要移动公司提供信号一样。我们需要根据时间进行计费。计费方式存在一种问题:假设Alice每一分钟就生成一笔账单,而且账单一直累加;如果创造了太多笔交易,那么交易费会增多,这样对Alice不利。

如果我们能够把每一分钟的小账单组合成一个大账单,可以节约很大一笔交易费。我们建立一个MULTISIG交易,这笔账单需要Alice和Bob共同签名,以获得相应数目的比特币。这样,每一分钟,Alice就签署一笔交易,给Bob应有的支付,其余的发给自己。注意,这些交易仅仅与Alice签名,Bob未签名,它们不会被发送到区块链上。当Alice使用完Bob的服务后,向Bob发出停止提供服务的请求,并且Alice停止签署账单。之后,Bob停止服务,并且他要收取相应的费用,同时把剩余的比特币给Alice。但是,上面的那些交易不会被系统所接受,因为只有Alice自己进行了签名,而Bob没有签名。

但是这种方式有很多大量的潜在双重支付,它不像green address那样对双重支付有很强的防范性。实际上,Bob可以仅签署最后一个交易,这样就不会有任何双重支付的潜在企图了。

但是,上面那种方式有一个缺陷,如果Bob永远不签署最后一个交易呢???那么这笔交易会被一直托管,而且Alice无法得到她应得的剩余的比特币。,为了解决这个问题,引入Lock Time机制。

Lock Time。为了防止Bob不签署的行为,在开始支付协议之前,Alice和Bob先签署一个协议,该协议规定了Alice会得到她所有支付的比特币,但是该协议必须要在一个规定的时间t后才有效。如果在t之前,Bob签署了最后一笔交易,那么交易会按照正常顺序进行,而且该协议会失效,否则就执行该协议,Alice会得到所有的比特币。

智能合约。上述的所有的类型的协议都可以看做智能合约。上面所有的执行方式都是由比特币系统自动执行的,而不是由法律或者法庭等的执行。如果比特币脚本语言可以有其他更多的功能,可以执行更多的合约等,这些都在探索中。

比特币块

实际的区块链不是以实际交易数目作为区块数量的,这样会大幅度降低系统接受交易的速率。区块链把大量的交易放到一个区块上,这样可以大幅提高速率。
如下图所示,区块链有两部分以哈希为基础的数据结构。第一是区块头,区块头的一个哈希指针指向前一个区块,另一个指向某一个交易的信息,这是一个Merkle树,有关操作的复杂度是对数级别的。
第三章 比特币的实现机制_第8张图片

一个区块头包括一个mining puzzle,包含一个矿工可以更改的nonce,一个时间戳,一个bits(用于表示找到该区块的难度)。只对区块头进行哈希运算,因此为了验证区块链,我们只要知道Merkle树根即可。

“coinbase”交易。这是创造新比特币的一种记录,与一般交易信息有一下不同:

  • 一般只有一个输入和输出
  • 输入值是空的hash指针。
  • 输出值比25BTC略多,输出值由2部分组成,一个是挖矿的奖励,另一个是交易费
  • 还有一个“coinbase”参数,矿工可以在这里放置任何值

第三章 比特币的实现机制_第9张图片

比特币网络

比特币网络中所有结点的地位是对等的,它们是P2P网络,运行于TCP协议之上。结点之间的拓扑结构是任意的。任何一个结点可以在任何时间加入或者离开。如果我们想要加入网络,首先要找到网络中的一个任一个结点结点,该结点称为“种子结点”,通过种子结点向其他结点建立链接,以此类推,可以向所有的结点建立链接。

这种链接的优势在于,如果我们要向网络广播一条消息,所有的结点都会收到。这个过程通过 “flooding算法”(也称为”gossip 协议”)实现。假设Alice向Bob支付一些BTC,那么算法过程如下:

  1. Alice的客户端把该消息向所有链接它的结点广播
  2. 每个接收到消息的结点检查消息,并决定是否接收该消息。如果检查通过,进入步骤3;否则忽略消息。此时交易信息未上区块链。
  3. 结点检查自己的交易缓冲池中是否有该消息。如果没有,那么把交易消息加入缓冲池,然后向它的邻接结点广播该消息;否则不广播该消息。这样保证了消息不会无限重复发送。

说明,因为每个交易都有唯一的哈希值,因此检查它们是否存在还是很容易的。

结点通过下面几点决定是否接受消息:

  • 交易合法性的检查:交易必须符合当前的区块链的信息。结点运行之前经过认证的脚本,并保证输出true。
  • 结点检查认证的输出没有被花费
  • 结点不接受缓冲池中存在的结点,上面提到了
  • 默认的,结点只接受“标准”的脚本,即有一个脚本白名单,接收到的脚本必须在名单里

上述的规则不是必须的,这是个P2P网络,任何结点都可以加入或者退出,这些要靠结点自己完成。

由于网络中存在延迟,因此结点的缓冲池会有一些差异,这对双重支付有较大的影响。假设Alice同时向Bob和Carlo支付了比特币,也就是双重支付。一些结点会先接收到支付给Bob的,另一些先接收到给Carlo的。结点会把先接收到的交易信息加入到缓冲池中(假设检验通过了),如果结点发现有双重支付的企图,那么结点会丢掉后来的交易信息。因此,结点会对把哪个交易信息加入区块链产生歧义,称之为“Race Condition”。

但是,由于这是去中心化的系统,上述的规则不是必须的,没有中心结构强制执行这一规则,那么可能有结点不是按照上述规则执行的。

之前我们提到过“零置信交易”,接受方只要接收到消息就立刻执行,不等6个区块的时间进行确认。由于矿工首先接受第一次监听到的消息,因此这在一定程度可以缓和双重支付攻击。

可能有结点不是接受先监听到的信息,比如有些结点会接受交易费高的那一个。那么这样会让双重支付在“零置信交易”中更容易实现。

验证区块的有效性币验证交易的有效性更加复杂。验证区块的有效性包括下面几个步骤:

  • 验证区块头,保证它的哈希值在合理的范围内。
  • 结点必须验证区块内的每个交易都是合法的 。
  • 区块必须建立在最长的区块链上 。

flood算法的延迟。延迟主要取决于网络的速度。同时,区块的尺寸越大,延迟越高。

存储要求: 完全有效的结点必须永久的链接在网络上,以监听所有的数据。离线的时间越长,那么一个结点再加入网络时需要做的事情就越多。永久有效结点需要存储整个区块链,同时能工监听每一笔新的交易,并且转发有效交易给其他结点。这样的结点必须存储所有未花费的交易输出。很明显,这需要存储在RAM中,只有这样才能在接受新的交易后,快速查找交易输出,然后运行脚本,验证签名是否是有效的,如果是有效的就把交易加入到交易缓冲池中。

轻量级结点: 与全连接结点相反,比特币网络中有许多轻量级结点,它们称为thin client或者simple payment verification(SPV),它们的数量远远多于全连接结点。这些结点只存储他们关心的需要验证的交易。一个钱包程序一般都是SPV结点,这类结点仅下载区块头部和指向我们地址的交易。

SPV结点没有像全连接结点那样的安全等级,因为它们只有区块头部,这可以验证区块的有效性,但是不能检查区块中的每个交易都是真的有效的,因为他没有交易历史,而且也不知道未花费的交易的输出的集合。SPV只能验证影响它们自身的交易。因此它们必须信任全连接结点已经验证了它们没有验证的部分。

SPV结点的存储开销较小,一般是是兆级别的,而完全 结点是GB级别的。因此SPV一般完全可以由手机等移动端设备运行。

限制和提升

限制:

比特币的总数和挖矿的奖励不能轻易改变,否则会付出较大的代价。比特币系统每秒大约能处理7笔交易,这与当前中心化交易系统没法抗衡。加密算法可能会被破解,这也是人们担心的问题。同时,随着交易总数越来越多,存储空间占用也会越来越多。。

提升手段:

更改协议,如果我们要为比特币增加新的特性,由于这是去中心化的系统,那么有些结点会同意,有些结点会不更新。面对这种现象,有两种解决方案:硬合并和软合并。

hard fork:让新的客户端软件进行判定,新的区块是合法的,旧的区块是不合法的。这样,大部分结点会更新,少部分不会更新。这样会有问题:最长的区块链会被旧的结点视为不合法的。旧的结点会丢弃包含新特性的结点,并且在不包含新特性的区块链的分支上继续运行。那么,旧结点会把它们的分支区块链是最长的,除非它们更新自己的软件。这两个区块链是永远无法合并的。

soft fork: 给有效验证规则添加限制。这样,旧的规则会接受所有的原来有效区块,而新的规则会拒绝一部分。这样,可以避免hard fork中造成的区块链永远分裂。这样的风险在于,旧的结点会发现自己的一些区块被拒绝,即使它们不知道原因。这样,它们会逐步更新自己的软件。

你可能感兴趣的:(区块链,区块链)