Mastering Bitcoin Chapter06 交易

6.1 简介

比特币交易是比特币系统中最重要的部分。系统中任何其他的部分都是为了确保比特币交易可以被生成、能在比特币网络中得以传播和通过验证,并最终添加入全球比特币交易总账簿(比特币区块链)。

6.2 交易细节

6.2.1 交易-幕后细节

事实上,我们在各种比特币应用程序用户界面中看到的大多数高级结构实际上并不存在于比特币系统中。

用 Bitcoin Core 的命令行界面(getrawtransaction 和 decodeawtransaction)来检索 Alice 的“原始”交易,对其进行解码,并查看它包含的内容。 结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"version": 1,
"locktime": 0,
"vin": [
{
"txid":"7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
"vout": 0,
"scriptSig": "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
"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",
}
]
}

比特币里,没有具体的货币,没有发送者,没有接收者,没有余额,没有帐户,没有地址。为了使用者的便利,以及使事情更容易理解,所有这些都构建在更高层次上。

6.3 交易的输入输出

比特币交易中的基础构建单元是交易输出。 比特币完整节点跟踪所有可找到的和可使用的输出,称为 “未花费的交易输出”(unspent transaction outputs),即 UTXO。 所有 UTXO 的集合被称为UTXO 集,目前有数百万个 UTXO。每一个交易都代表 UTXO 集的变化(状态转换)。

用户的比特币“余额”是指用户钱包中可用的 UTXO 总和,而他们可能分散在数百个交易和区块中。

  • 一个 UTXO 可以是1“聪”(satoshi)的任意倍数(整数倍)。
  • UTXO 可以是任意值,但一旦被创造出来,即不可分割。UTXO 是面值为“聪”的离散(不连续)且不可分割的价值单元,一个UTXO只能在一次交易中作为一个整体被消耗。

如果一个 UTXO 比一笔交易所需量大,它仍会被当作一个整体而消耗掉,但同时会在交易中生成零头。

一笔交易会消耗先前的已被记录(存在)的 UTXO,并创建新的 UTXO 以备未来的交易消耗。通过这种方式,一定数量的比特币价值在不同所有者之间转移,并在交易链中消耗和创建 UTXO。一笔比特币交易通过使用所有者的签名来解锁 UTXO,并通过使用新的所有者的比特币地址来锁定并创建 UTXO。

6.3.1 交易输出

交易输出包含两部分:

  • 一定量的比特币,面值为“聪”(satoshis) ,是最小的比特币单位;

  • 确定花费输出所需条件的加密难题(cryptographic puzzle)

这个加密难题也被称为锁定脚本(locking script), 见证脚本(witness script), 或脚本公钥 (scriptPubKey)。

6.3.1.1 交易序列化 - 输出

当交易通过网络传输或在应用程序之间交换时,它们被序列化。 序列化是将内部的数据结构表示转换为可以一次发送一个字节的格式(也称为字节流)的过程。交易输出的序列化格式如下表所示

从交易的字节流表示转换为函数库的内部数据结构表示的过程称为反序列化或交易解析。转换回字节流以通过网络传输、哈希化(hashing)或存储在磁盘上的过程称为序列化。大多数比特币函数库具有用于交易序列化和反序列化的内置函数。

6.3.2 交易输入

交易输入将 UTXO(通过引用)标记为将被消费,并通过解锁脚本提供所有权证明。

要构建一个交易,一个钱包从它控制的 UTXO 中选择足够的价值来执行被请求的付款。对于将用于进行此付款的每个 UTXO,钱包将创建一个指向 UTXO 的输入,并使用解锁脚本解锁它。

输入的组件:

  • 输入的第一部分是一个指向UTXO的指针,通过指向UTXO被记录在区块链中所在的交易的哈希值和序列号来实现。

  • 第二部分是解锁脚本,钱包构建它用以满足设定在UTXO中的支出条件。 大多数情况下,解锁脚本是一个证明比特币所有权的数字签名和公钥,但是并不是所有的解锁脚本都包含签名。

  • 第三部分是序列号。

1
2
3
4
5
6
7
8
"vin": [
{
"txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
"vout": 0,
"scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
"sequence": 4294967295
}
]

交易输入是一个名为 vin 的数组(列表):

  • 一个交易ID,引用包含正在使用的 UTXO 的交易
  • 一个输出索引(vout),用于标识来自该交易的哪个 UTXO 被引用(第一个为零)
  • 一个 scriptSig(解锁脚本),满足放置在 UTXO 上的条件,解锁它用于支出
  • 一个序列号

仅仅看这个输入,除了对包含它引用的交易之外,我们无从了解这个 UTXO 的任何内容。要找到这些信息,我们必须通过检索整个交易来检索被引用的 UTXO。一旦将该交易广播到网络,每个验证节点也将需要检索交易输入中引用的 UTXO,以验证该交易。

6.3.2.1 交易序列化 - 交易输入

当交易被序列化以在网络上传输时,它们的输入被编码成字节流,如下表所示:

输入解码为:

1
2
3
4
5
6
7
8
9
"vin":
[
{
"txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
"vout": 0,
"scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
"sequence": 4294967295
}
]

十六进制的字节流:

  • 交易 ID 以反转字节顺序序列化,因此以(十六进制)18 开头,以 79 结尾
  • 输出索引为 4 字节组的“0”,容易识别
  • scriptSig 的长度为 139 个字节,或十六进制为 8b
  • 序列号设置为 FFFFFFFF,也容易识别

6.3.3 交易费

大多数交易包含交易费(矿工费),这是为了确保网络安全而给比特币矿工的一种补偿。

交易费是根据比特币网络中的市场力量确定的。矿工会依据许多不同的标准对交易进行优先级排序,包括费用,他们甚至可能在某些特定情况下免费处理交易。但大多数情况下,交易费影响处理优先级。

在 Bitcoin Core 中,费用传递政策由 minrelaytxfee 选项设置。 目前默认的 minrelaytxfee 是每千字节 0.00001 比特币或者 millibitcoin 的1%。 因此,默认情况下,费用低于 0.0001 比特币的交易是免费的,但只有在内存池有空间时才会被转发;否则,会被丢弃。 比特币节点可以通过调整 minrelaytxfee 的值来覆盖默认的费用传策略。

任何创建交易的比特币服务,包括钱包,交易所,零售应用等,都必须实现动态收费。

费用估算算法根据网络能力和“竞争”交易提供的费用计算适当的费用。这些算法的范围从十分简单的(最后一个块中的平均值或中位数)到非常复杂的(统计分析)均有覆盖。

6.3.4 把交易费加到交易中

交易费即输入总和减输出总和的余量:交易费 = 求和(所有输入) - 求和(所有输出)

交易费是与参加交易的比特币值无关的,与交易的复杂度、尺寸(UTXO 个数等)有关

6.4 比特币交易脚本和脚本语言

比特币交易脚本语言,称为脚本,是一种类似 Forth 的逆波兰表达式的基于堆栈的执行语言。

6.4.1 图灵非完备性

比特币脚本语言包含许多操作码,但都故意限定为一种重要的模式——除了有条件的流控制以外,没有循环或复杂流控制能力。这样就保证了脚本语言的图灵非完备性,这意味着脚本有限的复杂性和可预见的执行次数。受限制的语言能防止交易验证机制被作为一个漏洞而加以利用。

6.4.2 去中心化验证

执行脚本所需信息都已包含在脚本中。可以预见的是,一个脚本能在任何系统上以相同的方式执行。如果一个系统验证了一个脚本,可以确信的是每一个比特币网络中的其他系统也将验证这个脚本,这意味着一个有效的交易对每个人而言都是有效的,而且每一个人都知道这一点。

6.4.3 脚本构建(锁定与解锁)

比特币的交易验证引擎依赖于两类脚本来验证比特币交易:锁定脚本和解锁脚本。

锁定脚本(locking script)是一个放置在输出上面的花费条件:它指定了今后花费这笔输出必须要满足的条件,又称脚本公钥(scriptPubKey)、见证脚本(witness script)、加密难题(cryptographic puzzle)。

解锁脚本是一个“解决”或满足被锁定脚本在一个输出上设定的花费条件的脚本,它将允许输出被消费。解锁脚本是每一笔比特币交易输入的一部分,而且往往含有一个由用户的比特币钱包(通过用户的私钥)生成的数字签名。又称为 ScriptSig、见证(witness)。

每一个比特币验证节点会通过同时执行锁定和解锁脚本来验证一笔交易。所有输入都是独立验证的,作为交易总体验证的一部分。

UTXO 被永久地记录在区块链中,因此是不变的,并且不受在新交易中引用失败的尝试的影响。 只有正确满足输出条件的有效交易才能将输出视为“开销来源”,继而该输出将被从未花费的交易输出集(UTXO set)中删除。

下图是最常见类型的比特币交易(P2PKH:对公钥哈希的付款)的解锁和锁定脚本的示例,显示了在脚本验证之前从解锁和锁定脚本的并置产生的组合脚本:

6.4.3.1 脚本执行堆栈

比特币的脚本语言被称为基于堆栈的语言,因为它使用一种被称为堆栈(LIFO)的数据结构。

6.4.3.2 一个简单的脚本

如下图,在比特币的脚本验证中,执行简单的数学运算时,脚本“ 2 3 OP_ADD 5 OP_EQUAL ”演示了算术加法操作码 OP_ADD ,该操作码将两个数字相加,然后把结果推送到堆栈, 后面的条件操作符 OP_EQUAL 是验算之前的两数之和是否等于 5 。为了简化起见,前缀OP_在一步步的演示过程中将被省略。有关可用脚本操作码和函数的更多详细信息,请参见[交易脚本]。

如果堆栈顶部的结果显示为 TRUE(标记为`{{0x01}}`),即为任何非零值,或脚本执行后堆栈为空情形,则交易有效。如果堆栈顶部的结果显示为 FALSE(0 字节空值,标记为 `{{}}`) 或脚本执行被操作码明确禁止,如 OP_VERIFY、 OP_RETURN,或有条件终止如 OP_ENDIF,则交易无效。详见[tx_script_ops] 相关内容。

6.4.3.3 解锁和锁定脚本的单独执行

首先,使用堆栈执行引擎执行解锁脚本。如果解锁脚本在执行过程中未报错(例如:没有“悬挂”操作码),则复制主堆栈(而不是备用堆栈),并执行锁定脚本。如果从解锁脚本中复制而来的堆栈数据执行锁定脚本的结果为“TRUE",那么解锁脚本就成功地满足了锁定脚本所设置的条件,因此,该输入是一个能使用该 UTXO 的有效授权。如果在合并脚本后的结果不是”TRUE“以外的任何结果,输入都是无效的,因为它不能满足 UTXO 中所设置的使用该笔资金的条件。

6.4.4 P2PKH(Pay-to-Public-Key-Hash)

比特币网络处理的大多数交易花费的都是由“付款至公钥哈希”(或 P2PKH)脚本锁定的输出,这些输出都含有一个锁定脚本,将输入锁定为一个公钥哈希值,即我们常说的比特币地址。由 P2PKH 脚本锁定的输出可以通过提供一个公钥和由相应私钥创建的数字签名来解锁(使用)。

下图显示了组合脚本一步步检验交易有效性的过程:

6.5 数字签名(ECDSA)

比特币中使用的数字签名算法是椭圆曲线数字签名算法(Elliptic Curve Digital Signature Algorithm)或 ECDSA。

数字签名在比特币中有三种用途:

  • 第一,签名证明私钥的所有者,即资金所有者,已经授权支出这些资金。
  • 第二,授权证明是不可否认的(不可否认性)。
  • 第三,签名证明交易(或交易的具体部分)在签字之后没有也不能被任何人修改。

6.5.1 数字签名如何工作

数字签名是一种由两部分组成的数学方案:第一部分是使用私钥(签名密钥)从消息(交易)创建签名的算法; 第二部分是允许任何人验证签名的算法,给定消息和公钥。

6.5.1.1 创建数字签名

在比特币的 ECDSA 算法的实现中,被签名的“消息”是交易,或更确切地说是交易中特定数据子集的哈希值(参见签名哈希类型(SIGHASH))。签名密钥是用户的私钥,结果是签名:

Sig = Fsig(Fhash(m), dA)

  • dA 是签名私钥
  • m 是交易(或其部分)
  • Fhash 是散列函数
  • Fsig 是签名算法
  • Sig 是结果签名

6.5.1.2 签名序列化(DER)

一个 DER 编码签名:

1
3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e381301

该签名是 Fsig 生成的 R 和 S 值的序列化字节流。序列化格式包含以下 9 个元素:

  • 0x30 表示 DER 序列的开始
  • 0x45 序列的长度(69字节)
  • 0x02 一个整数值
  • 0x21 整数的长度(33字节)
  • R-00884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb
  • 0x02 接下来是一个整数
  • 0x20 整数的长度(32字节)
  • S-4b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813
  • 后缀(0x01)指示使用的哈希的类型(SIGHASH_ALL)

6.5.2 验证签名

要验证签名,必须有签名(R 和 S)、序列化交易和公钥(对应于用于创建签名的私钥)。

签名验证算法采用消息(交易或其部分的哈希值)、签名者的公钥和签名(R 和 S 值),如果签名对该消息和公钥有效,则返回 TRUE 值。

6.5.3 签名哈希类型(SIGHASH)

在一个交易中一个签名可以只承诺(commit)一个数据子集。

每个签名都有一个 SIGHASH 标志,该标志在不同输入之间也可以不同。具有三个签名输入的交易可以具有不同 SIGHASH 标志的三个签名,每个签名签署(承诺)交易的不同部分。每个输入可能在其解锁脚本中包含一个签名。因此,包含多个输入的交易可以拥有具有不同 SIGHASH 标志的签名,这些标志在每个输入中承诺交易的不同部分。

有三个SIGHASH标志:ALL,NONE和SINGLE,如下表所示。

还有一个修饰符标志 SIGHASH_ANYONECANPAY,它可以与前面的每个标志组合。 当设置ANYONECANPAY 时,只有一个输入被签名,其余的(及其序列号)打开以进行修改。 ANYONECANPAY 的值为 0x80,并通过按位 OR 运算,得到如下所示的组合标志:

SIGHASH 标志在签名和验证期间应用的方式是建立交易的副本和删节其中的某些字段(设置长度为零并清空),继而生成的交易被序列化,SIGHASH 标志被添加到序列化交易的结尾,并将结果哈希化 ,得到的哈希值本身即是被签名的“消息”。

一些SIGHASH类型:

  • ALL | ANYONECANPAY

    这种构造可以用来做“众筹”交易,用ALL | ANYONECANPAY 签署自己的输入,除非收集到足够的输入以达到输出的价值,交易无效,每次捐赠是一项“抵押”,直到募集整个目标金额才能由募款人收取。

  • NONE

    该结构可用于创建特定数量的“不记名支票”或“空白支票”。它对输入进行承诺,但允许输出锁定脚本被更改。任何人都可以将自己的比特币地址写入输出锁定脚本并兑换交易。然而,输出值本身被签名锁定。

  • NONE | ANYONECANPAY

    这种构造可以用来建造一个“吸尘器”。在他们的钱包中拥有微小 UTXO 的用户无法花费这些费用,因为手续费用超过了这些微小UTXO的价值。借助这种类型的签名,微小 UTXO 可以为任何人捐赠,以便随时随地收集和消费。

6.5.4 ECDSA 数学

如前所述,签名由产生由两个值 R 和 S 组成的签名的数学函数 Fsig 创建。在本节中,我们将查看函数 Fsig 的更多细节。

签名算法首先生成一个 ephemeral(临时)私公钥对。 在涉及签名私钥和交易哈希的变换之后,该临时密钥对用于计算 R 和 S 值。

临时密钥对基于随机数 k,用作临时私钥。 从 k,我们生成相应的临时公钥 P(以 P = k * G 计算,与派生比特币公钥相同)。数字签名的 R 值则是临时公钥 P 的 x 坐标。

从那里,算法计算签名的 S 值,使得:

其中:

  • k 是临时私钥
  • R 是临时公钥的 x 坐标
  • dA 是签名私钥
  • m 是交易数据
  • p 是椭圆曲线的主要顺序

验证是签名生成函数的倒数,使用 R、S 值和公钥来计算一个值 P,该值是椭圆曲线上的一个点(签名创建中使用的临时公钥):

其中:

  • R 和 S 是签名值
  • Qa 是公钥
  • m 是签署的交易数据
  • G 是椭圆曲线发生器点

如果计算点 P 的 x 坐标等于 R,则验证者可以得出结论,签名是有效的。

6.5.5 随机性在签名中的重要性

如果在两个不同的交易中,在签名算法中使用相同的值 k,则私钥可以被计算并暴露给世界。

为了避免这个漏洞,业界最佳实践不是用熵播种的随机数生成器生成 k 值,而是使用交易数据本身播种的确定性随机进程。这确保每个交易产生不同的 k 值。在互联网工程任务组(Internet Engineering Task Force)发布的 RFC 6979 中定义了 k 值的确定性初始化的行业标准算法。

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×