交易 Transactions
“交易”是用户使用比特币的过程。每个交易由几个部分构成,一个交易即可以是简单的直接支付,也可以是复杂的交易。本小节会描述交易的每一个部门,而且说明怎样把各个部分合起来构建成一个完整的交易。
为了简单起便,本小节假设 coinbase transactions 不存在。 coinbase transactions只能被矿机创建并且这些交易是下面很多规则的例外。与其一一指出 coinbase transactions交易的例外,我们更加建议读者阅读本指南”区块链”一章里面关于 coinbase transactions的内容。
上面的图标说明了比特币交易的核心部分。每个交易至少由一个input和一个output。每个input 使用上一个oupt的比特币作为输入。每个output作为未花费的output【Unspent Transaction Output (UTXO)】等待着,直到一个最近的inptut使用这个output。当你的比特币钱包告诉你余额有10BTC时,它真正的意思是说你有10BTC在一个或者多少UTXOs等待被花费出去。
每个交易的前缀由四个字节的“交易版本序号”组成,这可以让比特币节点和矿工知道本交易适用于哪些规则。这也方便开发者未来开发出的新规则和旧规则能相兼容。
下面的图帮助你了解交易的一些特点,图示的工作流是ALICE发送了一个交易给BOB,稍后BOB又把这个交易发送出去。ALICE和BOB使用的都是最常见的标准交易类型,Pay-To-Public-Key-Hash (P2PKH)。P2PKH 让ALICE可以把比特币发送到一个典型的比特币地址上,然后又让BOB可以进一步通过简单的密钥对把比特币发送出去。
在ALICE创建第一笔交易前,Bob必须先生成公钥/私钥对。标准的比特币私钥是长度为256b的随机字符串。一份私钥的数据,最后会经过变成而成“公钥”。因为那个变形可以在稍后重复进行,所以公钥并不需要保存。
接着公钥将加密并未得哈希值。公钥的哈希值同样也可以再次求出来,所以也不需要保存。哈希值比较短,而且也经过混淆,使得手工抄写比较简单,而且也提供了对抗未知问题的安全性,这些未知问题如允许在往后的日子里面通过公钥重新构造成私钥。
BOB把公钥的哈希值提供给ALICE。公钥哈希就是大家所熟知的编码过的比特币地址,编码采用的base58进行,里面包含了一个版本序号、哈希值以及一个用来校验错误的值。比特币地址可能通过任何介质传播,当然也包括单向的介质,这样可以切断发款人和收款人的联系,比特币地址还可以被进一步编码成其它的格式,比如包括”bitcoion:”的二维码地址。
只要ALICE拿到地址,而且解码还原为原来的标准哈希值,她就可以创建第一笔交易了。她创建了一个标准的P2PKH交易输出,里面包括了可以让任何人花费这笔输出的“说明”,只这他能证明他拥有与BOB的公钥对应的私钥。那些说明,称为“script”。
ALICE广播那一笔交易并且把它添加到区块链。比特币网络会收集这一笔交易,并把它作为未花费的交易【Unspent Transaction Output (UTXO),】,并在bob的钱包软件显示为可以使用的余额。
未来,如果bob决定把那个UTXO用出去,他必须创建一个引用了ALICE创建的交易的哈希值(这个哈希值被称为交易标识(txid)),而且还要引用ALICE使用过的那一笔的输出索引。BOB必须创建一个“scriptSig”, scriptSig是指一个包括满足ALICE之前那笔交易设置的条件的数据集合。
Bob并不需要和ALICE进行沟通,BOB只要简单地在比特币点对点网络上证明,他可以满足那些script指定的条件就可恼。对于P2PKH类型的输出,BOB的scriptSig只需要包含下面两个条件即可:
1. 他提供的完整公钥(未经过哈希运算),以便于script 可以通过重新求得哈希值来验证ALICE提供的哈希值是否一致。
2. 一个用bob提供私钥采用 ECDSA 加密算法计算出的包含确定的交易数据的签名。这个签名用来验证BOB是否拥有那个生成公钥的私钥。
Bob的签名不仅仅是证明BOB拥有他的私钥,签名同时还保证了BOB的签名不被篡改,这样就可以在比特币P2P网络安全地进行广播。
如上图所示,bob的签名包括了txid和前一个交易的输出索引、前一个交易的script、bob创建的可以让下一个接收者花费它这个output的script、总共要转给下一具接者的比特币数量。本质上来说,整个交易都被签名除了scriptSigs,因为scriptSigs持有了公钥以及相关的signatures。
把他的signature 和公钥放到scriptSig后,BOB通过P2P网络广播这一笔交易给比特币矿机。在进一步广播以及被包含进区块链之前,每一个节点和矿机都独立地验证这一笔交易。
P2PKH Script Validation
验证的过程需要重新评估script。在一个P2PKH类型的output里面,script 如下:
OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG
发送者的 scriptSig 是经过验证的,而且也是script的开头部分。在一个标准的P2PKH 交易中,scriptSig 包含了一个signature 以及一个完整公钥创建的字符串连接:
OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG
script 语言是一种类似Forth的基于堆栈的语言,它是故意设计成与状态无关且是”图灵不完备”(Turing complete 图灵完
备)的。与其它状态无关保证了只要交易一写入到区块链,就没有其它条件可以把使其永远不可以花费出去。”图灵不完备”可以使得script 语言少了些灵活性,而且预测性更加地好,这极大简化了安全模块。
为了测试一个交易是否合法,一次只把一个scriptSig 和 script的参数推入到堆栈里面去,从bob的scriptSig 开始,以Alice的 script结束。下面的图展示了怎样检验一个标准的 P2PKH script;图示下面是这个过程的描述。
· signature (由BOB的scriptSig生成)被添加到一个空栈里面。因为只是一些数据,所以只是简单地把这些数据添加到栈,并没有做其它东西。公钥(同样也从scriptSig获得)被添加到signature的上面。
· 从ALICE的script里面,操作 OP_DUP被添加到堆栈。 OP_DUP用下一层的数据把自己替换掉,这样就把BOB提供的公钥复制了一次。
· 接着继续操作一下个,OP_HASH160,用下一层的数据(也就是BOB的公钥)把自己替换掉。这样就创建了BOB公钥的哈希值。
· 接着Alice的 script 把从她和BOB的第一笔交易得到的公钥哈希添加到堆栈里面。这样,堆栈顶部就有两份BOB的公钥哈希了。
现在事情变得有趣起来:Alice’的script把OP_EQUALVERIFY 添加到堆栈里面,OP_EQUALVERIFY 可以展开为 OP_EQUAL 和 OP_VERIFY(隐性地)。
OP_EQUAL (隐性地)检查它下面的两个值;在这个例子里,它会检查BOB提供的完整公钥生成的公钥哈希是否和ALICE创建的交易#1相等。OP_EQUAL 接着比较的结果:0(false)或者1(true)替换掉。
OP_VERIFY (隐性地)马上检查它下面的值。如果值为false,则马上停止堆栈内的检查,宣告交易检验失败。否则,它会把自己以及true值抛出栈外。
· 最后,ALICE的 script 把 OP_CHECKSIG压入堆栈,用以对BOB提供的signature 和BOB提供的当前经过验证的公钥进行校验。如果signature 符合公钥,OP_CHECKSIG会被 替换成true;
P2SH脚本
输出脚本由支付者创建,他们(钱花出去之后)不怎么关心他们消费的比特聪的长期安全或者对别人是否有用。收款人则关心输出脚本指定的条件。如果收款人愿意,他们可以请求支付者使用某种特定脚本。遗憾的是,定制的脚本没有短小的比特币地址方便,也不像P2PKH的公钥哈希方案( P2PKHpubkey hashes)那样容易保护。
为了解决这些问题,“支付到脚本哈希”(P2SH)交易在2012年被创建,它让支付者创建一个输出脚本,里边包含另一个脚本的哈希,另一个脚本称为“认领脚本”。
下图是基本的P2SH流程图,它看起来几乎与P2PKH流程一模一样。Bob随心所欲创建一个认领脚本,计算它的哈希,并把这个哈希值发给Alice。Alice创建一个P2SH风格的输出,其中包含Bob的认领脚本的哈希值。
当Bob想花费这个输出时,他把他的签名和完整的(序列化的)认领脚本放在输入的scriptSig域。比特币网络会确认,认领脚本被哈希后,得到的值与Alice输出里放的脚本哈希相同。然后网络会像处理原生脚本(即由Alice提供的脚本)那样,处理认领脚本,如果返回值为真,则允许Bob花费这个输出。
认领脚本的哈希和公钥哈希有相同的属性(主要指长度和范围),所以它可以被转换为标准的比特币地址格式,除了加上一点点小的变化,把它和标准地址区分开。这让接收P2SH风格的地址就像接收P2PKH风格的地址一样简单。哈希过程也混淆了认领脚本里的所有公钥,这使得P2SH脚本和P2PKH公钥哈希一样安全。
标准交易
必须小心避免非标准的输出脚本。按照比特币核心版本0.9,标准的脚本类型包括:
公钥哈希(P2PKH)
P2PKH是最常见的脚本形式,用于把交易发至一个或多个比特币地址。
script: OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG
脚本哈希(P2SH)
P2SH用于把交易发至一个脚本哈希。每一种标准脚本都可以用在P2SH认领脚本里。但实践中,只有多重签名(multisig)脚本是有意义的,除非以后有更多的交易类型变成标准的。