本章主要叙述的是比特币的机制。在前两章中,我们已经在较高层次上进行了讨论,现在我们将深入细节。我们将查看真实的数据结构,真正的脚本,并试图学习比特币的细节和语言,以便在本书的其余部分以精确的方式来建立我们想要谈论的一切。这一章将是具有挑战性的,因为很多细节将会飞向你。你将会学到使Bitcoin成为什么的具体细节和怪癖。

 

为了回顾上次我们停止的地方,比特币的共识机制给了我们一个附加的分类账,一个我们只能写的数据结构。一旦数据写入了它,它就永远在那里。有一个分散的议定书来确定对该分类帐价值的共识,还有一些矿工们执行该协议并验证交易。他们一起确保交易良好形成,他们还没有被花费,分类帐和网络可以作为货币运作。同时,我们假定存在一种货币来激励这些矿工。在本章中,我们将看看我们如何实际构建该货币的细节,以激励矿工使整个流程运转。

 

3.1

比特币交易

让我们从交易开始,比特币的基本构建区块。我们将使用一个简化的分类帐模型。而不是区块,我们假设单个交易一次性被添加到分类账中。

 

第3章:比特币的机制(一)

图3.1 一个基于账户的分类账

 

我们如何在这样的分类账之上建立货币呢?你可能会想到的第一个模型,实际上是许多人对Bitcoin如何工作的心理模型,就是你有一个基于帐户的系统。你可以添加一些创建新硬币并将授予某人的交易。然后,你可以转移他们。一笔交易将会像“我们正在将17个硬币从Alice转移给Bob”一样,并由Alice签署。这就是分类账中包含的所有交易信息。在图3.1中,Alice在第一个交易中收到25个硬币,然后在第二个交易中将17个硬币转入Bob,她的账户将剩下8个比特币。

 

这种做事方式的缺点是,任何想要确定交易是否有效的人都必须跟踪这些账户的余额。再来看看图3.1。Alice试图转移15个硬币给大卫,如何确定她有这些?为了弄清楚这一点,你必须一直回头看看每一个影响Alice的交易,以确认她试图向大卫转移15个硬币时的净额是否大于15个硬币。当然,我们可以通过一些数据结构来跟踪Alice在每个交易之后的余额,使其更有效率。但是,除了分类账本身之外,还需要大量的额外管理。

 

由于这些缺点,比特币不使用基于账户的模式。相反,比特币使用的分类帐只跟踪第1章中与ScroogeCoin类似的交易。

 

第3章:比特币的机制(一)

图3.2 这是一个基于交易的分类帐,与比特币非常接近

 

交易指定了一些输入和多个输出(ScroogeCoin中召回PayCoins)。你可以将输入视为消费中的硬币(在先前的交易中创建的),并将输出视为正在创建的硬币。对于新货币被铸造的交易,没有硬币被消费(ScroogeCoin中召回PayCoins)。每一个交易都有唯一的标识符。输出从0开始索引,所以我们将第一个输出称为“输出0”。

 

现在让我们来看看图3.2。交易1没有输入,因为这个交易正在创建新的硬币,它输出给Alice25个硬币。另外,由于这是一个正在创建新硬币的交易,所以不需要签名。现在我们来说,Alice想把那些硬币发给Bob。为了做到这一点,她在我们的例子中创建了一个新的交易,交易2。在交易中,她必须明确提及这些硬币来自的前一笔交易。在这里,她提到交易1的输出0(实际上是交易1的唯一输出),它向Alice分配了25个比特币。她也必须在交易中指定输出地址。在这个例子中,Alice指定了两个输出,17个硬币给Bob,8个硬币给Alice。 而且,这整个事情当然是由Alice签署的,所以我们知道Alice实际上是授权这个交易的。

转换地址。为什么Alice在这个例子中必须向自己汇钱?正如ScroogeCoin中的硬币是不可变的,在比特币中,整个交易输出必须被另一个交易消耗,或者没有它。Alice只想向Bob支付17个比特币,但她拥有的输出价值是25比特币。所以她需要创建一个新的输出,其中8个比特币被送回给自己。这可能是一个不同于拥有25个比特币的地址,但它必须由她拥有。 这就是所谓的转换地址。

 

有效的验证。当新的交易被添加到分类帐时,如何容易地检查它是否有效?在这个例子中,我们需要查询Alice引用的交易输出,确保它的值为25比特币,而且还没有被花费。查询交易输出很容易,因为我们使用散列指针。为了确保它没有被花费,我们需要扫描引用的交易和最新区块之间的区块链。我们不需要一路回到区块链的开始,也不需要保存任何额外的数据结构(尽管我们将看到,额外的数据结构将加快速度)。

 

整合资金。像ScroogeCoin一样,由于交易可以有很多输入和许多输出,分割和合并的价值很容易实现。例如,Bob在两次交易中收到钱,一个是17个比特币,另一个则是2个。Bob可能会说,我想有一个交易,我以后可以花费,因为我拥有19个比特币。这很容易——他用两个输入和一个输出创建一个交易,输出地址是他拥有的一个。这让他整合了这两个交易。

 

联合支付。同样,联合支付也很容易做到。卡罗尔和Bob都想支付给大卫。他们可以创建一个具有两个输入和一个输出的交易,但两个输入由两个不同的人拥有。他们可以创建一个具有两个输入和一个输出的交易,但两个输入由两个不同的人拥有。与上一个例子的唯一区别是,由于这里要求的先前交易中的两个输出来自不同的地址,交易将需要两个单独的签名——一个由卡罗尔和一个由Bob。

 

交易的语法。在概念上,这真的是Bitcoin交易。现在让我们看看它在比特币中低层的表现。最终,在网络上发送的每个数据结构都是一个位串。图3.3中显示的是非常底层的,但是这进一步被编译成一个不可读的紧凑二进制格式。

 

第3章:比特币的机制(一)

图3.3 一个实际的比特币交易

 

如图3.3所示,交易有三个部分,一些元数据,一系列输入和一系列输出。

 

·元数据这里有一些管理信息——交易的大小,输入的数量和输出的数量。整个交易的哈希是用作交易的唯一ID。这就是允许我们使用哈希指针来引用交易的原因。最后还有一个“lock_time”字段,我们稍后讲述。

 

·输入。交易输入形成一个数组,每个输入都具有相同的形式。一个输入指定一个先前的交易,所以它包含该交易的哈希,并作为一个哈希指针存在。输入中还包含了要声明的先前交易的输出索引。然后,还有一个签名。请记住,我们必须签署,以表明我们实际上有能力要求前面的交易输出。

 

·输出。输出又是一个数组。每个输出只有两个字段。它们各自具有一个值,并且所有输出值的总和必须小于或等于所有输入值的总和。如果输出值的总和小于输入值的总和,则差额是发布此交易的矿工的交易费用。

 

·然后,有一个有趣的行列,看起来像我们想要的收件人地址。每个输出都应该是一个特定的公共密钥,而且这个字段中有一些东西看起来像是公钥的哈希。但是还有一些其他的东西看起来像一组命令。事实上,这个区域是一个脚本,我们即将讨论这个。

3.2

比特币脚本

每个交易输出不仅指定一个公钥。它实际上指定了一个脚本。 什么是脚本,为什么要使用脚本? 在本节中,我们将研究Bitcoin脚本语言,并了解为什么使用脚本而不是简单地分配公钥。

 

比特币中最常见的交易类型是通过使用正确的密钥进行签名来兑换先前的交易输出。在这种情况下,我们希望交易输出说:“这可以通过地址X所有者的签名来兑换。”回想一下地址是一个公钥的散列。所以只是指定地址X不告诉我们什么是公钥,而不是给我们一个方法来检查签名!所以交易输出必须说:“这可以通过哈希到X的公钥来兑换,以及该公钥的所有者的签名。”我们将看到,这正是最常见的Bitcoin脚本类型。

 

第3章:比特币的机制(一)
图3.4 一个PubkeyHash支付的脚本,Bitcoin中最常见的输出脚本类型

 

但是这个脚本会发生什么?谁运行它,以及这个指令序列究竟如何执行上面的语句的?秘密在于输入包含脚本而不是签名。为了验证交易是否正确地兑换了以前的交易输出,我们将新交易的输入脚本和较早的交易的输出脚本相结合。我们简单地连接它们,并且生成的脚本必须成功运行才能使交易有效。这两个脚本称为scriptPubKey和scriptSig,因为在最简单的情况下,输出脚本只是指定公钥(或公开公钥哈希的地址),输入脚本使用该公钥指定签名。组合脚本可以在图3.5中看到。

 

比特币脚本语言。脚本语言是专门为Bitcoin而设计的,它被称为“脚本”或比特币脚本语言。它与一种称为Forth的语言有很多相似之处,一种旧的,简单的,基于堆栈的编程语言。但是您不需要通过了解Forth来了解Bitcoin脚本。脚本的关键设计目标是简单而紧凑,而且还具有对加密操作的本机支持。因此,例如,有专门的指令来计算哈希函数并计算和验证签名。

 

脚本语言是基于堆栈的。这意味着每条指令都以线性方式执行一次。特别的是Bitcoin脚本语言中没有循环。所以脚本中的指令数量给了我们运行多长时间以及可以使用多少内存的上限。语言不是图灵完备的,这意味着它不具备计算任意强大功能的能力。这就是设计——矿工必须运行由网络中的任意参与者提交的这些脚本。我们不想让他们有权提交一个可能有无限循环的脚本。

 

第3章:比特币的机制(一)
图3.5 要检查事务是否正确兑换输出,我们将通过参考输出交易(bottom)的scriptPubKey附加到兑换交易(top)的scriptSig来创建组合脚本。请注意,包含一个’?’。我们使用这个符号表示我们稍后会检查以确认这等于兑换脚本中提供的公钥的哈希值。

 

当Bitcoin脚本被执行时,只有两个可能的结果。它可以成功执行,没有错误,在这种情况下,交易是有效的。 或者,如果脚本执行时出现任何错误,则整个交易将无效,并且不应被接受到块链中。

 

比特币脚本语言非常小。只有256个指令的空间,因为每个指令由一个字节表示。在这256位中,15位目前被禁用,75位被保留。保留的指令代码尚未分配任何具体含义,但可能稍后添加指令。

 

许多基本指令都是你希望在任何编程语言中使用的指令。有基本的算术,基本的逻辑——如’if’和’then’——,抛出错误,不会抛出错误,还有提前返回。最后,还有一些加密指令,其中包括哈希函数,签名验证指令,以及一个称为CHECKMULTISIG的特殊而重要的指令,可以让你用一条指令来检查多个签名。图3.6列出了Bitcoin脚本语言中最常见的一些指令。

 

CHECKMULTISIG指令需要为阈值指定n个公钥和一个参数t。为了有效地执行该指令,从n个公共密钥中的t个,必须至少有t个签名才是有效的。我们将在下一节中介绍一些你使用多重签名的例子,但是应该立即清楚这是一个非常强大的原语。我们可以用紧凑的方式表达n个指定实体的T必须为交易有效而签名的概念。

 

顺便说一句,多重签名实现有一个错误,它一直在那里。CHECKMULTISIG指令从堆栈中弹出一个额外的数据值,并忽略它。这只是比特币语言的一个怪癖,必须通过在堆栈上放置一个额外的虚拟变量来处理它。这个bug是在原来的实现中,修复它的代价远远高于它造成的损害,我们将在后面的3.5节中看到。在这一点上,这个错误被认为是比特币的一个功能,因为它不会消失。

第3章:比特币的机制(一)

图3.6列出了常见的脚本指令及其功能。

 

执行脚本。要以基于堆栈的编程语言执行脚本,我们需要的是一个堆栈,我们可以将数据推送到其中并从中弹出数据。我们不需要任何其他内存或变量。这就是使它计算上如此简单的原因。有两种类型的指令:数据指令和操作码。当数据指令出现在脚本中时,该数据被简单地推到堆栈顶部。另一方面,操作码执行一些功能,通常将其作为堆栈顶部的输入数据。

 

现在来看看图3.5中的Bitcoin脚本是如何执行的。参见图3.7,我们在每个指令之后显示堆栈的状态。这个脚本中的前两个指令是数据指令——签名和公钥用来验证签名在兑换交易中输入指定交易scriptsig组件。正如我们所提到的,当我们看到一个数据指令时,我们只是把它推到堆栈上。脚本的其余部分是在参考交易中的交易输出指定ScriptPubKey组件。

首先我们有重复的指令OP_DUP,所以我们只需将公钥的副本推到堆栈的顶部。下一个指令是OP_HASH160,它告诉我们弹出顶部值,计算其加密哈希,并将结果推送到堆栈的顶部。当这个指令完成执行时,我们将堆栈顶部的公钥替换成它的哈希。

第3章:比特币的机制(一)
图3.7 比特币执行脚本。在底部,我们将显示脚本中的指令。数据指令用周围的尖括号表示,而操作码以“OP_”开头。在顶部,我们在执行该指令之后显示堆栈。

 

接下来,我们将再次将数据推送到堆栈上。回想一下,这个数据是被引用交易的发送者指定的。它是发送者指定的公钥哈希值;必须使用相应的私钥来生成签名来兑换这些硬币。此时,堆栈顶部有两个值。有发件人指定的公共密钥的哈希,以及收件人在尝试索取硬币时使用的公共密钥的哈希。

 

此时,我们将运行EQUALVERIFY命令,该命令检查堆栈顶部的两个值是否相等。如果没有,则会抛出错误,脚本将停止执行。但在我们的例子中,我们假设他们是相等的,也就是说硬币的收件人使用正确的公钥。该指令将消耗堆栈顶部的两个数据项,而堆栈现在包含两个项目——一个签名和一个公钥。

 

我们已经检查了这个公钥实际上是引用交易的指定公钥,现在我们必须检查签名是否有效。这是一个很好的例子,其中比特币脚本语言是用加密技术构建的。即使在逻辑方面这是一个相当简单的语言,还有一些非常强大的指令,就像这个“OP_CHECKSIG”指令一样。这个单个指令从堆栈中弹出这两个值,并且一次完成整个签名验证。

但这是什么签名呢?签名函数的输入是什么?事实证明,只有一件事你可以在比特币上签署——一个完整的交易。因此,“CHECKSIG”指令会从堆栈中弹出两个值,即公钥和签名,并使用该公钥验证整个交易的有效签名。现在我们已经执行了脚本中的所有指令,堆栈中没有任何内容。如果没有任何错误,此脚本的输出将简单地表示交易是有效的。

 

实际上使用的是什么呢?从理论上讲,脚本可以让我们在某种意义上指定为了花钱而必须满足的任意条件。但是,截至今天,这种灵活性并没有被非常重视。如果我们看看到目前为止比特币历史上实际使用的脚本,绝大多数,99.9%都是完全相同的脚本,这实际上是我们在示例中使用的脚本。正如我们所看到的,这个脚本只是指定一个公共密钥,并且需要该公钥的签名才能花费这些硬币。还有一些其他指令可以使用。MULTISIG使用了一些特殊类型的脚本,称为Pay-to-Script-Hash,我们将在稍后讨论。但除此之外,在脚本使用方面还没有太多的多样性。这是因为Bitcoin节点在默认情况下具有标准脚本的白名单,并且拒绝接受不在列表中的脚本。这并不意味着这些脚本根本不能使用;它只是使它们更难使用。事实上,这个区别是一个非常微妙的点,当我们谈论比特币对等网络时,我们将再回来一点。

 

销毁证明。销毁证明是一个永远不能被挽回的脚本。将硬币发送到销毁证明脚本,它们就已确定被销毁,因为没有任何可能再去花费它们。一种使用销毁证据的方式是通过强迫人们摧毁比特币以便在新系统中获得硬币来引导比特币的代币。我们将在第10章中更详细地讨论这一点。销毁证明相当容易实现:OP_RETURN操作码如果达到,就会抛出错误。无论在OP_RETURN之前放置什么值,该指令将最终执行,在这种情况下,该脚本将返回false。

因为抛出错误,OP_RETURN之后的脚本中的数据将不被处理。因此,这是人们将任意数据放入脚本中,从而进入区块链的一个机会。如果出于某种原因,你想写你的名字,或者如果你想要时间戳,并在某个特定的时间证明你知道一些数据,你可以创建一个非常低价值的比特币交易。你可以销毁一个非常小量的货币,但你想要将任何你想的东西写入区块链,这就需要它永远保持下去。

 

支付脚本的哈希。Bitcoin脚本工作方式的一个后果是硬币的发送者必须准确地指定脚本。但这有时可能是一件很奇怪的事情。比方说,你作为消费者正在在线购物,而你即将订购一些东西。你说,“好的,我准备付钱了。告诉我我应该将硬币发送到哪个地址。“现在,你购物的公司正在使用MULTISIG地址。那么,由于硬币的花费必须具体说明,所以零售商必须回过头来说:“哦,很好,我们现在做点什么不一样的,我们正在使用MULTISIG。 我们将要求您将硬币发送到一些复杂的脚本上。你可能会说,“我不知道该怎么做。这太复杂了。作为消费者,我只想发送到一个简单点的地址”。

 

对于这个问题,比特币有一个聪明的解决方案,它不仅适用于多个SIG地址,而且适用于任何复杂的条件,管理可以花费的硬币。相比于告诉发件人“发送你的硬币到这个公钥的哈希”,接收方可以告诉发件人“发送你的硬币到这个脚本的哈希。强加兑换那些硬币的条件,有必要揭示具有给定哈希的脚本,并进一步提供使脚本评估为真的数据。发件人通过使用具有上述语义的付费脚本散列(P2SH)交易类型来达到此目的。

 

具体而言,P2SH脚本只是简单地对堆栈的顶部值进行哈希,检查它是否与提供的哈希值相匹配,然后执行特殊的第二步验证:将堆栈中的顶层数据值重新诠释为指令序列,并二次作为脚本执行,用堆栈的其余部分作为输入。

 

获得P2SH的支持非常复杂,因为它不是Bitcoin初始设计规范的一部分。它是事后补充的。这可能是原始规范中没有的,添加到比特币中最显著的功能。它解决了一些重要的问题。它消除了发件人的复杂性,因此接收方只需指定发送者发送钱的哈希。在上面的例子中,Alice不用担心Bob正在使用多个SIG;她只是发送到Bob的P2SH地址,Bob有责任在兑换硬币时指定花哨的脚本。

 

P2SH也有一个很好的效率增益。矿工们必须跟踪尚未兑换的输出脚本集,并且使用P2SH输出,输出脚本现在要小得多,因为它们只用指定一个哈希。所有的复杂性被推送到输入脚本。

3.3

比特币脚本的应用

现在我们了解了比特币脚本的工作原理,让我们来看看一些可以用这种脚本语言实现的强大应用程序。事实证明,我们可以做许多优美的事情,这将证明具有脚本语言的复杂性,而不是仅仅指定公钥。

 

托管交易。Alice和Bob想彼此做生意——Alice想用比特币支付Bob,而Bob把一些实体商品送给Alice。问题在于,Alice想收到商品后才付款,但Bob不想在付款前发货。我们能做些什么呢?在实践中比特币使用的一个不错的解决方案是引入第三方并进行代管交易。

 

托管交易可以很简单地用MULTISIG来实现。Alice不把钱直接发送给Bob,而是创建了一个需要三个人中的两个签署才能兑换硬币的MULTISIG交易。这三个人将是Alice,Bob和一些第三方仲裁员朱迪,如果有任何争议,他将会起作用。所以Alice创造了一个2/3的MULTISIG交易,发送一些她拥有的硬币,并指定如果Alice,Bob和Judy中的两个签署了就可以花费。这个交易被包括在区块链中,在这一点上,这些硬币在Alice,Bob和朱迪之间进行代管,这样他们中的任何两个可以指定硬币应该去哪里。在这一点上,Bob相信将货物发送给Alice是安全的,所以他会邮寄或交付它们。现在在正常情况下,Alice和Bob都是诚实的。所以,Bob会发送Alice所期待的货物,当Alice收到货物时,Alice和Bob都签署了一笔交易,赎回代管的资金,并将它们发给Bob。请注意,在这种情况下,Alice和Bob都是诚实的,朱迪根本就不必参与其中。这里没有争议,Alice和Bob的签名符合MULTISIG交易的2/3要求。所以在正常情况下,效率并不比Alice直接把硬币发送给Bob低。它在区块链上只需要一个额外的交易。

 

但是,如果Bob没有真正发送货物或者丢失了邮件,会发生什么?或者商品与Alice订购的不一样?Alice现在不想支付Bob,因为她认为她被骗了,她想要把钱要回去。所以Alice绝对不会签署一笔向Bob发放资金的交易。但Bob也可以否认任何不法行为,并拒绝签署将资金退回Alice的交易。这就是朱迪需要参与的地方。朱迪要决定这两个人中哪一个应该得到这些钱。如果朱迪判决Bob作弊,朱迪愿意与Alice一起签署交易,将钱从代管处寄回Alice。Alice和朱迪的签名符合MULTISIG交易的2/3的要求,而Alice则会收回她的钱。当然,如果朱迪认为Alice在这里是不对的,而Alice只是简单地拒绝付钱,朱迪就能和Bob一起签署一笔交易,把钱交给Bob。所以朱迪决定两种可能的结果。但最好的事情是她不必参与,除非有争议。

 

绿色地址。另一个很酷的应用是所谓的绿色地址。Alice想支付Bob,而Bob却离线。由于他离线,Bob不能去查看区块链,看Alice发送的交易是否真实的在那里。也有可能鲍伯在线,但没有时间去查看区块链,并等待交易被确认。记住,通常我们希望一个交易处于区块链中,并且在我们相信它处于区块链中之前,需要六个区块来确认,这大概需要一个小时。但是对于一些商品,如食物,Bob不能等待一个小时才交付。如果Bob是卖热狗的街头小贩,Alice不太可能等待一个小时才能收到她的食物。或者也许Bob因为其他原因与互联网根本没有任何连接,因此不能检查区块链。

 

为了解决这个问题,接受者不必访问区块链却能使用比特币来发送资金,我们必须引入另一个第三方,我们称之为银行(实际上,它可以是一个兑换或任何其他金融中介)。Alice打算和她的银行谈谈,说:“嘿,这是我,Alice。我是你的忠实客户。这是我的卡或身份证。我真的很想在这里支付Bob,你能帮助我吗?”银行会说,“当然。我会从你的帐户中扣除一些钱。并将一笔交易从我的一个绿色地址交给Bob。”

 

所以,注意到这笔钱直接从银行转到了Bob。当然,这些钱可能改变地址回到银行。但基本上,银行从银行控制的地址向Bob付款,我们称此地址为绿色地址。此外,银行保证不会再花这笔钱。所以一旦Bob看到这笔交易是由银行签署的,如果他相信银行的担保不会双重支付这笔资金,他可以接受这笔在区块链中确认的钱最终将是他的。

 

注意,这不是比特币强制担保。这是一个现实世界的保证,为了使这个系统发挥作用,Bob不得不相信,现实世界中的银行关心他们的声誉,不会因为这个原因而花费双倍的钱。银行可以说:“你可以看看我的历史交易记录。我使用这个绿色地址很长一段时间了,我从来没有双重支付过。所以我今后也不太可能这样做。”因此,Bob不再不得不信任他一无所知的Alice。相反,他信任银行,相信他们不会将发给他的钱双重支付。

 

当然,如果银行双重支付,人们就会停止信任它的绿色地址。事实上,实施绿色地址的两个最著名的在线服务是Instawallet和Mt. Gox,并且都最终崩溃了。今天,绿色地址并没有得到太多的使用。当这个想法首次提出时,它作为一种更快速地进行付款并且无需访问区块链的方式,产生了很大的兴奋。然而,现在人们对这个想法变得非常谨慎,担心这对银行的信任过高。

 

有效的微额支付。比特币脚本的第三个例子是高效的微额支付。Alice是一个不断为Bob提供的一些服务进行支付的客户。例如,Bob可能是Alice的无线服务提供商,并要求她为在她手机上谈论的每分钟支付一小笔费用。

 

每分钟都为Alice的通话创建一个比特币交易将无法正常运行。这将造成太多交易,且交易费用累加。如果这些交易中的每一笔交易的价值与交易费用一一对应,Alice将为此付出相当高的代价。

 

我们希望最终能将所有这些小额支付合并成一笔大的支付。事实证明,有一个很好的方法可以做到这一点。我们从MULTISIG交易开始,Alice将需要花费最大的金额,该支付输出要求Alice和Bob签署以释放硬币。现在,在Alice使用该服务的第一分钟之后,或者Alice第一次需要进行小额支付时,她会签署一笔交易使用那些发送到MULTISIG地址的硬币,该交易将支付一个单位给Bob,并将其余部分退回给Alice。在使用该服务的下一分钟之后,Alice签署另一笔交易,此次向Bob支付两个单位,并将剩余部分交给自己。请注意,这些只是由Alice签名,尚未由Bob签名,也不会被发布到区块链。随着Alice每分钟都使用该服务,她继续将这些交易发送给Bob。最后,Alice将完成使用该服务,并告诉Bob:“我已经完成了,请切断我的服务。”此时,Alice将停止签署额外的交易。听到这话,Bob会说“太好了”。 我会断开您的服务,并把您发送给我的最后一个交易签署,将其发布到区块链上。”由于每笔交易都向Bob支付了一点费用,而Alice稍微少了一点,Bob兑换的最后一笔交易完全是支付他所提供的服务的,其余款项则退还给Alice。Alice签署的所有交易都不会出现在区块链上。Bob不必签署他们,他们只是会被丢弃。

 

从技术上讲,这些交易都是双重支付的。之所以,不同于我们专门设法避免双重支付的绿色地址的情况,在一个强有力的保证下,通过这种小额支付协议,我们实际上产生了大量潜在的双重支付。但实际上,如果双方都正常运作,Bob永远不会签署任何交易,除了最后一个交易,在这种情况下,这个区块链实际上并不会看到双重支付的尝试。

 

还有另一个棘手的细节:如果Bob从不签署最后一笔交易呢?他可能会说:“我很高兴让硬币永远躺在托管那里”,在这种情况下,也许硬币不会移动,但Alice将失去一开始支付的全部价值。有一个非常聪明的方法来避免我们刚才提到的这个问题,现在我们来解释。

 

锁定时间。为了避免这个问题,甚至可以在微支付协议开始之前,Alice和Bob都将签署一笔交易,将Alice的所有资金退还给她,但退款在将来某个时候段内被“锁定”。所以,在Alice签名之后,广播之前,首先将资金转入托管的MULTISIG交易中,她将想从Bob那得到这笔退款交易,并一直持续下去。这样做可以保证,如果到达时间t,而Bob没有签署Alice发送的任何小交易,Alice可以发布直接将所有钱直接退还给她的交易。

 

它被说定到时间t是什么意思呢?回想一下,当我们查看比特币交易中的元数据时,有这样一个lock_time参数,我们并没有解释。它的工作方式是,如果你为锁定时间指定了零以外的任何值,则会告知矿工在指定的锁定时间之前不要发布交易。基于放入区块的时间戳,交易在特定区块号或特定时间点之前将无效。因此,这是一种准备交易的方法,它只有在将来还没有投入的时候才能使用。它作为Alice的安全阀,在微支付协议中工作的相当不错,Alice知道如果鲍勃从不签名,最终她将能够收回她的钱。

 

希望这些例子告诉你,我们可以用Bitcoin脚本做一些漂亮的事情。我们讨论了三个简单实用的例子,但还有很多其他已研究的。其中的一个是多玩家彩票,一个非常复杂的多步骤协议,大量的交易具有不同的锁定时间,并且人们在欺骗的情况下进行托管。还有一些漂亮的协议使用脚本语言来允许不同的人将他们的硬币结合在一起,并将它们混合在一起,这样很难追踪谁拥有哪个硬币。我们将在第6章中详细介绍。

 

智能合约。我们在本节中看到的合约的一般术语是智能合约。这些是比特币中我们有一定程度技术执行的合约,然而传统上它们是通过法律或仲裁法院执行的。Bitcoin有一个非常酷的功能,我们可以使用脚本,矿工和交易验证来实现托管协议或微支付协议,而不需要集中的权限。

 

对智能合约的研究远远超出了我们在本节中看到的应用。今天,有许多类型的智能合同,人们希望能够执行,但不被Bitcoin的脚本语言所支持。或者至少没有人想出创造性的方式去实现它们。正如我们所看到的,有一点创造力,你可以使用Bitcoin脚本做很多事,就像现在一样。

 

 

想了解更多相关内容,请关注wherein旅行微信公众号,我们给你想要的和你意想不到的。

?

第3章:比特币的机制(一)

始发于微信公众号: 可可旅行人生