比特币中的交易过程如何执行?

简单概述下比特币交易的一个过程。简单说明下比特币是怎么交易流转?

自问自答、抛砖引玉

bitcoin交易简介

bitcoin交易是bitcoin系统中最重要的部分,中本聪巧妙的设计了UTXO这种结构,来进行交易和验证。使得系统中bitcoin得以传播和验证,并最终把交易记录到区块链上。
bitcoin交易的本质是一个数据结构,记录并很好的验证了bitcoin中每个节点之间的价值转换关系。且整个bitcoin交易记录在区块链上公开,保证不可篡改。大致介绍下bitcoin的交易过程。参考《精通比特币》第二版

首先说下UTXO:

  • UTXO:Unspent Transaction Output,未消费的交易输出(一个数据结构,包含了交易数据和执行脚本)。这个理解为现在的银行支票比较合适。但是和现在传统的银行,信用卡,一些第三方支付机构不一样,这些都是通过账户来控制。但是在bitcoin中没有账户的一个概念。传统中心化机构对账户进行验证,通过中心化关系数据库,查询余额,确保账户有足够支出。bitcoin中没有一个中心化的机构来提供验证查询服务。
  • 理解UTXO:在bitcoin中记录的一笔笔的交易记录,那么也就是一个资金的流向,那么记录了一个bitcoin从产生到最新的一个流转状态。

说明其他几个概念:

  • bitcoin交易中基础构建单元就是交易输出。
  • UTXO最小单位是“聪”。
  • 钱包中所谓的bitcoin余额是指UTXO可用的总和。这些分散在区块中,钱包知识扫描区块链并汇总该钱包密钥掌握下的UTXO计算余额。
  • UTXO的集合称为UTXO集,交易代表的是UTXO集的状态变换。
  • 每一笔的交易都会创造输出,并被记录。

交易输出

交易的输出创造一定数量的用于支付的bitcoin,也就是UTXO,这些创建后的UTXO在整个网络中被识别。

交易的输出包括两个部分:

  • bitcoin数量
  • 确定花费输出所需的条件:加密难题(cryptographic puzzle)= 锁定脚本(locking script)或者脚本公钥(scriptPubKey)

在JSON编码中,输出vout数组,如下:

"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",
  }
]
  • 可以发现,交易中两个输出,一笔0.015、一笔0.0845.每一个输出都由一个值和一个加密难度来定义。value和scriptPubKey

交易输入

交易输入将UTXO标记为将被消费,并通过解锁脚本提供所有权的证明。
钱包控制UTXO中需要执行请求的付款,这个时候使用多少UTXO根据需求来确定,那么每一个付款的UTXO,钱包都会创建一个指向UTXO的输入,并使用解锁脚本。

交易输入包含三部分:

  • 指向UTXO的指针。通过指向UTXO被记录在区块链中的交易的hash值和序列号来实现。
  • 解锁脚本,钱包构建用于满足设定在UTXO的支出条件,一般来说解锁脚本就是证明bitcoin所有权的数字签名和公钥。
  • 序列号。

输出vout数组,如下:

"vin": [
  {
    "txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
    "vout": 0,
    "scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
    "sequence": 4294967295
  }
]

  • 可以发现,交易中一个输入,但是包含了4个要素(但是没有交易的金额):
    • 一个交易的ID号,引用了包含正在使用的UTXO交易。
    • vout,一个输出的索引,用于标识来自该交易是哪一个UTXO被引用。这个第一个是0.
    • scriptSig,解锁脚本,满足UTXO上的解锁条件。
    • sequence,序列号。
  • 那么理解到这个交易的ID是:
    • 7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18

交易说明

交易说明

  • 首先你看上面交易的输出和输入,你只能在输出看到金额,在输入中没有相关的金额信息和UTXO信息。那么首先检索引用的UTXO,检查锁定脚本,钱包来构建解锁脚本。
  • 检索整个交易,具体就是检索引用的UTXO,同时由于没有金额,那么还需要计算交易支付的费用。
  • 通过检索UTXO信息,那么得到具体UTXO中相关内容:
"vout": [
   {
     "value": 0.10000000,
     "scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG"
   }
 ]

那么在这里就可以看到这个UTXO是0.1,然后有一个OP_DUP OP_HASH160…的锁定脚本

交易脚本

上文中一直在说到的锁定脚本和解锁脚本,用于bitcoin交易验证。

锁定脚本

  • 锁定脚本在交易输出中的一个花费条件,作用就是后来需要来使用这笔输出必须满足的条件。在bitcoin中脚本公钥(scriptPubKey)、锁定脚本(locking script)、见证脚本(witness script)这些其实指的都是这个概念。一般锁定脚本含有公钥或者地址。

解锁脚本

  • 解锁脚本满足锁定脚本在交易输出上所设定的条件。一般含有由钱包私钥生成的数字签名。在bitcoin中常见为ScriptSig。
  • 在bitcoin全网中,每一个节点通过同时来执行锁定和解锁脚本来验证一笔交易。交易输入中的解锁脚本,应用之前存在的UTXO,验证将复制解锁脚本和引用的UTXO,并复制引用的这个UTXO的锁定脚本。然后执行解锁和锁定脚本。那么符合要求就验证通过。全部输入都是独立验证。

  • 脚本执行堆栈,堆栈一种数据结构,两个操作push和pop,那么在堆栈顶添加,也在堆栈顶删除,操作就在堆栈的顶端,所以就理解为“后进先出”

  • bitcoin中解锁和锁定脚本随着堆栈的传递依次分别执行。

    • 首先堆栈执行解锁脚本,解锁脚本执行过程中未报错,那么复制到主堆栈。
    • 执行锁定脚本,和之前复制到主堆栈的解锁脚本结果进行比较。结果为“true”。那么说明解锁脚本满足锁定脚本的条件。获得UTXO的有效授权。
    • 如果上一步中,执行结果不是“true”,那么交易输入无效。

脚本执行过程

bitcoin网络中大多数交易都是P2PKH模式(付款到公钥hash)。交易输出有一个锁定脚本,那么它是将交易输入锁定为一个公钥hash值,理解为是bitcoin中的地址。那么解锁脚本提供一个公钥和对应的私钥创建的数字签名(钱包创建)来解锁。
使用Alice、Bob、Carol、Dave支付的案例,来说明下脚本的执行过程。

  • 一系列交易(如下表):
    | 交易 | 具体内容 | 说明 |
    |:-------:|:-----------:|:-----------:expressionless:
    |1.Alice-Bob|一个输入交易(a)、一个输出交易(b)|a是之前的一个输出对应的输入交易。|
    |2.Bob-Carol|一个输入交易(c)、一个输出交易(d)|c是对应1交易中的b输出交易|
    |3.Carol-Dave|一个输入交易(e)、一个输出交易(f)|e是对应2交易中d输出交易|
  • 三个交易说明:
  • 三个交易都是单输入单输出。
  • 输出交易和输入交易对应相应的脚本。
  • 每一个输入都对应其前一个输出。
  • 一对输出和输入脚本:(上表交易2为例)
  • 输出(锁定)脚本
    OP_DUP OP_HASH160 <Carol Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG
  • 输入(解锁)脚本
    <Carol Signature> <Carol Public Key>
  • 脚本组合后
<Carol Signature> <Carol Public Key> OP_DUP OP_HASH160
<Carol Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG
  • 脚本执行后,显示结果为“true”说明交易通过。

具体执行过程:

  • bitcoin中的堆栈有一个主堆栈和副堆栈。我们主要看主堆栈的一个执行过程。
  • 一个输入脚本(主要是相关脚本指令和接收方的公钥hash),脚本从左到右执行,那么最先入堆栈的是签名,随即公钥。
  • 一个输出脚本(主要是签名sig和公钥pubkey),从左到右执行。
  • 执行过程(如下表):
    | 步骤 | 具体内容 | 说明 |
    |:-------:|:-----------:|:-----------:expressionless:
    |1.1|执行输入脚本|sig入堆栈|
    |1.2|执行输入脚本|pubkey入堆栈|
    |2.1|执行输出脚本-复制pubkey|OP_DUP,复制堆栈内的pubkey|
    |2.2|计算堆栈顶元素hash值|执行OP_HASH160,堆栈顶是pubkey,执行后得到pubkeyhash|
    |2.3|输出脚本中的sig入堆栈|sig入堆栈,区分目前堆栈顶的pubkeyhash,标记为pubkeyhash’|
    |3.1|执行检查|OP_EQUALVERIFY检查两个pubkeyhash时候相等。相等继续执行,不相等则终止操作,返回结果失败。|
    |3.2|签名校验|OP_CHECKSIG检查两个签名的校验,相等返回成功,不相等返回失败|