Mastering Bitcoin 2nd Edition Chapter 6: Transactions

<!–more–>

Mastering Bitcoin 2nd Edition Chapter 6: Transaction

“Transactions are the most important part of the bitcoin system. Everything else in bitcoin is designed to ensure that transactions can be created, propagated on the network, validated, and finally added to the global ledger of transactions (the blockchain).”

第六章的开篇又提到了Transaction 的重要性,可以说就是为了保证Transaction 能够成功,才创造了其他一系列的技术支持。在第二章中,我们已经大致明白了transaction 是怎样工作的了,在第六章中,我们将介绍其中的细节。

先贴一个Transaction 在这里,之后我们慢慢展开讲其中所包含的信息

{
  "version": 1,
  "locktime": 0,
  "vin": [
    {
    "txid":
    "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
    "vout": 0,
    "scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204 b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d1 72787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
    "sequence": 4294967295
  }
  ],
  "vout": [
    {
    "value": 0.01500000,
    "scriptPubKey": "OP_DUP OP_HASH160
ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG"
  },
    {
    "value": 0.08450000,
    "scriptPubKey": "OP_DUP OP_HASH160
 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
  }
  ]
}

Transaction Outputs and Inputs

这里我们直接引入一个新的概念: UTXO (Unspent transaction outputs) 未被花费的outputs,他具有discrete and indivisible 两个特性,就像物理货币一样,每一个硬币,每一张钞票,你在消费的时候,不能把它拆开来使用一样,并且一旦用出,你得到的找零也是其他的货币。

所有的Transaction整个过程中都是涉及到UTXO

Received Bitcoin
Wallet 通过检测整一个bitcoin network, 发现有与当前钱包所控制的bitcoin address 相关的UTXO 存在
Bitcoin Balance
Wallet 对所有这些检测到的可以使用的UTXO 做一个总和,就是当前的余额balance
Spend UTXO
  1. 将多个UTXO 汇总/直接使用一个大额度的UTXO
  2. 差值作为找零生成新的UTXO 返回钱包
  3. 这同时也代表着新的UTXO 的产生
  4. 不同大小的UTXO的不断汇总,分散,但是形成了一条chain
Coinbase transaction
先有鸡,还是先有蛋的问题,最找的UTXO 从哪里来的呢? 这里就要引入一个新的概念coinbase transaction 也就是每个block由miner创造的一个特殊的transaction, 包含了创造新的block 的奖励以及所有的transaction fees,这个就是最初始产生的UTXO

Transaction Outputs

“Every bitcoin transaction creates outputs ,which are recorded on the bitcoin ledger.”

Transcation outputs 由两部分组成
  1. 一定数量的bitcoin, 用 satoshis 来表示
  2. 一个密码学题目,用来决定如果使用这个output (A cryptographic puzzle: locking script, witness script, or a scriptPubKey)

此时我们再回过头来之前transcation的内容,value out部分就很好理解了,就是用 satoshis 表示的一部分value 以及用scriptPubkey表示的一个 puzzle, 我们之后会讲到如何lock+unlock 这个scriptPubKey

"vout": [
    {
    "value": 0.01500000,
    "scriptPubKey": "OP_DUP OP_HASH160
ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG"
  },
    {
    "value": 0.08450000,
    "scriptPubKey": "OP_DUP OP_HASH160
 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
  }
  ]

Transaction serialisation – outputs

我们知道所有的Transaction 都会在整个bitcoin network中传递,同时也会被保存在各个节点上(bitcoin libraries)

那么为了传输以及保存的方便,就有了两种形式:

  1. 第一种就是我们之前见到过的用数据结构进行存储
  2. 第二种就是转换成byte stream 的形式,方便用于网络的传输

他们之前的转换就被我们称为序列化serialisation 以及反序列化 deserialisation

  1. 数据结构 -> byte-stream: serialisation

  1. byte-stream -> 数据结构:deserialisation

Transaction Inputs

Transaction inputs 制定了哪些UTXO 将要被用到本次transaction 当中,并为其提供unlocking script的proof of ownership

当wallet开始进行一次transaction 的时候,它会从该wallet 所控制的所有UTXO中选择符合要求的,一定数量的UTXO 来进行

Transaction Inputs 包含两个部分

一个指向对应的一个 UTXO 的指针 (通过这个指针,包括hash id & sequence number, 我们可以在blockchain上找到这个UTXO 对应的信息)

一个 unlocking script (用于满足UTXO的 locking script的使用条件)

我们继续通过之前的例子来看transaction inputs

"vin": [
    {
    "txid":
    "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
    "vout": 0,
    "scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204 b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d1 72787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
    "sequence": 4294967295
  }
]

这条 Inputs 的记录包含了四个部分:

  1. Transaction ID 指向了我们需要的UTXO所对应的Transaction
  2. Output index (vout) 用于指示对应的那个Transaction中我们需要的UTXO 记得我们之前提到的不同forms的transaction吗,其中有一种就是存在很多的outputs,也就是生成了很多新的UTXO, 我们需要指出我们本次需要的具体是哪一个
  3. scriptSig,用于unlock对应UTXO的locking script
  4. sequence number

细心的人可能会发现,在这条关于inputs的记录中似乎少了点什么,作为一个转账记录,它缺少最重要的东西,就是“多少钱”

完全没有bitcoin value 以及 locking script的信息

这也是作者提醒各位开发者的信息,每次在处理transaction 特别是inputs的时候,我们都需要利用 Transaction ID 去主动去获取对应的 UTXO 的信息(getrawtrasaction and decoderawtrasaction) 比如以这条记录为例,查询到的结果就是

"vout": [
    {
     "value": 0.10000000,
     "scriptPubKey": "OP_DUP OP_HASH160
7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG"
    }
]

Transaction serialization—inputs

Transaction inputs的存储和传输同样也需要用到序列化和反序列化

Transaction fee

设置transaction fee 的目的?
  1. 给予miners记账的奖励
  2. 通过设置transaction fee 其实带来的是一个安全机制,也就是说attackers 不同通过大量的transaction来flood网络,因为这样会产生大量的消耗
如何决定 transcation fee 的数量?
  1. 最开始是恒定的

  2. 后来开始可以自由设置

Transaction fee 的多少有什么影响
Transaction fee的数量直接决定了对应的这个 transaction 被处理的优先级,数量越多,就更有可能被包含在下一个block中

相对的,如果你设的越低,或者根本不设,很可能会因为best-effort而被放到很后面来执行,甚至根本永远都不会被处理

Adding Fees to Trasactions
我们观察之前的transaction的数据结构,里面并没有任何的变量指向transaction fee,那么其实这里是需要提前自行从找零的charge中扣除一部分的bitcoin value,如果忘记做了这一点,就会把整一个charge付给miner。当我们主动扣除之后,那么在后期结算的时候,就可以发现有一些未被分配的bitcoin value,这些就会被当作是transaction fee。
Fees = Sum(Inputs) – Sum(Outputs)

就如下图的一次transaction一样,我们可以看到右侧的outputs中,综合为0.995 BTC,也就是扣除了transaction fee之后的结果

Transaction validation

在这一章,我们来具体讲讲每一个transaction要如何得到验证,我们先再来回顾一下构成一个transaction所需要的inputs和outputs是由什么组成的。

Transaction Inputs 包含两个部分

一个指向对应的一个 UTXO 的指针 (通过这个指针,包括hash id & sequence number, 我们可以在blockchain上找到这个UTXO 对应的信息)

一个 unlocking script (用于满足UTXO的 locking script的使用条件)

Transcation outputs 由两部分组成
  1. 一定数量的bitcoin, 用 satoshis 来表示
  2. 一个密码学题目,用来决定如果使用这个output (A cryptographic puzzle: locking script, witness script, or a scriptPubKey)

我们可以观察到他们都包含了一个概念叫做 script ,中文我们一般翻译为脚本,意思是一段可以执行的指令,一开始我接触这个概念的时候我也觉得很奇怪,为什么要在inputs和outputs中放脚本呢,他们又要如何运行呢,我们接着一起来来看。

先说结论,这些脚本确实可以运行, unlocking script 以及 locking script 结合在一起,可以组成简单的计算,得到 True / False 的结果来决定本次 transaction 是否成立,如果成立,那么 UTXO 将会被 spent 也就从 UTXO set 中被移除了。

Pay-to-Public-Key-Hash script

A locking script
  • is a spending condition placed on an output
  • also called scriptPubKey, witness script, crytographic puzzle
  • it usually contained a public key or bitcoin address (public key hash)
A unlocking script
  • is a script that “solves,” or satisfies, the conditions placed on an output by a locking script and allows the output to be spent
  • also called scriptSig
  • contain a digital signature produced by the user’s wallet from his or her private key

我们用之前Alice在Bob的咖啡馆买咖啡的例子来演示具体需要如何来验证一次transaction:

  1. Alice发起了一次付款,她使用自己钱包中的UTXO作为inputs,然后产生一个output给咖啡馆,一个output作为找零返回给自己

  2. 发给咖啡馆的transaction output将会包含一个locking script如下:

    OP_DUP OP_HASH160 <Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG

  3. OP开头的字符串都表示script指令,那么这一串locking script就包含了一系列的指令和咖啡馆的public key hash

  4. 当Bob的咖啡馆需要消费这个input(UTXO)的时候,就需要利用它的unlocking script来解锁之前的locking script,其中应该包含两个部分

    <Cafe Signature> <Cafe Public Key>

  5. 那么当locking script和unlocking script拼接在一起的时候,就组成了一个完整的脚本

    <Cafe Signature> <Cafe Public Key> OP_DUP OP_HASH160 <Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG

  6. 如果验证的结果为TRUE的话就验证成功了

我们可以看看具体的验证过程,这里的脚本语言是基于stack栈实现的:

  1. 将signature压入栈
  2. 将Public key压入栈
  3. 使用DUP指令来复制栈顶的内容并压入栈

  1. 使用HASH160来处理栈顶的内容并将结果压入栈HASH160(PubK) = <PubKHash>
  2. 将原本locking script中的<PubKHash>压入栈
  3. 使用指令EQUALVERIFY来比较栈顶的两个 <PubKHash> 是否相等,如果相等,则全部移出栈
  4. 最后使用指令CHECKSIG来验证 <PubK> 与 <sig> 是否匹配(本质上判断是不是一对public key 和 private key),如果匹配成功,返回True,验证成功

这里附带一个 Bitcoin Address 的产生过程

comments powered by Disqus
Cogito, ergo sum
Built with Hugo
Theme Stack designed by Jimmy