比特币也可以有智能合约

发现

项目

学习

体验

蜂群

比特币也可以有智能合约

这是智能合约系列文章的第一篇,介绍什么是智能合约以及比特币如何支持智能合约。本文假定你已经了解比特币的基本原理,了解什么是哈希算法,什么是数字签名。但你不需要是一名程序员。


阅读完本文,你将知道:

  • 比特币交易并不仅限于转账功能,可以通过脚本定义复杂的交易逻辑
  • 什么是智能合约
  • 比特币上能实现哪些类型的智能合约
  • 比特币上不能实现哪些类型的智能合约
  • 对于一个智能合约应用的可信度,我们应该关注哪些东西

不只是转账


我们都知道比特币交易大部分都是在表达这么一种意思:谁把他的多少比特币转给了谁,比如 A 把他的 10 比特币转给了 B。


A 要支付这 10 个比特币,必须指明这里使用的是他从之前哪个交易中得到的比特币,而且在这次支付交易中,他要提供自己的数字签名。


这个工作通常比特币钱包帮忙做了,用户不会察觉到。


之所以要提供数字签名,是因为之前那个交易指定了把比特币支付到 A 的某个钱包地址中。A 必须使用跟这个地址匹配的数字签名,才能使用该比特币。


这是对于比特币交易的一种常规理解。只有掌握地址对应的私钥,进行数字签名,你才能够使用相应的比特币。


不过,比特币交易并不是这样有针对性地设计的。在指定交易的比特币接收者时,它使用的是锁定脚本;而当接收者想要使用那个比特币时,他需要在新交易中提供解锁脚本。


脚本,简单地说,就是指一段可执行的程序


当我们通过转账交易把一定数额的比特币转到某个地址,这个交易其实只是包含了对这些比特币的锁定脚本。 锁定脚本定义了解锁的条件。在转账交易中,锁定脚本定义了这些条件(虽然本文用文字直接描述脚本内容,但实际上必须使用专门的脚本语言编写它们):


请提供两个值:
- 第一个值在哈希后等于指定的 <地址>
- 第二个值是第一个值的签名


在本文表述的“ XX 的签名”中,XX 通常是一个公钥,而签名指的是使用该公钥对应的私钥,对本交易进行的签名。


交易要解锁它代表的比特币时,便必须提供这样脚本:


这里有两个值:
- 第一个值是一个公钥
- 第二个值是一段数字签名


比特币矿工在验证交易时,会把两个脚本合起来,看能否执行成功。只有在成功执行后,新交易才被添加进去区块链。


如果比特币只是作为虚拟货币,提供转账功能,大可不必使用这种可编程的脚本。但是因为比特币交易提供了这种脚本的机制,它可以做的事情,就远远不止简单的转账交易。


它能定义智能合约。


智能合约是什么


根据维基百科,"智能合约是用于在数字世界促成、验证和执行特定合同的的计算机程序。它允许在没有第三方的情况下进行可信交易。它的执行是可追踪而且不可篡改的。"


智能合约能够根据不同条件执行预设的步骤;它的执行需要根据外部条件进行触发;它的执行会修改条款所针对的客体的状态。


智能合约,包括了合同中所有条款的信息,能够自动地根据条件执行预设的所有动作。


这并不是一个很新的概念,只不过因为区块链的流行,让智能合约的特性得以更好的实现。


如果一个智能合约要在没有第三方控制下自动可信地执行,它的条款所针对的客体(object),必须在它的控制之下;而且触发它执行的外部条件必须是可信的。


下面我们根据比特币上的示例,来看看智能合约具体长什么样。


比特币上的智能合约


共管账户


比特币能实现的一种最简单的合约,是共管账户 - 需要两个或者多个人同时签名才能动用的钱。


假设三人合作提供某种专业服务,客户通过比特币支付,他们希望所有的收益至少有两个人的签名才能支配。


客户支付时,交易的锁定脚本,大概可以定义如下


请提供 2 个数值,
它们是公钥 A,B,C 之二的签名:


客户使用这种交易支付给他们的比特币,等于支付到了他们的共管账户智能合约。


假设他们三人之中,A 拥有更大的控制权,希望共管账户的规则定义为: A 可以直接支配资金,而如果是 B 和 C, 则需要两个人共同决定。


比特币也支持这种逻辑。此时,智能合约的锁定脚本可以写成两个条件:


条件 1:
请提供公钥 A 的签名;

条件 2:
请提供公钥 B 的签名;
请提供公钥 C 的签名。


比特币脚本使用“IF...ELSE...”的形式定义这种分支条件,解锁时可以选择执行其中之一,就像传统合同中, 当事人根据情况自行决定希望行使哪项权利。


时间的限制


比特币脚本支持时间条件。在比特币这种分布式网络中,时间是难以统一的。因此比特币网络根据当前区块链数据,计算出来所谓的“共识时间”。这个共识时间大概比真实时间延迟一个小时。(见 BIP-113


比特币中的智能合约,可以根据这个共识时间进行逻辑的编写。


还是假设 A、B、C 三人合作提供服务,他们希望客户支付给他们的钱,进入这样一种共管账户:当钱入账之后,三十天内,必须有三人之二共同签名,才能支配;三十天之后,三人中任何一人加上他们的律师 D 的签名,就可以支配;九十天之后,三人中任何一人的签名都可以支配。


支付交易的锁定脚本,便可以直接定义这三组不同的条件:


条件1:
请提供公钥 A, B 和 C 之二的签名

条件2:
当前距离交易时间必须已经过了 30 天 
请提供公钥 A,B 和 C 之一的签名
请提供公钥 D 的签名

条件3:
当前距离交易时间必须已经过了 90 天
请提供公钥 A,B 和 C 之一的签名


类似的逻辑组合无穷尽。关于共管账户逻辑的智能合约,就先举例到这里。我们接下来看看其他类型的智能合约,比如打赌。


简单的双方打赌


假设两个人 A 和 B 要进行简单的打赌。他们不在同一个地方,希望通过比特币平台来完成。(当然,如今这已不太现实,因为比特币上的交易成本实在太高,不过我们权且举个例子)


比特币上没有随机数可使用,不能掷骰子。于是他们初步设计: A 和 B 各提供一个数字,两个数字加起来除于二,如果余数为 0 则 A 胜,余数为 1 则 B 胜。


方案听起来很简单,但有一些细节问题待解决。


1)剪刀石头布问题


第一个问题是,如果其中一人先提出数字,另一人自然可以调整自己的数字,来确保获胜。就像剪刀石头布,大家不能先后出。但是比特币网络没办法保证双方同时提供数字。


这个问题可以通过取哈希值解决。整个流程如下:

  • 第一回合:两人把自己选择的数字进行哈希求值;把赌注支付到特定合约,同时披露哈希值。
  • 第二回合:在限定时间内,两人披露自己的数字,双方可以用第一回合的哈希值验证对方披露的数字。

根据第二回合的数字,来判定胜负。胜者可以把双方的赌注从合约中取走。


已经有哈希值在先,两人都无法在第二回合临时修改自己的数字,于是解决了剪刀石头布的问题。


在第一回合,A 和 B 都必须将自己的赌注,支付到特定的合约中。这个合约脚本比较复杂,它定义了两组条件:


条件 1:
请提供三个数值
第一个数值经过哈希后等于 <A之前披露的哈希值>
第二个数值哈希后等于 <B之前披露的哈希值>
第一和第二个数值之和除于 2 等于 0
第三个数值,是公钥 A 的签名

条件 2:
请提供三个数值
第一个数值经过哈希后等于 <A之前披露的哈希值>
第二个数值哈希后等于 <B之前披露的哈希值>
第一和第二个数值之和除于 2 等于 1
第三个数值,是公钥 B 的签名


这个合约可以这么理解,当披露出来的数字之和除于 2 等于 0 时,只有 A 才能进行支配资金;否则,就只有 B 才能支配资金。


因此,等第二回后双方把数字披露出来后,如果 A 胜出,他可以使用两个数字和自己的签名,把双方的赌注都取出来。如果 B 胜出,也是一样。


2)拒绝耍赖


接下来需要解决第二个问题。如果在第二回合时,一个人披露完自己数字后,另一个人发现自己肯定输,于是耍赖不愿意披露自己的数字怎么办。虽然他并不能取回自己的赌注,但是损人不利己的行为,在一个没有互信的环境下,也是需要避免的。


为了解决这个问题可以新增一个保证金合约。


对于 B 来说,他需要把一定的保证金支付到比特币网络。这个保证金只能通过两种方式之一来取回:

  1. A 签名,但是要在一个小时(或者其他双方认可的时间)之后
  2. B 签名而且把自己的数字披露出来

保证金合约锁定脚本定义的条件大概如下:


条件 1:
当前时间距离交易时间必须已经过了一个小时
请提供公钥 A 的签名

条件 2:
请提供公钥 B 的签名
请提供一个数,它在哈希计算后等于<B之前披露的哈希值>


有了这个合约,如果 B 要赎回自己的保证金,就必须披露他打赌的数字。而且,如果在一个小时后还不披露,A 可以自行把 B 的保证金取走。


A 也一样,也需要把保证金支付到这样的合约中。


因此这个打赌过程变成了三个回合:

  • 第一回合:两人先把自己选择的数字进行哈希求值;把保证金支付到各自的保证金合约,同时披露哈希值
  • 第二回合:双方都把赌注支付到打赌合约。
  • 第三回合:在限定时间内,两人披露自己的数字,双方可以用第一回合的哈希值验证对方披露的数字。

根据第三回合披露的数字,来判定胜负。双方各自通过披露数字把自己的保证金取走;胜者通过数字和自己的签名,把双方的赌注取走。如果有一方不愿披露数字,另一方可以把对方的保证金取走;双方都损失掉赌注。


至此,在双方完全不互信的情况下进行打赌的合约,就已经完成。


比特币智能合约的特点


举例到这,我们来梳理一下比特币智能合约的特点。


比特币上的脚本支持基本的算术和逻辑操作,支持一些复杂操作如计算哈希值、检查数字签名等,能够根据条件选择性执行动作,也能够根据区块链共识时间来进行时间判断。


根据这些能力可以组合出比较复杂的逻辑。但是它不支持循环,因此不是“图灵完备”。


图灵完备的意思是能做任何可能的计算(精确地说是,任何图灵机能够进行的计算)。图灵完备的语言设计出来的程序,有个著名的“停机问题”:你无法在不运行它的情况下,知道它是不是在有限步骤下能够结束。这一点在比特币交易上是不可接受的,因为任何一个交易,当被放进区块链前都会被验证,脚本会被执行,如果有一个无法执行完的脚本,整个网络都将无法工作。


有了这些逻辑,这些合约能达成什么结果?或者说,它们能控制或者改变外部的什么东西?


从以上这些例子来看,它们只能控制交易脚本锁定的比特币。如果我们通过“染色币”的方式,在比特币网络发行自定义的资产,也可以通过智能合约来控制这些自定义资产。


染色币,是指在一个很小面值的比特币上面,增加额外的标签和属性,让它们代表一些其他意思,比如自定义的货币,或者实物资产的所有权凭证,等等。这也可以通过脚本实现,不过不属于智能合约的范畴,在这里就不做详解。


这些合约的执行,通常需要一个或多个参与方的行动来触发。根据以上例子我们知道,进行触发时需要这几类外部信息:

  1. 参与方的签名
  2. 合约限定的信息
  3. 辅助的条件路径选择数值

在目前这些例子中,这些所有的外部信息都是可信的


数字签名,如果我们相信非对称加密算法没有被攻破,而且私钥确实是掌握在它的主人手中,它们就是可信的。


合约限定的信息,包括上面所提到的 1)转账脚本中的“经过哈希之后的值为特定地址”的数值;2)赌注协议中“经过哈希之后的值为特定数”的数字;3)用于判定时间条件的区块链共识时间,等等。这些都是可信的。


而辅助的的条件路径选择数值,并不影响合约的执行,只是关乎哪条执行路径的选择而已。


因此,上面所述的智能合约,都是“trustless”合约,也就是,不需要基于任何人与人之间的信任,也不需要任何第三方见证的合约。


但是有些合约需要的输入信息,并不能保证可信。


不可信的外部信息


很多智能合约的执行,往往需要根据一些外部的事实。在这些事实被放入交易中触发合约的执行时,它们的来源并不一定是可信的。


设想一个例子,两个人,A 和 B,在 2014 年世界杯决赛前打赌德国和阿根廷谁能胜出。A 认为德国赢,B 认为阿根廷赢。他们要把赌注都投入到一个智能合约中。


我们可以怎么来写这个智能合约?


粗糙无用的版本


这个智能合约的条件,必须涉及到 “德国和阿根廷究竟谁胜出” 的这个事实。


下面是一个近乎无用的合约版本


条件 1:
请提供公钥 A 的签名;

条件 2:
请提供公钥 B 的签名。


这里面,蕴含着一个假设:A 和 B 双方都会在决赛结束后,根据真实的结果,来选择执行条件 1 或者 2。但是合约中对此未做任何限制。


因此这个智能合约基本是无用的。A 和 B 间需要完全的互信,才能保证合约有效。


引入一个仲裁者


我们可以引入仲裁者 C,这个合约条件变成:


条件 1:
请提供公钥 A 的签名;
请提供公钥 C 的签名。

条件 2:
请提供公钥 B 的签名;
请提供公钥 C 的签名。


此时,A 和 B 是把信任交给了这个仲裁者 C,而且仲裁者必须参与到这次打赌的行为中。C 要根据赛果来选择性地允许 A 或者 B 取走赌注。


与交易无关的仲裁者


技术上我们也可以实现一种与打赌行为无关的仲裁者,他只对现实事件负责。


世界杯决赛前,这个中立的仲裁者发布两个公钥,其中一个代表“德国胜”,另一个代表“阿根廷胜”。


A 和 B 把赌注支付到如下的合约脚本:


条件 1:
请提供公钥 A 的签名;
请提供公钥“德国胜”的签名;

条件 2:
请提供公钥 B 的签名;
请提供公钥“阿根廷胜”的签名;


在世界杯决赛后,仲裁者根据赛果,公开其中一个私钥。另一个私钥则不能被公开。


如果德国胜了,A 可以通过仲裁者公开的代表“德国胜”的私钥,以及自己的私钥,对交易进行签名,获得赌注。如果阿根廷胜,B 也可以做一样的事情。


虽然这个中立的仲裁者,并未参与任何一个交易,A 和 B 的智能合约,仍然是把一定程度的信任交给了他。


可信的输入来源是个重要问题


根据上面的讨论,我们知道,大部分与现实生活有关的智能合约,都可能会涉及到一些输入信息,这些信息的可信度,无法通过密码学的技术手段、也无法通过区块链来保证


这种类型的智能合约,要么把信任部分地转移到第三方上,要么就要设计额外的去中心化机制来解决这个信任问题。


所以,部署在可信区块链上的智能合约,并不是本质上就必然可信的。


在考察一个区块链应用时,这是一个要重点关注的问题


最后我们来看看比特币上不支持哪些类型的智能合约。



比特币智能合约的局限


比特币平台上的智能合约有比较大的局限性,以下是我觉得比较重要的几方面:


1)它们不是图灵完备


简而言之,图灵完备,就是能进行任何可以想象到的任何计算。比特币平台上的智能合约不支持循环迭代的操作,因此它不是图灵完备。


2)当合约执行时,它没办法指定被影响到的比特币金额,要么全部解锁,要么就完全不解锁


它不能轻易地实现这样一种合约:A 支付给 B 一大笔资金,但不希望 B 一次性取完,只允许他每月支取一定数额,同时 A 可以随时把余额全部冻结或者取回。


3)合约没有中间状态


因为比特币上的智能合约只是一个锁定脚本,成功解锁前后,没有中间状态,导致实现复杂协议很困难。


例如上面所介绍的“不基于信任的打赌”,这种简单的协议,也需要三个合约 - 两个各自的保证金合约、一个打赌合约 - 来实现。


对于更复杂的协议可想而知。


关于这些局限所导致的不能实现的智能合约,我并不准备举太多例子,因为在比特币之后,有更好的智能合约区块链平台在迅速发展中,比如以太坊。


比特币之后


除了上面所说的局限性,比特币平台如今已经不适合作为智能合约平台,还因为两个重要因素,一是性能,二是高昂的交易成本。因此,在接下来的智能合约“科普”系列文章中,我会更多地介绍以太坊以及其他平台的智能合约。


最后我们来简单回顾关于比特币上智能合约的一些事实和特点:

  1. 比特币交易的脚本,可以通过设计复杂逻辑来实现智能合约;
  2. 比特币智能合约,只能控制交易包含的比特币,或者在比特币平台发行的自定义资产;
  3. 比特币的智能合约,需要外部输入信息来执行。外部输入的信息,可能是 Trustless (不需要任何信任基础就能相信的)的,也可能不是;
  4. 智能合约的每一次成功执行,都是把它控制的比特币或者自定义资产,全部解锁。all or nothing。

欢迎加入群蜂社,共同讨论和学习。