深入理解比特币交易的脚本

深入理解比特币交易的脚本

 

 

作者:廖雪峰

 

在比特币区块链中,每一个区块都指向上一个区块,这些通过SHA256计算的区块哈希链就是比特币账本不可篡改的基础。

 

在一个区块中,比特币系统用交易(Transaction)来表示一笔比特币交易。一个区块包含至少一笔交易。这些Transaction的Hash通过Merkle Tree计算出所有交易的Merkle Hash,并被包含至区块Hash中,从而实现交易的不可修改。

 

如果我们仔细观察每一笔交易,可以发现,除了第一笔交易是矿工的挖矿所得外,每一笔交易都拥有一个或多个输入(TxIn),以及一个或多个输出(TxOut):

 

第一笔矿工挖矿的收入交易通常被称为coinbase,它没有输入,所以TxIn的Hash总是被标记为00000000...0000。

 

其他的交易,任何一个TxIn都会唯一追溯到区块链上在本区块之前的某个交易Hash,以及索引:

 

通过交易Hash和索引(从0开始),即可唯一确定一个未花费的交易输出——UTXO(Unspent Transaction Output)。这样,每一个Tx Input都和之前的某个Tx Output关联了起来。

 

我们假设在上一笔交易中,Bob给Alice支付了0.15个BTC。

 

由于比特币并没有账户的概念,这一笔交易的输出并没有写上Alice的名字,也没有写上Alice的公钥。

 

那么,Alice想要花费这0.15个BTC,她应该如何证明自己拥有这个UTXO,并且,其他人无法假冒Alice来花费这个UTXO呢?

 

答案是比特币的交易创建的输出其实并非一个简单的公钥地址,而是一个脚本。在Bob给Alice支付0.15个BTC的这个交易中,Bob创建的输出脚本类似:

 

OP_DUP OP_HASH160 abcd1234...9876 OP_EQUALVERIFY OP_CHECKSIG

 

其中,abcd1234...9876是Alice的公钥Hash。整个脚本的意思是,谁能够提供一个签名和一个公钥,让这个脚本运行通过,谁就能花费这笔交易的0.15个BTC。

 

由于创建签名只能使用Alice的私钥,非Alice的私钥创建的签名将无法通过这个脚本的验证,所以,其他人无法假冒Alice来花费这笔输出。

 

一旦Alice提供了一个签名和自己的公钥,她实际上已经创建了另一笔交易来花费这个输出。

 

所有人都可以验证Alice创建的这个新交易是否有效。如果有效,该交易就会被矿工打包进新的区块,从而成为区块链上不可更改的一部分。

 

我们以著名的Pizza Transaction为例,来验证一个交易是否是有效的。

 

在交易cca75078...4d79中,唯一的TxIn输入提供的sigScript是:

 

8b4830450221009908144ca6539e09512b9295c8

a27050d478fbb96f8addbc3d075544dc41328702

201aa528be2b907d316d2da068dd9eb1e23243d9

7e444d59290d2fddf25269ee0e0141042e930f39

ba62c6534ee98ed20ca98959d34aa9e057cda01c

fd422c6bab3667b76426529382c23f42b9b08d78

32d4fee1d6b437a8526e59667ce9c4e9dcebcabb

 

该sigScript实际上由两部分构成:

 

签名:30450221...ee0e01(71字节+1字节签名类型),实际签名是去掉最后一个字节01的30450221...ee0e,签名类型是SIGHASH_ALL(0x01)。

 

公钥:042e930f...cabb(65字节)

 

为了验证该交易是否有效,我们首先要根据TxIn所声明的Previous Output Hash:a1075db5…d48d和索引0找到上一笔交易的输出a1075db5...d48d。

 

这笔交易输出的脚本是:

 

1976a91446af3fb481837fadbb421727f9959c2d32a3682988ac

 

比特币的脚本由一系列指令和数据构成,每个指令占用一个字节,数据由数据头部的长度决定。上述二进制脚本翻译后的比特币指令如下:

 

OP_DUP OP_HASH160 46af3fb4...6829 OP_EQUALVERIFY OP_CHECKSIG

 

现在,我们有了签名,公钥和脚本:

 

sig: 30450221...ee0e01

 

pubkey: 042e930f...cabb

 

script: OP_DUP OP_HASH160 46af3fb4…6829 OP_EQUALVERIFY OP_CHECKSIG

 

就可以运行这个脚本来验证交易是否有效。

 

比特币脚本被设计成以栈来运行的虚拟机指令,它只有有限的几种指令,并且故意被设计成没有循环、条件跳转,所以,比特币脚本不是图灵完备的语言。

 

比特币脚本的执行非常简单。我们首先要准备一个空栈,然后把签名和公钥入栈:

 

 

紧接着,我们就可以执行TxOut的脚本:

 

OP_DUP OP_HASH160 46af3fb4...6829 OP_EQUALVERIFY OP_CHECKSIG

 

首先执行OP_DUP,这条指令把栈顶的元素复制一份,所以结果变成:

 

 

紧接着执行OP_HASH160,它对栈顶元素计算SHA256/RipeMD160,实际上是计算公钥Hash,所以运行结果变成:

 

 

 

接下来的指令实际上是一个数据,我们直接把数据入栈:

 

 

然后,执行OP_EQUALVERIFY,这条指令会比较栈顶的两个元素是否相等,如果不等,整个脚本就执行失败了,如果相等,脚本会继续执行,所以运行结果变成:

 

 

最后,执行指令OP_CHECKSIG,这条指令会验证签名。首先,我们根据签名类型SIGHASH_ALL(0x01)对整个交易进行验证。验证方法是:

 

把当前Transaction的所有TxIn的scriptSig去掉(红色部分),并把当前TxIn的scriptSig替换为UTXO的script(蓝色部分),调整长度字段(绿色部分):

 

 

最后加上小端序4字节的签名类型0x01(灰色部分),计算两次SHA256,我们得到:

 

c2d48f45...2669

 

现在,使用ECDSA算法对签名进行验证:

 

boolean ecdsa_verify_signature(byte[] message, byte[] signature, byte[] pubkey)

 

根据签名的验证结果,我们即可确认该交易是否有效。

 

由于引入了脚本,我们可以看到,比特币实际上通过编程脚本实现了一个严格以计算机程序验证为基础的数字货币所有权的转移机制。由于计算机程序的可扩展性,比特币支付其实并不限定在必须支付给某一个公钥地址。利用脚本,我们可以构造出各种支付条件,例如,多重签名验证条件:

 

2 3 OP_CHECKMULTISIGN

 

这种提供多个公钥地址,并且需要多个签名验证的多重签名脚本,允许在M个签名种至少给出N个签名即可使用。上述脚本允许提供3个公钥地址中的任意两个有效签名。

 

当我们把比特币托管在某个第三方的在线钱包中时,就可以使用多重签名来保证只有自己和第三方钱包共同签名后才可动用输出,这样保证了黑客在攻击了第三方钱包后也无法花掉用户的比特币。

 

通过OP_CHECKLOCKTIMEVERIFY,我们可以指定一个交易的锁定时间,在此之前,该交易输出无法被花掉。这个指令其实实现了支付宝的7天资金锁定然后再支付给卖家的功能。

 

还有一些交易并没有指定一个公钥Hash,例如,这个交易的脚本如下:

 

OP_HASH256 6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000 OP_EQUAL

 

它的意思是说,谁能够提供一个数据,它的SHA256是6fe28c0a...0000,谁就可以花费这笔交易。

 

(注:该交易已经被花费了,有人找到了符合条件的数据)

 

从比特币的脚本,我们可以看到,基于区块链的数字货币支付实际上是数字货币所有权的安全转移。如果我们把金融资产或者实物资产以数字化的形式登记在区块链上,通过脚本就可以安全实现各种条件下的所有权转移,这正是智能合约在区块链上的应用

 

但在比特币中,这个过程是通过 UTXO 实现的,图示如下:

 

 

比特币的区块链账本里记录的是一笔又一笔的交易。

 

每笔交易都有若干交易输入,也就是资金来源,也都有若干笔交易输出,也就是资金去向。一般来说,每一笔交易都要花费(spend)一笔输入,产生一笔输出,而其所产生的输出,就是“未花费过的交易输出”,也就是 UTXO。

 

比特币交易遵守几个规则。

第一,除了 coinbase 交易之外,所有的资金来源都必须来自前面某一个或者几个交易的 UTXO,就像接水管一样,一个接一个,此出彼入,此入彼出,生生不息,钱就在交易之间流动起来了。

 

第二,任何一笔交易的交易输入总量必须等于交易输出总量,等式两边必须配平。

 

上图第一个交易 #1001 号交易是 coinbase 交易。比特币是矿工挖出来的。当一个矿机费尽九牛二虎之力找到一个合格的区块之后,它就获得一个特权,能够创造一个 coinbase 交易,在其中放入一笔新钱,并且在交易输出的收款人地址一栏,堂堂正正的写上自己的地址。在我写文章的这一天(2016年8月9日),这笔比特币的数额规定为 12.5 枚,市价 48,576元人民币。这个 coinbase 交易随着张三挖出来的区块被各个节点接受,经过六个确认以后永远的烙印在历史中。

 

过了几天,张三打算付 2.5 个比特币给李四,张三就发起一#2001号交易,这个交易的资金来源项写着“#1001(1)”,也就是 #1001 号交易——张三挖出矿的那个 coinbase 交易——的第一项 UTXO。然后在本交易的交易输出 UTXO 项中,把2.5个比特币的收款人地址设为李四的地址。

 

请注意,这一笔交易必须将前面产生那一项 12.5 个比特币的输出项全部消耗,而由于张三只打算付给李四 2.5 个比特币,为了要消耗剩下的10比特币,他只好把剩余的那 10 个比特币支付给自己,这样才能符合输入与输出配平的规则。

 

再过几天,张三和李四打算AA制合起来给王五付 5 枚比特币。那么张三或李四发起 #3001 号交易,在交易输入部分,有两个资金来源,分别是#2001(1) 和 #2001(2),代表第 #2001 号交易的第 (1) 和第 (2) 项 UTXO。然后在这个交易的输出部分里如法炮制,给王五5比特币,把张三剩下的 7.5 比特币发还给自己。以后王五若要再花他这5比特币,就必须在他的交易里注明资金的来源是 #3001(1)。

 

所以,其实并没有什么比特币,只有 UTXO。当我们说张三拥有 10 枚比特币的时候,我实际上是说,当前区块链账本中,有若干笔交易的 UTXO 项收款人写的是张三的地址,而这些 UTXO 项的数额总和是 10。因为在比特币系统里,一个人可以拥有的地址资源,可谓取之不尽用之不竭。要知道自己的一大堆地址里一共收了多少 UTXO,人是算不过来的,需要由比特币钱包代为跟踪计算。

 

以上即为 UTXO 的一个简要的介绍。

 

那么UTXO高在哪里?

 

比特币的很多技术点都不是中本聪的原创。比如基于“工作量证明(Proof-of-Work)”的共识达成机制是Adam Back 在 Hashcash 里提出来的,将全部交易计入一本总账、并给交易打时间戳来防范双花攻击(double-spend attack)的思想是 Wei Dai 的 b-money 和 Nick Szabo 的 Bitgold 提出来的,更不用说比特币网络是零优化的大水漫灌式P2P网络,仅就 P2P 技术而言,很多方面还赶不上2001年出现的 BitTorrent 。

 

但是有三个技术点绝对是中本聪原创,一个是区块链的设计,一个是UTXO,一个是智能合约。而这三个设计是极为天才的,被斯坦福大学密码学和计算机安全教授 Dan Boneh 评价为“extremely brilliant”,“必将激发无穷的创新”。

 

当然,但中本聪最了不起的地方并不是这三个单点创新,而是将所有这些技术点跟密码学货币自身特点相结合,设计了一套“惩恶扬善”的经济激励制度,将技术创新与制度设计糅合成一个严丝合缝的体系。

 

在这个体系里,任何人都可以建立一个匿名节点,编写破坏性的代码,然后实施匿名攻击,即便你攻击得手、偷来大笔财富,也不会暴露身份,所以可以逍遥法外。

 

这个系统赤身裸体,开门揖盗,任由你攻击破坏,甚至如果你成功的突破防线偷来一大笔财富,整个比特币体系不但不会惩罚你,还会坚定的保障你的赃款。然后悬赏100亿美金,运行七年,至今为止,在主干区块链上,没有发生一起成功的攻击,一次都没有。

 

中本聪把比特币设计得跟数学原理一样漂亮,很多后来者连抄都抄不到这个水平。我想这就是为什么加州大学洛杉矶分校的金融学教授 Bhagwan Chowdhry会提名中本聪为2016年度诺贝尔经济学奖候选人。我相信中本聪在比特币里的很多设计思想,以及整个比特币开发者社区所做的大量改进,不仅是区块链的开山之作,而且也会成为IT系统设计的一个创新思想源泉。

 

UTXO 的设计就很值得玩味。在《什么是UTXO》一文中对其设计方案进行了介绍。本文要讨论的是UTXO 的优点和不足。

 

中本聪为什么要把比特币设计成这样呢?考虑到他应该也不是从未来穿越回来的人物,以常理推论,他一开始应该也是从基于账户的系统出发来设计的,但他后来决定切换到UTXO方案,一定是遇到什么问题。

你可能感兴趣的:(bitcoin)