6.3 交易的输入输出
比特币交易的基本组成部分是交易输出transaction output。 交易输出是比特币不可分割的基本组合,记录在区块链上,并被整个网络认可有效。 比特币全节点跟踪所有可找到的和可使用的输出,称为 “未花费的交易输出”(unspent transaction outputs),即UTXO。 所有UTXO的集合被称为UTXO集,目前有数百万个UTXO。 当新的UTXO被创建,UTXO集就会变大,当UTXO被消耗时,UTXO集会随着缩小。每一个交易都代表UTXO集的变化(状态转换)。
当用户的钱包已经“收到”比特币时,就意味着,钱包已经检测到了可用的UTXO,这些UTXO可以用钱包所控制的其中一个密钥消费。 因此,用户的比特币“余额”是指用户钱包中可用的UTXO总和,这些UTXO分散在几百个交易和几百个区块中。用户的 “比特币余额”,这个概念是比特币钱包应用创建的。比特币钱包扫描区块链,得到可以用这个钱包控制的密钥进行消费的所有UTXO,加到一起就计算出了该用户的余额 。大多数钱包维护一个数据库或使用数据库服务来存储所有UTXO的快速引用集,其中包含可以使用用户的密钥进行消费的所有UTXO。
一个UTXO可以是1“聪”(satoshi)的任意倍数(整数倍)。就像美元可以被分割成表示两位小数的“分”一样,比特币可以被分割成八位小数的“聪”。尽管UTXO可以是任意值,但一旦被创造出来,即不可分割。这是UTXO值得被强调的一个重要特性:UTXO的面值为“聪”的整数倍,是离散(不连续)且不可分割的价值单位,一个UTXO只能在一次交易中作为一个整体被消耗。
如果一个 UTXO比一笔交易金额大,它仍会被当作一个整体而消耗掉,但同时会在交易中生成找零。例如,你有一个价值20比特币的 UTXO,想支付1比特币,那么你的交易必须消耗掉整个20比特币的UTXO,产生两个输出:一个支付了1比特币给收款人,另一个支付19比特币的找零到你的钱包。这样的话,由于UTXO(或交易输出)的不可分割特性,大部分比特币交易都会产生找零。
想象一下,一位顾客要买1.5元的饮料。她掏出钱包并试图从所有硬币和钞票中找出一种组合来凑齐她要支付的1.5 元。如果可能的话,她会选刚刚好的零钱(比如一张1元纸币和5个一毛硬币)或者是小面额的组合(比如3个五毛硬币)。如果都不行的话,她会用一张大面额的钞票,比如5元纸币。如果她把5元给了商店老板,她会得到3.5元的找零,并把找零放回她的钱包供未来使用。
类似的,一笔比特币交易可以是任意金额,但必须从用户可用的UTXO中创建出来。用户不能再把UTXO进一步细分,就像不能把一元纸币撕开而继续当货币使用一样。用户的钱包应用通常会从用户可用的UTXO中选取多个来拼凑出一个大于或等于当前交易所需的比特币量。
就像现实生活中一样,比特币应用可以使用一些策略来满足付款需求:组合若干小额UTXO,并算出准确的找零;或者使用一个比交易额大的UTXO然后进行找零。所有这些复杂的、由可花费UTXO组成的集合,都是由用户的钱包自动完成, 并不为用户所见。只有当你以编程方式用UTXO来构建原始交易时,这些才与你有关。
一笔交易会消耗先前的已被记录(存在)的UTXO,并创建新的UTXO以备未来的交易消耗。通过这种方式,一定数量的比特币价值在不同所有者之间转移,并在交易链中消耗和创建UTXO。
交易的输出与输入链存在一个例外,即被称为“币基交易”(Coinbase Transaction)的特殊交易,它是每个区块中的第一笔交易,这笔交易是由“赢家”矿工放置的,创造了支付给该矿工的全新比特币,作为挖矿奖励。这个特殊的币基交易不消耗UTXO,相反,它有一个称为“coinbase”的特殊类型的输入。这也就是为什么比特币可以在挖矿过程中被创造出来,我们将在“第十章挖矿”进行详述。
小贴士: 输入和输出,先有那个呢?先有鸡还是先有蛋?严格来讲,先产生输出,因为创造新比特币的 “币基交易”没有输入,但它可以无中生有产生输出。
6.3.1 交易输出
每一笔比特币交易都会创造输出,并被比特币账簿记录下来。几乎所有的输出,除了一个例外(见“数据输出操作符”(OP_RETURN)),都能创造称为UTXO的比特币块,然后被整个网络识别,供所有者在未来交易中使用。
UTXO集中的UTXO被每一个全节点比特币客户端追踪。 新的交易从UTXO集中消耗(花费)一个或多个输出。
交易输出包含两部分:
一定量的比特币,面值为“聪”(satoshis) ,是最小的比特币单位;
确定花费输出所需条件的加密难题(cryptographic puzzle)
这个加密难题也被称为锁定脚本(locking script), 见证脚本(witness script), 或脚本公钥 (scriptPubKey)。
有关交易脚本语言会在后面的“交易脚本和脚本语言”一节中详细讨论。
现在,我们来看看 Alice 的交易(之前的6.2.1“交易 - 幕后细节”所示),看看我们是否可以找到并识别输出。 在 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",
}
]
如您所见,交易包含两个输出。 每个输出都由一个值和一个加密难题来定义。 在 Bitcoin Core 显示的编码中,这里的value值以比特币为单位,但在交易本身中,它被记录为以 “聪”为单位的整数。 输出的第二部分是设定支付条件的加密难题。 Bitcoin Core 将其显示为 scriptPubKey,后面跟一个可读的脚本。
稍后将在6.4.3 脚本构建(锁定与解锁)中讨论UTXO的锁定和解锁。 在ScriptPubKey 中使用的脚本语言在6.4比特币交易脚本和脚本语言中讨论。 但在深入研究这些话题之前,需要先了解交易输入和输出的整体结构。
6.3.1.1交易序列化 - 输出
当交易通过网络传输或在应用程序之间交换时,它们是序列化的。 序列化是将数据结构的内部表示转换为可以一次发送一个字节的格式(也称为字节流)的过程。 序列化最常用于编码通过网络传输或用于文件中存储的数据结构。 交易输出的序列化格式如表6-1所示:
表6-1交易输出序列化
Size | Field | Description |
---|---|---|
8 bytes (little-endian) | Amount | Bitcoin value in satoshis (10-8 bitcoin) |
1–9 bytes (VarInt) | Locking-Script Size | Locking-Script length in bytes, to follow |
Variable | Locking-Script | A script defining the conditions needed to spend the output |
大多数比特币库和框架在内部不会将交易存储为字节流,因为每次需要访问单个字段时,都需要复杂的解析。为了方便和可读性,比特币库在数据结构(通常是面向对象的结构)中存储交易。
从交易的字节流表示转换为库的内部表示数据结构的过程称为反序列化或交易解析。转换回字节流通过网络传输、哈希或存储在磁盘上的过程称为序列化。大多数比特币库都有用于交易序列化和反序列化的内置函数。
看看是否可以从序列化的十六进制形式手动解码 Alice 的交易,找到我们以前看到的一些元素。包含两个输出的部分在下面例6-1中加粗显示:
例6-1。Alice的交易,序列化十六进制表示
0100000001186f9f998a5aa6f048e51dd8419a14d8a0f1a8a2836dd734d2804fe65fa35779000000008b483045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e381301410484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adfffffffff0260e31600000000001976a914ab68025513c3dbd2f7b92a94e0581f5d50f654e788acd0ef8000000000001976a9147f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a888ac 00000000
这里有一些提示:
- 加粗显示的部分有两个输出,每个都如本节之前所述进行了序列化。
- 0.015比特币的价值是1,500,000 聪。 十六进制表示是16 e3 60。
- 在序列化交易中,值16 e3 60以小端(最低有效字节优先)字节顺序进行编码,所以它看起来像60 e3 16。
- scriptPubKey的长度为25个字节,十六进制显示为19。
6.3.2交易输入
交易输入标识哪个UTXO(通过引用)将被消费,并通过解锁脚本提供所有权证明。
要构建一个交易,一个钱包从它控制的UTXO中选择足够的面值来支付请求的付款。 有时一个UTXO就足够,有时候需要不止一个。 对于用于付款的每个UTXO,钱包将创建一个指向该UTXO的输入,使用解锁脚本解锁它。
让我们更详细地看一下输入的组成内容。输入的第一部分是一个指向UTXO的指针,引用交易哈希和输出索引,这个索引标识了交易中的特定UTXO。 第二部分是解锁脚本,钱包构建它用以满足在UTXO中的支付条件。 大多数情况下,解锁脚本是一个证明比特币所有权的数字签名和公钥,但是并不是所有的解锁脚本都包含签名。 第三部分是序列号,稍后再讨论。
考虑一下我们在【6.2.1“交易 - 幕后细节】提到的例子。交易输入是一个名为 vin 的数组(列表):
"vin": [
{
"txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
"vout": 0,
"scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
"sequence": 4294967295
}
]
如您所见,列表中只有一个输入(因为一个UTXO的面值足够完成付款)。 输入包含四个元素:
- 一个交易ID,引用包含将要消费的UTXO的交易
- 一个输出索引(vout),用于标识来自该交易的哪个UTXO被引用(第一个为零)
- 一个 scriptSig(解锁脚本),满足UTXO的消费条件,解锁用于支出
- 一个序列号(稍后讨论)
在 Alice 的交易中,输入指向的交易ID是:
7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18
输出索引是0(即由该交易创建的第一个UTXO)。解锁脚本由Alice的钱包创建,首先检索引用的UTXO,检查其锁定脚本,然后用它来构造满足要求的解锁脚本。
仅仅看这个输入,你可能已经注意到,除了涉及包含该UTXO的交易之外,我们无从了解这个UTXO的任何内容。不知道它的金额(多少聪),不知道锁定脚本的消费要求。要找到这些信息,必须通过检索整个交易来检索被引用的UTXO。请注意,由于输入的值未明确说明,因此还必须使用被引用的UTXO来计算需要支付的交易费(参见【6.3.3 交易费】)。
不仅仅是Alice的钱包需要检索输入中引用的UTXO。一旦将该交易广播到网络,每个验证节点也将需要检索交易输入中引用的UTXO,以验证该交易。
因为缺乏上下文,这些交易本身似乎不完整。它们在输入中引用了UTXO,但是如果不检索UTXO,我们就无法知道输入的值或其锁定条件。在编写比特币软件时,无论何时,只要是解码交易以验证交易、计算费用或检查解锁脚本,所编的代码就必须首先从区块链中检索引用的UTXO,以便构造输入引用的UTXO隐含但不存在的上下文。例如,要计算支付总额的交易费,必须知道输入和输出值的总和。但是,如果没有检索输入中引用的UTXO,就不能知道这些值。因此,在单个交易中计算交易费用看似简单,实际上涉及多个交易的多个步骤和数据。
我们可以使用与Bitcoin Core相同的命令序列,就像我们在检索Alice的交易(getrawtransaction和decodeawtransaction)时一样。可以得到在前面的输入中引用的UTXO,如下:
Alice 的UTXO,输入中引用的来自以前的交易:
"vout": [
{
"value": 0.10000000,
"scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG"
}
]
我们看到这个UTXO的值为0.1BTC,并且它有一个包含“OP_DUP OP_HASH160 …”的锁定脚本(scriptPubKey)。
提示 为了充分了解Alice的交易,我们必须检索作为输入引用的之前的交易。 检索以前的交易和未花费的交易输出的函数很常见,大多数比特币函数库和API中都有。
6.3.2.1交易序列化—交易输入
当交易被序列化在网络上传输时,它们的输入被编码成字节流,如下表所示
表6-2 交易输入序列化
Size | Field | Description |
---|---|---|
32 bytes | Transaction Hash | Pointer to the transaction containing the UTXO to be spent |
4 bytes | Output Index | The index number of the UTXO to be spent; first one is 0 |
1–9 bytes (VarInt) | Unlocking-Script Size | Unlocking-Script length in bytes, to follow |
Variable | Unlocking-Script | A script that fulfills the conditions of the UTXO locking script |
4 bytes | Sequence Number | Used for locktime or disabled (0xFFFFFFFF) |
与输出一样,可以从序列化格式的 Alice 的交易中找到输入。 首先,将输入解码:
"vin":
[
{
"txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
"vout": 0,
"scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
"sequence": 4294967295
}
]
现在,看一下下面例6-2中序列化以十六进制表示的字段:
例6-2 Alice的交易,序列化并以十六进制表示
0100000001186f9f998a5aa6f048e51dd8419a14d8a0f1a8a2836dd734d2804fe65fa35779000000008b483045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e381301410484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adfffffffff0260e31600000000001976a914ab68025513c3dbd2f7b92a94e0581f5d50f654e788acd0ef8000000000001976a9147f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a888ac00000 000
提示:
- 交易ID序列化后与原来的字节逆序呈现,因此以(十六进制)18开头,以79结尾
- 输出索引为4字节组的“0”,容易识别
- scriptSig的长度为139个字节,十六进制为8b
- 序列号设置为FFFFFFFF,也容易识别
6.3.3 交易费
大多数交易都包含交易费,这是对比特币矿工保护网络安全的补偿。交易费本身也是一种安全机制,增加攻击者向网络中大量发送交易的经济成本。我们将在【第十章挖矿】详细讨论挖矿、交易费和矿工得到的奖励。
这一节解释交易费是如何被包含在一个典型的交易中的。大多数钱包自动计算并包含交易费。但是, 如果你以编程方式构造交易,或者使用命令行界面,你必须手动计算并包含这些费用。
交易费用是一种激励措施,激励将交易纳入(挖矿)下一个区块,但通过对每笔交易收取小额费用,也起到抑制滥用系统的作用。交易费由成功挖到区块的矿工收取,该区块把交易记录在区块链上。
交易费是基于交易的千字节(KB)大小来计算的,而不是交易比特币的价值。总的来说,交易费是根据比特币网络中的市场力量确定的。矿工会依据许多不同的标准,比如交易费,对交易进行优先级排序,甚至在某些特定情况下免费处理交易。但大多数情况下,交易费影响处理优先级,这意味着有足够费用的交易会更可能被打包进下一个挖出的区块中;反之交易费不足或者没有交易费的交易可能会被推迟,基于尽力而为的原则在几个区块之后被处理,甚至可能根本不被处理。交易费不是强制的,而且没有交易费的交易最终也可能会被处理,但是,有交易费会鼓励优先处理。
随着时间的推移,交易费的计算方式以及在交易处理优先级上的影响已经发生了变化。起初,交易费是固定的,是网络中的一个固定常数。随着网络容量和交易量的增加,收费结构逐渐放松,并可能受到市场力量的影响。至少从2016年初以来,比特币网络容量的限制已经造成交易之间的竞争,从而导致更高的费用,免费交易彻底成为历史。零费用或非常低费用的交易很少被处理,有时甚至不会在网络上传播。
在 Bitcoin Core 中,费用中继策略由minrelaytxfee选项设置。 目前默认的minrelaytxfee是每KB大小0.00001比特币或者mBTC的1%。 因此,默认情况下,费用低于0.0001比特币的交易被视为零费用,只有在内存池有空间时才会被转发; 否则,会被丢弃。 比特币节点可以通过调整minrelaytxfee的值来覆盖默认的费用中继策略。
任何创建交易的比特币服务,包括钱包,交易所,零售应用等,都必须实施动态收费。动态费用可以通过第三方费用估算服务或内置的费用估算算法来实现。如果不确定,请从第三方服务开始,随着经验积累,如果希望删除第三方依赖项,再设计并实现自己的算法。
费用估算算法根据网络能力和“彼此竞争”的交易提供的费用计算适当的费用。这些算法从十分简单的(最后一个块中的平均值或中位数)到非常复杂的(统计分析)都有。它们估计必要的费用(以字节的聪为单位),这将使得交易具有很高的可能性被选择打包进一定数量的块内。大多数服务为用户提供高、中、低优先级费用的选择。高优先级意味着用户支付更高的交易费,但交易就更可能被打包进下一个区块中。中低优先级意味着用户支付较低的交易费,但交易可能需要更长时间才能确认。
许多钱包应用程序使用第三方服务进行费用计算。常用的一个是earnbitcoin网站这个页面 ,它提供了一个API和一个可视化图表,以聪/字节为单位显示了不同优先级的费用。
小贴士: 固定费用在比特币网络上不再可行。 设置固定费用的钱包将导致用户体验很差,因为交易往往会被“卡住”,不被确认。不了解比特币交易和费用的用户因交易被“卡住” 而感到沮丧,因为他们认为自己已经失去了这笔钱。
下面图6-2中的图表显示了按照10聪/字节增长的实时估算费用,还有每个收费区间中交易的预期确认时间(分钟和块数)。 对于每个收费区间(例如,61-70 聪/字节),两个横条显示该区间内过去24小时中交易总数(102,975笔)和未确认交易的数量(1405笔)。 根据图表,此时推荐的高优先级费用为80 聪/字节,这就使交易在最近的下一个区块(零块延迟)中被挖出。 一般来说,一笔常规交易的大小约为226字节,因此单笔交易费建议为18,080 聪(0.00018080 BTC)。
费用估算数据可以通过简单的HTTP REST APIhttps://bitcoinfees.earn.com/api/v1/fees/recommended 例如,在命令行中使用curl命令:
使用费用估算API
$ curl https://bitcoinfees.earn.com/api/v1/fees/recommended
{"fastestFee":80,"halfHourFee":80,"hourFee":60}
API返回一个satoshi/byte 形式的JSON对象,其中包括当前”最快确认“ (fastestFee),三个块(halfHourFee)确认和六个块(hourFee)确认的费用估算值。
图6-2 bitcoinfees.earn.com提供的费用估算服务
6.3.4 把交易费加到交易中
交易的数据结构没有交易费这个字段。相反,交易费是指输入和输出之间的差值。从所有输入中扣掉所有输出之后的剩余的金额是矿工收取的交易费:
Fees = Sum(Inputs) – Sum(Outputs)
正确理解交易比较困难,但又尤为重要。因为如果你要构建你自己的交易,你必须确保没有因为疏忽没支付够输入,反而在交易中添加一大笔交易费。这意味着你必须计算所有的输入,如有必要则加上找零, 不然的话,就给了矿工一笔相当可观的交易费!
举例来说,如果你消耗了一个20比特币的UTXO来完成1比特币的付款,你必须包含一笔19比特币的找零回到你的钱包。否则,那剩下的19比特币会被当作交易费,并将由挖出你交易的矿工收走。尽管你会得到高优先级的处理,并且让一个矿工喜出望外,但这一定不是你想要的结果。
警告: 如果你忘记了在手动构造的交易中增加找零的输出,系统会把找零当作交易费来处理。“不用找了!”也许不是你的真实意愿。
让我们重温一下Alice在咖啡店的交易来看看在实际中它如何运作。Alice想花0.015比特币购买咖啡。为了确保这笔交易能被立即处理,Alice想添加一笔交易费,比如说0.001。这意味着总花费会变成0.016。因此她的钱包需要凑齐一些UXTO加起来是0.016比特币或更多金额。如果更多的话,就得加上找零。我们假设她的钱包有一个0.2比特币的UTXO可用。钱包就会消耗掉这个UTXO,创造一个新的0.015的输出给Bob的咖啡店,另一个0.184比特币的输出作为找零回到Alice的钱包,并留下未分配的0.001交易费作为交易的隐含费用。
再看看另一种情况。Eugenia,菲律宾的儿童募捐项目主管,完成了一次为孩子购买教材的筹款活动。她从世界范围内接收到了好几千份小额捐款,总额是50比特币。所以她的钱包塞满了非常小的UTXO。现在她想用比特币从本地的一家出版商购买几百本教材。
现在Eugenia的钱包应用想要构造一个单笔大额付款交易,它必须来自可用的由许多较小的金额组成的UTXO集。这意味着这笔交易是把上百个小额UTXO作为输入,产生一个用来付给出版商的输出。输入数量这么巨大的交易一定会比1KB要大,也许会达到两至三KB。结果就是它需要比通常交易要高得多的交易费。
Eugenia的钱包应用会测量交易的大小,乘以每KB需要的费用来计算适当的交易费。很多钱包会支付较大的交易费,确保交易得到及时处理。更高交易费不是因为Eugenia付的钱很多,而是因为她的交易很复杂并且尺寸更大——交易费与交易的比特币金额无关。