Skip to content

第六章:处理更复杂的交易

ch06

经过多次升级后,Q币已经完全是去中心化的了,它的账本由遍布全球各地的成千上万个节点共同维护。任何人,哪怕是Q公司自己,都无法操纵这个分布式账本。密码泄漏、交易篡改、交易删除、交易监管、服务宕机等问题,都一一解决。不仅如此,围绕Q币还产生了一个庞大的生态系统。包括开发热钱包的软件公司、开发冷钱包与矿机的硬件厂商,以及矿池服务等。还有无数人的心情跟着Q币每四年一次减半的周期而波动。

那么Q币系统已经完美了吗?当然不是,这世界上就不存在完美的系统。在本章,Q公司会对Q币系统进行几个比较小的改进,让它可以更好的保护用户隐私,以及执行更复杂的转账交易。在下一章,Q币系统将迎来又一次史诗级的升级,敬请期待。

隐藏公钥

还记得吗?目前Q链的设计是直接在输出列表里放上收款方的公钥。由于Q链持续火爆,出于各种目的想方设法攻击它的黑客也越来越多。这个设计将公钥过早地暴露出来,并不是很好。为了改善这些问题,Q公司引入了地址(Address)的概念,它是公钥的泛化版。第一版的地址格式如下图所示:

address

简单来说就是把公钥进行一次哈希运算。但为了保持兼容性,我们在哈希值后面拼接一个字节(数字1),作为版本号。这样,我们可以通过长度来区分公钥(32字节)和地址(33字节)。长度一样时,还可以通过版本号来区分不同类型的地址。有了地址的概念,我们就可以对交易格式进行升级了。改动非常小,只是把公钥换成地址,如下图所示:

tx

由于我们可以通过交易数据和签名恢复出对应的公钥,于是我们把公钥推迟到了输出被使用(而不是生成)时才暴露。那么这个改进具体有哪些好处呢?

第一,缩小了潜在的攻击面。我们知道非对称加密是非常难破解的,但也不是无懈可击。比如说ECDSA算法,如果同一私钥对两条不同消息签名时错误使用了同样的随机数,那么攻击者可通过这两个签名反推出私钥。虽然Q币钱包等一般会严格保证随机数的唯一性,但是通过哈希值隐藏公钥提供了多一层的保护,减少了被针对性攻击的可能性。

第二,带来了一定的隐私性。Q链上的交易数据都是公开透明的,任何人都可以看到。我们可以轻易追踪某个公钥在链上的所有过往行为。而仅通过地址(公钥哈希值),无法反推出对应的公钥。这样,某个公钥的行为可以推迟到它第一次花Q币时才暴露,有限地提升了匿名性。

第三,支持更多的交易类型。目前Q链只支持简单的转账,把公钥泛化为地址也为添加更多的交易类型提供了可能性。我们在下一小节会讨论简单多签交易,在下下小节会讨论更复杂的多签交易。

第四,可以减少交易字节数。如果采用输出长度更短的哈希算法,我们就可以得到更短的地址。比如RIPEMD-160哈希算法的输出长度为20字节,相比32字节的公钥,可以节约12字节的空间。地址变小,交易就变小了,继而整个区块也就变小了,这样就可以提升交易和区块在Q链网络中的传播与存储效率。

多签交易

由于Q链完全是去中心化运行了,Q币价格暴涨,很多游戏工作室也开始在Q链上打金。相比个人玩家,这些工作室往往掌握着数额巨大的Q币。还有一些人开始囤积Q币,也积攒了可观的财富。我们称这些拥有大量Q币的用户为巨鲸(Whale)。

为了避免损失资金,这些巨鲸希望自己的Q币可以由多个(比如三个)公钥共同控制,只有这些公钥一起签名才能发起交易。这样即使其中一些私钥不慎泄漏,只要还有一个私钥还是安全的,账户也仍然是安全的。我们把这样的交易叫做多签(Multi-Signature,通常简称Multi-Sig)交易。为了支持多签交易,Q链引入了一个新的地址格式,版本是2,如下图所示:

address2

上图中红色的数字2是地址的版本号,后面一个字节记录该多签地址对应的公钥数量,在这个例子里是3。我们把公钥按顺序拼接在一起(1),然后计算哈希值(2),后面再跟上版本号和公钥数量(3),就得到了多签地址。那么怎么花掉多签地址里的Q币呢?我们需要一个新的交易格式,如下图所示:

tx2

我们要求新版的交易有且只有一个输入,而且对应一个多签地址。注意我们不需要给交易添加版本号,因为我们可以通过输入数量和输入对应地址的版本号判断出这是不是一笔多签交易。老版的交易只要有一个签名就可以了,而多签交易需要有多个签名。多签地址由几个公钥生成的,交易里就应该有几个签名,而且签名用的私钥和计算地址时的公钥顺序必须一致。多签地址的恢复过程如下图所示:

recover2

执行脚本

但是上面的多签交易并不是很灵活。比如说某个打金工作室有三个老板,共同控制着一个Q币账号。他们希望达到这样一个目的:只要其中任何两个人签名,就可以动用里面的Q币。这也是多签交易,为了和前面那种简单的多签交易区分,我们通常把这种交易叫做m-of-n多签交易。就这个例子而言,工作室需要的是一个2-of-3多签交易。

这种交易是非常灵活的,用普通的方式根本就搞不定。为了解决这个问题,以及为了应对更复杂的交易类型,Q链引入了执行代码的机制。我们先来看一下新的地址格式,版本是3,如下图所示:

address3

注意看,我们把公钥直接替换成了一段脚本(Script,一般指较为简单的程序)。用它算出哈希值以后,再拼接数字3,就得到了新版地址。公钥脚本里放的是一小段代码,起到和公钥差不多的作用,但是里面可以写复杂的逻辑。既然公钥变成了公钥脚本,那么私钥也相应地变成了私钥脚本。与新版地址对应的交易格式如下图所示:

tx3

原先,验证交易签名的逻辑是硬编码(Hardcode)在Q链节点的代码中的。现在,我们把这一部分逻辑移出来,由公钥脚本和私钥脚本一起配合完成。以m-of-n多签交易为例,公钥脚本可以描述共有哪些公钥、至少需要几个签名,私钥脚本可以描述有哪些私钥进行了签名,然后两个脚本一起验证签名数量是否达到阈值。

在收到这种交易后,Q链的节点需要把这两段脚本组装起来,然后交给一台虚拟的计算机(Virtual Machine),简称虚拟机(VM),去执行脚本里面的指令,最终确认交易是否合法。通过这种方式,我们不仅可以支持m-of-n多签交易,还为执行各种复杂交易提供了技术基础。比如说,我们可以引入时间的概念,限制一笔输出在一定时间(例如两周)后才能被花掉。总之,从此刻起,Q链具备了执行程序的能力。

停机问题

什么是停机问题?如果大家没有学过计算机编程的话,这里可以进行一个简单的科普。一个计算机程序(或者说一段代码),不管它的逻辑有多么复杂,都是由三种基本的结构组成的:顺序、分支、循环。可以想象一下我们开着车行驶在路上,如果一路前进就好比顺序结构,如果遇到分叉路口需要选择就好比分支结构,如果遇到环线一直绕圈就好比循环结构。顺序、分支、循环这三种结构如下图所示:

structure

程序是需要由计算机来执行的。如果某台计算机支持全部这三种结构,那么为这台机器编写的程序就可以表达任意复杂的逻辑。换句话说,这台计算机具备模拟其他任何计算机的能力。为了纪念最早提出这个理论的计算机先驱图灵,我们称计算机这种可以执行任意逻辑的能力为图灵完备(Turing Complete)。

现在来考虑这么一个问题。假如有一台图灵完备的机器,然后有一个人编写了一个恶意的程序,最终的结果是这个程序一旦运行起来就不会停止,会一直循环下去。那么我们可以不可以写另外一个程序,来帮助我们判断某个程序是不是恶意程序(也就是一旦机器开始跑这个程序最终能不能停下来)?这个就是计算机科学中著名的停机问题(Halting Problem)。那么答案呢?图灵早已经给出了证明:我们无法写出通用的分析程序。

所以如果有坏人在Q链上提交了一笔恶意交易,里面有恶意的死循环脚本,Q链是无法提前分析出来的。结果就是这笔恶意交易会被某个节点接收,打包进块,然后被广播到整个Q链网络中。然后某一天这笔交易中的恶意脚本被触发,全网节点都陷入死循环,无法对外提供任何服务。这种耗尽服务器某种资源使其无法对外服务的攻击行为称为拒绝服务(Denial of Service,简称DoS)攻击。

你是否接到过骚扰电话?想象一下,如果工作日频繁接到陌生电话,有的推销产品,有的响一声就挂,手机线路被占、注意力被扰,客户来电接不到、工作思路被打断,根本没法正常办公,其实这就是生活中的“拒绝服务攻击”。就像黑客用无效请求占满服务器资源,骚扰电话也用无意义呼叫抢占你的通讯与时间资源,最终让有价值的正常需求彻底无法实现。我们只能把这些恶意号码逐一拉黑,让手机重新回归畅通,这样工作与生活的节奏才能回到正轨。

那么停机问题有解吗?没有通用解,但是在Q链上可以采用一些特定的解决办法。这里Q公司采取了一种简单粗暴的解法:直接禁止循环结构。没有循环结构,自然也就无法写出死循环程序了。由于这个原因,我们说Q链节点执行脚本的虚拟机是非图灵完备的。在下一章,我们会看到另外一种更优雅的解法,可以在基本保持图灵完备的情况下解决这个问题。

顺便说一下,为了避免黑客通过发送包含大量顺序和分支结构的脚本来攻击网络,Q链把交易的大小(字节数)和手续费进行了挂钩。由于只有顺序和分支结构,交易逻辑的复杂性、交易数据的大小,以及交易的最低手续费,这三个量现在呈正比关系。

本章小结

在这一章,Q公司对Q链网络进行了一些小的升级。首先,公钥被地址取代,既减少了攻击面,又增加了隐私性,还给新的交易类型提供了可能性,可谓一举三得。在此基础上,增加了对简单多签交易的支持,允许多人共同控制一个账号。最后,引入了脚本的概念,使得更复杂的交易(例如m-of-n多签交易,时间锁交易等)成为可能。从公钥到地址,再到公钥脚本,Q链处理交易的能力得到了大幅提升。

然而为了解决停机问题,Q链节点采用了非图灵完备的虚拟机。简而言之,Q链目前仍然只能处理转账交易,只不过可以处理比之前复杂得多的转账交易。如何突破这个限制,让Q链可以执行任意复杂的脚本?这是接下来要讨论的问题。在下一章,我们将会看到Q链又一次关键的转变,并带动一个全新生态环境的快速发展。

本书以 CC0 1.0 协议发布,可自由使用