揭秘比特币和区块链(四):比特币的交易 [zz]
原文转自:InfoQ
在比特币区块链中,交易是最核心的内容。通过前面的讲述,我们知道,比特币通过基于密码学的公私钥体系,交易的发起者可以使用自己的私钥对交易进行签名,其他人可以使用其公钥进行验证,这就从数学上保证了用户资金的安全。那么其交易具体是怎么构建的呢?
简化模型
在中本聪的白皮书里,比特币被定义成一个链式的数字签名串。币的拥有者通过对前一次交易和下一次拥有者的公钥签署一个数字签名,并将这个签名附加在这笔交易的当中,来完成一笔转账。而转账的收款人通过对签名进行验证,就能够验证该链条的所有者是不是发送方。
交易的运作图如下:
这样设计的交易体系的问题在于收款人很难校验之前的某位资产拥有者是否进行了双重支付(双花)。通常的解决方案是引入可信的第三方,如银行,来对每一笔交易进行检验,以防止双重支付。而如果想要排除第三方中介机构,那么交易信息就应当被公开,需要整个系统内的所有参与者,都有唯一公认的历史交易序列。收款人需要确保在交易期间绝大多数的节点都认同该交易是首次出现。
账本系统不以“账户”为基础
比特币区块链本质上可以说是一个基于互联网的去中心化的账本系统,而这个账本上记载的,就是一笔笔比特币地址之间的转账交易,一笔具体的交易过程如上面所示,那整个系统该如何构建呢?。
常常有一种简单化的说法,将比特币公钥类比为用户的银行卡号,也即用户的账户。那么最容易想到的交易系统的记录方式是以账户为基础的,简化的示意图类似这样:
这种记账方式是最容易想到的,然而比特币区块链并没有采用这种方式。重要的事情说三遍,比特币的交易系统不是这样的,不是这样的,不是这样的。原因很简单,如果采用这种记账方式的话,每当要进行一笔新交易的时候,系统都不得不回溯该所有交易历史,这样才能确定最新的这笔交易是不是合法,如上图所示,用户C有这些钱吗?当系统庞大、交易数量众多的时候,每次都进行这样的检验无疑是笨重低效的。
那么比特币的交易系统是怎样构建的呢?
UTXO是比特币交易的基本单位
UTXO(Unspent Transaction Outputs)是未花费的交易输出,它是比特币交易生成及验证的一个核心概念。交易构成了一组链式结构,所有合法的比特币交易都可以追溯到前向一个或多个交易的输出,这些链条的源头都是挖矿奖励,末尾则是当前未花费的交易输出。所有的未花费的输出即整个比特币网络的UTXO。
比特币规定每一笔新的交易的输入必须是某笔交易未花费的输出,每一笔输入同时也需要上一笔输出所对应的私钥进行签名,并且每个比特币的节点都会存储当前整个区块链上的UTXO,整个网络上的节点通过UTXO及签名算法来验证新交易的合法性。这样,节点不需要追溯历史就可以验证新交易的合法性。
交易的输入与输出
比特币的交易,并不是通常意义的一手交钱一手交货的交易,而是转账。如果每一笔转账都需要构造一笔交易数据会比较笨拙,为了使得价值易于组合与分割,比特币的交易被设计为可以纳入多个输入和输出。即一笔交易可以转账给多个人。从生成到在网络中传播,再到通过工作量证明、整个网络节点验证,最终记录到比特币的区块链,就是交易的整个生命周期。
交易的本质是一个包含交易发送方、接收方、资产转移等相关信息的数据结构,其数据结构如下:
字段 | 描述 | 大小 |
---|---|---|
版本 | 这笔交易参照的规则 | 4 字节 |
输入数量 | 交易输入列表的数量 | 1 - 9 字节 |
输入列表 | 一个或多个交易输入 | 不定 |
输出数量 | 交易输出列表的数量 | 1 - 9 字节 |
输出列表 | 一个或多个交易输出 | 不定 |
锁定时间 | 锁定时间 | 4 字节 |
从整体结构来看,交易主要的两个单元字段就是交易的输入与输出。输入标识着交易的发送方,输出标识着交易的接收方及对于自己的找零,交易的手续费则是输入的总和与输出的总和之差。由于所有的交易输入必然是前面某笔交易的输出,所以交易最核心的字段是交易的输出。
一笔交易的数据结构图如下所示:
比特币的交易输入(TxIn)有三种,分别是Standard TxIn(标准输入)、Spend Coinbase TxOut(花费挖矿奖励)、Coinbase/Generation(产生挖矿奖励),下图分别描述了这三种TxIn的结构:
比特币的交易输出(TxOut Script)有两种,分别是Standard TxOut (标准交易输出)、Coinbase TxOut (挖矿奖励输出),下图分别描述了这两种TxOut的结构:
脚本
脚本是交易里另一个比较重要的技术。每一笔交易的每一项输出严格意义上并不是指向一个地址,而是指向一个脚本。脚本类似一套规则,它约束着接收方怎样才能花掉这个输出上锁定的资产。
交易的合法性验证也依赖于脚本。目前它依赖于两类脚本:锁定脚本与解锁脚本。锁定脚本是基于可变的模式,通过一段脚本语言来实现,位于交易的输出。解锁脚本与锁定脚本相对应,只有按锁定脚本的规则去解,才能花掉这个脚本上对应的资产,位于交易的输入。脚本语言可以表达出无数的条件变种。这也是比特币作为一种“可编程的货币”所拥有的特性。而解释该脚本是通过类似我们编程领域里的“虚拟机”,它分布式运行在比特币网络里的每一个节点。
比特币的脚本目前常用的主要分为两种,一种是普通的类型P2PKH(Pay-to-Public-Key-Hash),即支付给公钥的哈希即地址,接收方只需要使用地址对应的私钥对该输出进行签名,即可花掉该输出。另一种是P2SH(Pay-to-Script-Hash),支付脚本的哈希。拿多重签名来举例,它要求该输出同时要有N把私钥中的M把私钥(M<=N)同时签名才能花掉该资产,它类似于现实生活中需要多把钥匙才能同时打开的保险柜,只是更加灵活。
比如在比特币中,P2PKH的脚本规则如下:
Pubkey script: OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG Signature script: <sig> <pubkey>
P2SH的脚本规则如下:
Pubkey script: OP_HASH160 <Hash160(redeemScript)> OP_EQUAL Signature script: <sig> [sig] [sig...] <redeemScript>
在上述的2种脚本规则里,Pubkey script代表着锁定脚本,Signature script代表着解锁脚本。OP_开头的单词是相关的脚本命令,也是”虚拟机”所能解析的指令。这些命令规则根据Pubkey script的不同来进行划分,它也决定着解锁脚本的规则。
比特币中的脚本机制相对简单,只是一个基于堆栈式的,解释相关OP指令的引擎,能够解析的脚本规则并不是太多,不能实现很复杂的逻辑。但它为区块链可编程提供了一个原型,后续一些可编程区块链项目其实是基于脚本的原理发展起来的,比如以太坊,就是深入强化了脚本机制,脚本机制里不再单单是简单的OP指令,而是支持脚本语言,该脚本语言可以通过”虚拟机”去执行。以太坊实现了一个支持图灵完备脚本语言的区块链平台。
脚本的机制对于区块链来说非常重要,它类似于区块链技术提供的一个扩展接口,任何人都可以基于这个接口,去开发基于区块链技术的应用,比如智能合约的功能。脚本机制也让区块链技术作为一项底层协议成为可能。未来很多基于区块链的颠覆性应用,都有可能是通过区块链的脚本语言来完成的。
以上简述了比特币区块链中交易的过程和相关的重要概念。限于篇幅,在这里省略了一些可以拓展的内容。到目前为止,我们讲述的内容,包括上一节讲述的公私钥,都是与用户的使用直接相关的。关于区块链的共识机制、系统安全等广大读者关心的问题,我们会在之后的文章中为您讲解。