在我们前面的文章中,我们提到,从建设银行转账到工商银行10w元,过程其实是这样的:
- 建设银行发送报文到人行CNAPS系统
- 人行CNAPS发送转账报文到工商银行
- 工商银行发送响应报文给人行CNAPS
- 人行发送响应报文给建设银行
- 转账成功,建设银行、人行、工商银行各自更新账本
整个过程中,有几个很有趣的事实:
- 所谓的转账交易,不过是账本上数字的加加减减
- 我们的账户,除了各自在工行、建行开设的户头之外,在人行还有一个总账;人行是所有银行的妈,你在任何银行开设的账户,人行都有一个总账;所以打印征信的时候我们要到人行打印
- 建设银行和工商银行间的转账需要人行做清算,人行提供了信用;建行和工行相信人行不会造假
- 我们需要信任三个机构:人行、工行、建行,我们相信他们不会造假
- 人行是所有账目的中心节点,人行的账本对不上了,中国的金融系统就乱套了
然后作为对比,我们来看看比特币是怎样设计的。
中本聪创造比特币之初,在Genesis Block里面付了一句有名的话:”The Times 03/Jan/2009 Chancellor on brink of second bailout for banks”。在白皮书中他很自豪的宣称:”We have proposed a system for electronic transactions without relying on trust. “ 去中心化一直是比特币的指导纲领,那么问题来了,如果让我们来设计一个去中心化的账本,将会面临哪些技术问题,又该如何解决呢?
很自然的,我们设想的是一个类似于分布式数据库的系统,整个系统维护着唯一的账本,每个节点(node)都是一个副本(Replica Set),每个副本保有完全的账本数据,并且节点间相互同步数据,如果部分节点挂掉,不影响整个系统的运行。
用户转账的行为,其实就是这个分布式账本的增删查改。当然,为了简化设计,我们这个账本可以只支持账目写入,不支持删改。
我们开始思考这个分布式账本要解决的两个核心问题:
什么样的交易是一笔合法的交易
- 一笔交易中,如何保证交易账户的完全所有权;如果保证用户A的资金不会被用户B盗用
- 用户A本来有1000元,如何保证他不会转出2000元?
哪个节点有记账的权力,如何保证整个账本是唯一且不可篡改的
- 如果有部分节点是不诚实的,它就会有动机去伪造不存在的交易来获取利益,如何识别并排除不诚实的节点?(拜占庭将军问题)
- 如果A的账户有1000元,发送了1000元给B,由于是分布式系统,部分节点收到了这笔交易,这时候A又发送了1000元给C,另一部分收到了这笔交易,这时候该如何处理?如何保证一笔钱不会被花两次? (双重支付问题)
为了解决这两个问题,比特币引入了三个核心技术:UTXO交易模型、POW工作量证明、blockchain数据结构组织。且让我们一一道来。
初版交易设计
如果读了之前我们的<比特币hd钱包>系列文章;天然的,我们意识到非对称加密方法是在分布式账本中建立账户的天选之术;比特币hd钱包>
存款
用户A想要建立一个账户,只要在帐目中增加一笔 公钥+金额
的记录就可以了。我们用一个表格表示整个账本,用户A以及用户B各存入50个币的动作可以记作:
账目ID | 原始交易细节 |
---|---|
1 | Trans1:存入(A公钥+50) |
2 | Trans2:存入(B公钥+50) |
这个原始存入的资金我们先不去纠结怎么来的,总之此时账本中有两笔交易,代表着A以及B各自有50个币
验证
在账目1中,如何验证A确实是这笔资金的拥有者呢?非常简单,就是账户资金增加的时候,A对这笔交易数据的摘要用私钥做一个签名,然后再把公钥附在后面就可以了,这样账目就变成了这样:
账目ID | 原始交易细节 | 所有权证明 |
---|---|---|
1 | Trans1:存入(A公钥+50) | signature(digest(Trans1))+A公钥 |
2 | Trans2:存入(B公钥+50) | signature(digest(Trans2))+B公钥 |
任何一个要验证账户A的节点或第三方,对其所有权证明用公钥解密,然后对照摘要(digest)即可。
转账
如果A要向B转账20个币呢,我们最简单的设计,就是构造Trans1 - 20,然后同样的方法构造签名即可,这样账本如下:
账目ID | 原始交易细节 | 所有权证明 |
---|---|---|
1 | Trans1:存入(A公钥+50) | signature(digest(Trans1))+A公钥 |
2 | Trans2:存入(B公钥+50) | signature(digest(Trans2))+B公钥 |
3 | Trans3:Trans1-20 -> B | signature(digest(Trans1 - 20 -> B))+A公钥 |
4 | Trans4:存入(B公钥+20) | signature(digest(Trans4))+B公钥 |
看起来一切还好,但是这个时候我们发现了一些缺点
- 收到汇款的时候因为要添加所有权证明,账户拥有者得一直在线监控自己的账户地址
- 收款人还得验证汇款人的合法性,感觉都点怪;我收钱就好了,还得去管这个钱合不合法?
- 如果多重转账,或者一对多,或多对一,这个记录格式就复杂了
- 用户B要验证一笔交易合法性的时候,可能要回溯到账本非常深的位置,因为上一笔交易可能发生在很久之前,这种交易记录的存储设计很难高效查询
- 最后,这个账目设计中,所有账户的公钥是暴漏在外的;虽然椭圆曲线算法目前看来牢不可破,但是整个安全体系只依赖一个非对称加密算法,比较脆弱
解决方法其实也简单,换个思路,就是A转账给B,B是不需要验证的,只要A提供账户所有权的证明就好了,想想我们平时转账,不也是这样的吗?
那么最简洁的设计,就是借鉴现实世界。每一笔交易都看作是硬币的流转,硬币其实没有特征,它只是从A的保险箱转移到了B的保险箱而已,那么,采用什么办法来表示:这是A的保险箱中的一笔资金币
这个譬喻呢?
进阶交易设计
UTXO 模型
比特币的账本世界,构筑在UTXO (Unspent Transaction Output)之上;其实每个UTXO代表着未花费的一笔硬币(数额可大可小,没有限制);一个账户的资金,其实就是一堆UTXO的集合;转账交易,就是一个或多个UTXO的输入再输出为另外的UTXO而已。你可以想象成现实世界中金银铸币的流通。
那么一个UTXO中包含什么呢?如何作为输入呢?如何构造输出呢?这就是比特币交易的核心技术。
- 我们用下面一张图来表示
A保险箱里面的50个硬币
这件事:
把它想象成一个邮筒构造的保险箱,在不打开的前提下,投币是只进不出的。可以注意到,我们并没有直接将Public Key明晃晃暴露在外面,而是先HASH一下,然后贴到保险箱子上面,想要存币的人,只要知道这个HASH值,作为保险箱的ID,就可以直接投币进去啦。
但是保险箱的锁在哪里呢?
- 这张图中,我们引入了一个脚本,称之为
Pubkey Script
;具体内容是:
1
|
|
呵呵,像天书吧,不要怕;这是我们特有的保险锁构造。细节会在后面讲到。这里你可以这样简单理解:
为了锁住这个保险箱里的资金,比特币系统设置了一个谜题作为锁。解开这个谜题,才能转移里面的资金。
这个谜题是这样构造的:
- 记录了A的公开的
Public key hash
值,开锁的人,需要提供A的full public key
,同时验证hash160(public key) == Public key hash
- 需要提供A的私钥基于这笔交易的签名Signature, 这样系统可以用
full public key
来验证公私钥是否匹配
这个过程是通过上面的脚本指令通过入栈出栈执行的,这也为比特币系统验证更复杂的交易逻辑提供了基础,甚至能作为一个简单的虚拟机执行更复杂的组合指令。
整个过程组织如下图:
当我提供一个signature以及full public key的时候,就可以开锁了,开锁下一步自然就是转移资金啦。我们给B汇款50个币,而B的保险箱又是怎么表示的呢?和A保险箱是一样的。
-
带有
public key hash
ID的保险箱是一个UTXO,这个保险箱用public key hash
上锁,而提供signature
和full public key
开锁,转移资金的过程,就是花费UTXO的过程,其实就是把A的UTXO转移到B的UTXO的过程,这就是比特币最简单的一笔交易 -
我们可以继续拓展下去,可以1对多支付,多对1支付,多对多支付,更复杂的多签名支付,延迟支付等等,今后我们会详细介绍
这个系统有如下优点:
- 所有的交易都抽象为了UTXO的转移,你可以想象一下,一堆硬币在几个保险箱之间转移的样子
- 用户其实可以不检查交易的合法性,只要运行分布式账本的所有节点检查通过合法后,确保写入账本就保证资金的安全转移了
- 每个账户的拥有者在真正花费UTXO之前,是不用暴露公钥的
- 验证UTXO交易合法行的函数,抽象为几个指令的集合,这个验证行为指令通用化,为智能合约编写创造了条件
- 这样的交易记录非常容易组织,我们以后可以看到;把这些交易批量打包,组织成名为blockchain的精巧数据结构,有许多优点
- 一个用户A可以用一个私钥加密多个保险箱,或者多个私钥加密多个保险箱,非常灵活
小结
好啦,看到这里,我们对比特币的最简单的交易构造已经有感性认识了。但是俗话说得好: 光说不练假把式
,下篇文章我们就会手工构造一笔完整的交易,让你搞明白其中细节。
另外,我们前面提出了好几个问题:
- 原始资金从何处来?
- 节点如何解决拜占庭将军问题?
- 节点如何解决双重支付问题?
后面我们会一一解答,那么,下次再见。