交易 - 比特币开发指南
交易 - 比特币开发指南
原文链接: https://bitcoin.org/en/developer-guide#transactions
翻译: terryc007
版本:1.0
比特币开发指南
交易让用户花掉satoshis。每个交易由好几个部分组成,这些组成部分可以允许简单直接的支付,也可以实现复杂的交易。 本节将讲述每个部分,同时展示如何运用他们来创建复杂的交易。
为简化,本节不考虑coinbase交易。 Coinbase交易仅能由矿工创建,同时,对于下面的很多规则,并不适用Coinbase交易。如想了解Coinbase交易,请你阅读在区块链章节中有关coinbase交易部分的内容。
上图展示了比特币交易的主要构成部分。每个交易至少包含一个输入,一个输出。每个输入会花掉satoshis去支付之前的输出,然后每个输出会以一个未被花掉的交易输出(UTXO)形式存在,直到后续的输入把它花掉。 当比特币钱包说你有10000个satoshis余额时,它其实是你一个10000个sotoshi以一个或多个UTXO的形式存在。
每个交易以4字节的版本号开头,交易版本号用来告诉比特币节点,矿工该用那些规则来验证它。这让比特币开发者,在不违反之前交易规则前提下,为未来的交易新增规则。
每输出基于他在交易中的位置,有一个隐式的索引号 - 第一个输出的索引号是0. 每个输出有一定数量的satoshi,以用于支付一个条件公钥脚本。只要满足公钥脚本条件,任何人都可以花掉里面的satoshi。
每个输入使用一个交易di(txid),输出索引号(通常叫做:作为输出向量的vout )来识别一个被发掉的特定的输出。同时,每个输入还包含了一个签名脚本。该签名脚本允许输入为公钥脚本条件,提供数据参数。 (序列号,锁定时间相关内容会在后面的小节再讲解。)
下面的图通过展示Alice发送一个交易给Bob,让后Bob花费这个交易输出的流程,阐明如何使用这些功能。 Alice跟Bob都使用最为通用的支付公钥哈希 Pay-to-Public-Key-Hash(P2PKH)的交易类型。P2PKH可以让Alice给一个通用的比特币地址支付satoshi,让后让Bob以后可以使用一个简单的密钥花掉这些satoshi。
在Alice跟Bob间能创建第一笔交易前,Bob必须创建一个私钥/公钥密钥对。比特币采用通过secp256k1曲线实现的椭圆曲线数字签名算法(the Elliptic Curve Digital Signature Algorithm ECDSA). secp256k1密钥是一个256位的随机数据。该密钥的拷贝可变换成一个确定的secp256k1公钥。因为这个变换能够可靠的重复,即只要私钥不变,通过这个变换就能生成同样的公钥,所以在以保存了私钥的情况下,就没有必要存储公钥了。
然后公钥被加密哈希。这个加密哈希后的哈希值,也是可以被可靠的生成出来,因此也没有必要保存它。短化的,模糊处理了的公钥,不仅使得手动交易更简单,同时为预防一些意外情况(后续会讲到的:允许通过公钥数据来重建私钥)提供了安全保障。
Bob给Alice提供一个公钥哈希值。 公钥哈希值通常以比特币地址的形式进行编码,再发送出去。 比特币地址是一串通过base58编码后的字符串,包含一个地址版本号,哈希值,错误检查校验和。这个地址可以通过任何媒介进行传输,包括单向媒介(可以防止支付方与收款方进行通信),同时比特币地址可进一步被编码成另外一种格式,比如以QR码格式(bitcoin:URI).
一但Alice获取Bob的比特币钱包地址,并反编码成一个标准的哈希值,她就能创建与Bob间的第一个交易。她创建一个标准的P2PKH交易输出。交易输出里包含了一些指令: 这些指令允许人可以花掉这个输出,只要他能证明他们控制了与Bob相应的哈希公钥相对应的私钥。这些指令被称之为: 公钥脚本(pubkey script)或者 scriptPubKey。
然后Alice广播这个交易,同时交易被加入到区块链。比特币网络把这个交易分类成一个未花费交易输出UTXO,而Bob的钱包会显示为一个可花的余额。
过后,当Bob决定要花掉这个UTXO时,他必须创建一个输入,这个输入通过交易哈希id(txid),来引用Alice的交易,以及通过输出的序列号来使用Alice使用的输出。Bob必须创建一个签名脚本 — 其实就是一些参数数据集合,这些参数数据满足在之前Alice交易输出的公钥脚本中设置的条件。签名脚本也叫scriptSigs.
公钥脚本和签名脚本通过secp256k1公钥,带有条件逻辑的签名组合起来,来创建一个可编程的授权机制。
对于P2PKH类型输出,Bob的签名脚本包含以下两种数据:
- 他的完整(没经过哈希的)公钥,这样公钥脚本能够检查Alice提供的公钥哈希是否跟完整公钥经过哈希处理后所得的哈希值一致。
- 一个secp256k1签名, 它是通过ECDSA加密公式把一定的交易数据,与Bob私钥结合起来生成的。这可以让公钥脚本验证:Bob是那个创建那个公钥的密钥的拥有者。
Bob的 secp256k1签名不仅是证明Bob控制了他的密钥,它也使得他的交易中非签名脚本部分是防篡改的,因此Bob能安全地在p2p网络中广播交易。
如上图所示,Bob签名的数据包括交易id,前一交易的输出索引号,之前输出公钥脚本,Bob创建的公钥脚本(可被下一个接受者发掉这个交易的输出),可被下一个接受者发掉的satoshi的数量。本质上讲,整个交易除了签名脚本,secp256k1签名外,整个交易都会被签名。
Bob把他的签名,以及公钥放到签名脚本后,他通过P2P比特币网络广播该交易给比特币矿工。每个比特币节点,矿工会独立的验证交易后,再向其他节点广播该交易,或尝试添加到新区块交易中。
P2PKH 脚本验证
验证程序需要对签名脚本跟公钥脚本求值。 在一个P2PKH输出,公钥脚本是这样子的:
OP_DUP OP_HASH160 <PubkeyHash> OP_EQUALVERIFY OP_CHECKSIG
花费者签名脚本被求值,并被放到脚本的开头处。在一个P2PKH交易中,签名脚本包含一个secp256k1签名(sig),一个完整公钥(publkey), 并以如下方式串起来:
<Sig> <PubKey> OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
这个脚本语言一种类Forth的基于堆栈的编程语言,专门为比特币而设计的无状态的,非图灵完备的脚本语言。无状态保证了一个交易一但被加到区块链中,就没有条件使得其永久不可用[?]。 非图灵完备(更具体来说,就是缺少循环或goto语句)使得脚本语言拥有更少的灵活性,更多的可预测性,这极大的简化了安全模型。
为测试交易是否有效,签名脚本和公钥脚本操作每次只执行一个: 先执行Bob的签名脚本,接着是Alice的公钥脚本。 下图展示了一个标准的P2PKH公钥脚本的计算过程。
-
把签名(来自Bob的签名脚本)压入一个空的堆栈。因为它仅仅是一个数据,所以仅需要把他压入堆栈。然后把公钥(来自Bob的签名脚本)压入堆栈顶部。
-
从Alice的公钥脚本,执行
OP_DUP
指令。OP_DUP
会把栈顶的数据复制一份并压入栈顶 — 在这,就是在在栈顶复制一份Bob的公钥。 -
然后再执行
OP_HASH160
, 该指令会对栈顶的数据进行哈希,并把哈希值压入堆栈 — 在这,就是创建Bob公钥的哈希,并压入栈顶。 -
然后,Alice的脚本把第一个交易中,Bob给她的公钥压入栈顶。这时,在堆栈栈顶有两份Bob的公钥哈希值。
-
现在开始有意思了:Alice的公钥脚本会执行
OP_EQUALVERIFY
.OP_EQUALVERIFY
相对于执行了OP_EQUAL
,让后再执行OP_VERIFY
(在上面没有显示).OP_EQUAL
(在上面没有显示) 会检查在栈顶两个值;在这,它会检查从Bob完整公钥生成的公钥哈希值是否等于Alice提供的哈希公钥值(她创建交易1时,从Bob拿获得的)。OP_EQUAL
会弹出(即把数据从栈顶删除)刚比较的两个值,并把比较结果压入堆栈:0(false)或1(true)。OP_VERIFY
(在上面没有显示)会检测栈顶的值。如果值是false,它会立即停止计算,交易验证失败。否则它会把true从栈顶弹出。 -
最终,Alice的公钥脚本执行
OP_CHECKSIG
, 它会检查Bob提供的签名,以及Bob提供授权的公钥。如果签名跟公钥匹配,并且是通过所有需要的数据签名生成的,OP_CHECKSIG
会在栈顶压入true。
在完成公钥计算后,如果此时栈顶不是false,那么这个交易就是有效的(假使该交易没有什么其他问题)。
P2SH 脚本
公钥脚本被花费者创建,他们对脚本到底做了什么没有什么太大兴趣。而接受者却很关心脚本的条件,如果他们愿意,他们能要求花费者使用特定的公钥脚本。不幸的是,比起短比特币地址,自定义公钥脚本很不方便。 在广泛实现BIP70支付协议(后面在讨论)之前,还没有一个标准的方式实现程序之间通信。
为解决这些问题,在2012年,创建了支付脚本哈希(pay-to-script-hash)P2SH交易。这种交易能让花费者创建一个公钥脚本。该公钥脚本包含第二脚本(redeem 脚本)的哈希值。
P2SH的工作流程,如下图所示,看起来跟P2PKH几乎是一样的。Bob创建一个redeem脚本,可带有其他任何他要想的脚本,让后对redeem脚本进行哈希,再把redeem脚本的哈希值提供给Alice。Alice创建一个P2SH类的交易输出,包含Bob的redeem脚本哈希值。
当Bob想花掉输出时,他会为签名脚本提供完整的(可序列化)redeem脚本。比特币P2P网络确保redeem脚本的所计算出的哈希值跟Alice输出中提供的哈希值一样; 如果它是主要的公钥脚本,那么它会按其所期望的那样精确执行,如果redeem脚本没有返回false,就会让Bob发掉这个输出。
spendingP2SH.jpgRedeem脚本哈希跟公钥哈希有一样的属性 — 因此它可以变换成标准的比特币地址格式,仅一个小地方跟标准的地址不一样。这使得收集一个P2SH地址跟一个P2PKH地址一样同样简单。Redeem哈希会混淆Redeem里所有的公钥,因此P2SH脚本跟P2PKH脚本哈希一样安全。
标准交易
在早期的比特币版本,发现了好几个危险的bug后,增加了一个测试。该测试仅接受那些公钥脚本,签名脚本匹配一个最小安全可信模板集合,且交易其他部分没有违反另外一个加强网络的行为规则小集合的交易。 这就是 isStandard()
测试,能通过这个测试的交易被称之为标准交易。
非标准交易 — 这些交易会在上面的测试失败 — 可以被那些没有使用比特币内核默认设置的节点接收。如果这些交易被包含在区块中,他们也会回避IsStandard测试,并被处理。
标准交易,除了对那些广播有害交易的人,提高其攻击比特币网络难度,同时交易测试也实现了:为用户今天创建新的交易,防止在以后新增一些新的功能时,难度的增大。 比如,如上所述,每个交易包含一个版本号 — 如果用户肆意的更改版本号, 对于引入一个向后兼容功能时,作为一个工具,它会变的毫无用处。
自比特币内核0.9版本起,标准的公钥脚本类型如下:
支付公钥哈希(P2PKH)
P2PKH 是最为通用的公钥脚本类型,它被用于发送一个交易到一个或多个比特币地址。
Pubkey script: OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
Signature script: <sig> <pubkey>
支付脚本哈希(P2SH)
P2SH用于发送一个交易到脚本哈希。 每个标准公钥脚本能够被当做一个P2SH redeem脚本, 但是在编码实践中,在多个交易类型被标准化后,仅多重签名(multisig)公钥脚本有意义。
Pubkey script: OP_HASH160 <Hash160(redeemScript) OP_EQUAL
Signature script: <sig> [sig] [sig...] <redeemScript>
多重签名
目前,虽然P2SH多重签名通常被用于多重签名交易,在UTXO能被花掉前,这个基础脚本可用于需求多个签名[?]。
在多重签名脚本中,被称之为m-of-n, m是最小数量匹配公钥的签名;n是所提供公钥数量。m和n应该是操作符 OP_1
到OP_16
, 他们相对于相应的数字。
在比特币实现中,因为考虑兼容的问题,一个一位偏移错误必须被保留下来,OP_CHECKMULTISIG
会从堆栈消耗掉m所指定个数值(至少1个),因此,在签名脚本中的secp256k1签名列表必须以一个额外值OP_0
, 这个值会消耗掉,但不会被用。
签名脚本提供的签名的顺序,必须跟公钥脚本或redeem脚本中的公钥顺序一致。想了解可以查阅OP_CHECKMULTISIG了解更多详情。
Pubkey script : <m> <a pubkey> [B pubkey] [C pubkey] <n> OP_CHECKMULTISIG
Signature script: OP_0 < A sig> [B sig] [C sig...]
虽然它不是一个可分割的交易类型,这个一个2-of-3的P2SH多重签名:
Pubkey script: OP_HASH160 <Hash160(redeemScript)> OP_EQUAL
Redeem script: <OP_2> <A pubkey > <B pubkey > < C pubkey > <OP_3> OP_CHEKMULTISIG
Signature script: OP_O < A sig> < C Sig> <redeemScript>
公钥
公钥输出是一个简化了的P2PKH公钥脚本, 但是安全性比不上P2PKH,因此通常他们在新的交易中不再被使用。
Pubkey script: <pubkey> OP_CHECKSIG
Signature script: <sig>
空数据
在默认情况下,比特币内核0.9.0版会转发,处理空数据交易类型交易。后来,在一个可证明不可花掉的公钥脚本加入任意数据,全节点不必在他们的UTXO数据库中存储这些交易。使用空数据交易比起那些使UTXO数据库膨胀的交易会更好,因为空数据交易不能被自动裁掉;然而,如果有可能的话,把数据存储在交易外面是一个更好的选择。
假设他们遵守所有其他的共识规则,那么共识规则允许空数据输出可达到公钥脚本所支持的最大10000字节大小。比如压入数据的大小不会超过520字节。
在默认情况下,比特币内核0.9.x 到 0.10.x 会转发,处理空数据交易,在单个压入数据最大在40字节,且只有一个只支付0 satoshis空数据输出.
Pubkey Script: OP_RETURN <0 to 40 bytes of data>
(Null data scripts cannot be spent, so there's no signature script.)
在保持其他规则不变的情况下,比特币内核 0.11.x把默认大小增加到80个字节。
假设在不超过总字节的前提下,比特币内核0.12.0默认会转发,处理任意数量,小于83字节的数据压入的空数据输出。同时必须仅有一个支付 0 satoshis的空数据输出。
-datacarriersize
比特币内核配置选项,可以允许你设置比特币内核可转发,可处理的空数据输出最大字节数。
非标准交易
如果你在输出中使用任何非标准公钥脚本,那些使用默认设置的比特币节点,矿工不会接收,广播,处理你的交易。 当你试图广播你的交易到一个使用默认设置的比特币节点时,你会收到一个错误。
如果你创建一个redeem脚本,并做哈希处理,把哈希值用在一个P2SH输出里,比特币网络只会看到这个哈希值,因此不管redeem脚本内容是什么,比特币网络都会认为这个输出是有效的。这就允许对非标准脚本执行支付,从比特币内核0.11起,几乎所有的有效redeem脚本都可以被花掉,除了使用了NOP操作符的脚本。这些操作符是为未来软分叉而预留的,并只被那些没有准守标准内存池策略的节点转发,处理。
注意:标准交易是用来保护,帮助整个比特币网络,而不是防止你犯错的。创建一个可以让satoshi变成不可使用是一件非常容易的事情。
从比特币内核0.9.3起,标准交易必须满足以下几个条件:
-
交易必须完成: 要么它的锁定时间必须过去的某个时间,或其所在区块的区块高度必须少于等于当前区块高度,要么其他序列号都是0xffffffff。
-
交易大小必须小于100,000个字节。这大约是200多个典型单输入,单输出P2PKH交易的大小。
-
每个交易的签名脚本大小必须小于1650个字节。在P2SH交易中,这足够可以容纳15-of-15个使用压缩公钥的多重签名。
-
需要至少3个公钥的空(非P2SH)多重签名交易不再是标准交易。
-
交易的签名脚本只能把数据压入脚本求值堆栈。它不能压入新的操作符,除了那些仅压入数据到堆栈的操作符。
-
交易不可以包含:其输出中的satoshi数量,少于在一个典型的输入中,通常要花掉satoshi总量的1/3 的任何输出。 在一个默认设置的比特币节点,在目前,一个P2PKH或P2SH输出要花费546个satoshi。 有个例外: 标准空数据输出必须只接收0个satoshi。
签名哈希类型
OP_CHECKSIG
会从每个它要求值的签名中取出一个非堆栈参数,允许签名者决定交易的哪些部分需要 签名。因为签名可以防止这些交易的部分被修改,这也可以让签名者有选择的让其他人修改他们的交易。
这些各种各样要被签名的选项就叫做签名哈希类型。目前有三种可用的基本SIGHASH类型:
-
SIGHASH_ALL
, 这是默认选项,它会对所有的输入,输出进行签名,防止所有数据被修改,除了签名脚本。 -
SIGHASH_NONE
对所有的输入进行签名,但不对任何输出签名,这允许任何人修改satoshi的去向,除非其他签名使用其他签名哈希标志来保护输出。 -
SIGHASH_SINGLE
仅对跟输入相对应的输出进行签名(输出的输出索引号跟输入的索引号一样),确保没有人能改变交易中属于你的那部分,但允许其他签名者可以修改交易中属于他们的那部分。相应的输出必须存在,或被签上数值“1”,以突破签名安全方案。这里的输入跟其他输入一样,都被包含在签名里面。其他没有包含在签名里面的输入的序列号是可以被更新的。
使用SIGHASH_ANYONECANPAY
(任何人可以支付)标志可以修改这些基本类型。有如下三种组合:
-
SIGHASH_ALL|SIGHASH_ANYONECANPAY
对所以输出签名,但仅对一个输入签名,同时允许任何人添加,删除其他输入,因此任何人可以贡献额外的satoshi,但不能改变发送satoshi的数量,以及目的地。 -
SIGHASH_NONE|SIGHASH_ANYONECANPAY
仅对一个输入签名,同时允许任何人添加,删除输入,输出,因此任何获得该交易拷贝人都可以自由地把它花掉。 -
SIGHASH_SINGLE|SIGHASH_ANYONECANPAY
签名一个输入且与其相对应的输出。允许任何人添加,删除其他输入。
因为每个输入都被签名,一个有多个输入的交易,其不同部分可以用多个签名哈希类型来签名。例如,一个用NONE
签名单输入交易可以让把它添加到区块链的矿工修改其输出。另一方面,如果一个带有两个输入的交易有一个输入使用NONE
来签名,另外一个使用All
来签名,这个All
签名者可以在不要跟NONE
签名者商议,就可以选择怎么花掉satoshi。 但是其他任何人不能修改这个交易。
锁定时间和序列号
所有签名类型要签名的数据是:交易的锁定时间。(在比特币内核源码中是:mLockTime) 锁定时间表示交易最早能加入到区块链的时间。
锁定时间允许签名者创建时间锁定交易。 这种交易仅在未来的某个时间才会有效,这给签名者一个改变他们想法的机会。
如果任何签名者改变他们的想法,他们能创建一个新的非锁定时间交易。这个新的交易,作为之前交易的输入,会使用之前锁定交易的输出作为其输出。在锁定时间到期之前,如果这个新的交易被添加到区块链,就使之前的锁定交易无效。
之前的比特币内核版本提供了一个功能,可以防止交易签名者使用上面的方法取消时间锁定交易,但为了防止拒绝访问攻击,这个功能一个必要的部分已被禁止。这个系统中遗留部分是每个输入中的4字节序列号。 序号号意味着允许多个签名者同意更新一个交易。当他们完成交易更新后,他们可以同意把每个输入的序列号设置成0xffffffff(4字节无符号) - 这可以允许交易加入到区块链中,即便锁定时间还没到期。
即使到今天,把所有序列号设置成0xffffffff(在比特币内中,默认是这个值)可以禁止掉所有的时间锁,因此如果你想是一个时间锁,至少一个输入的序列号是小于0xffffffff的。因为序列号没有其他用途,所有把序列号设置成0就可以开启时间锁。
mLockTime是一个无符号4字节整型数字,其可以通过两种方式来解析:
-
如果小于50亿,mLockTime就被解析成区块高度。这个交易就可被添加到任何等于,或高于这个区块高度的区块中。
-
如果大于等于50亿,mLockTime就以Unix epoch(从1970-1-1 00:00 UTC时间起,到现在过去的秒数,到目前为止有13.95亿秒) 时间格式来解析。这个交易就可被加入任何区块时间大于mLockTime的区块中。
交易费用和零钱
交易费用的支付是基于签名交易字节太小来计算。每个字节的费用是基于,在被挖出区块其所占空间来计算,需求的空间越大,费用就越高。在区块链章节中所述,交易费用是给矿工的,因此最终是由每个矿工来决定选择最低的交易费用。
有一个”高优先级交易“的概念,它可以花掉那些长时间没有用过的satoshis。[?]
在一起,这些”优先“交易通常可以不需交易费。在比特币内核0.12前,每个区块会高优先级交易预留50kb空间,然而,现在默认设置成0kb。在优先级区域后,所有交易按他们每字节费用来按序排列,高费用的交易优先会被加到队列中,直到可用空间填满。
自从比特币内核0.9版本后,在比特币网络中,广播一个交易需要支付一笔最小费用(目前是1000satoshi)。在区块有足够多用的空间前,任何支付这个最小费用的交易要准备好等很长一段时间。这非常重要,想知道为什么,请看支付验证章节.
因为每个交易花UTXO,且因为一个UTXO只能被使用一次,UTXO里面的satoshi必须一次使用完,或作为交易费用。UTXO里面的satoshi数量跟其他要支付的一样多是很少见的,因此会有多个交易包含到一个零钱输出。
零钱输出是正规的输出。它把那些零散的satoshi从UTXO转到花费者。他们能重用UTXO里面的P2PHK公钥哈希或P2SH脚本哈希,但是我们会在下一小节所讲述,强烈建议把零钱输出发送到一个新的P2PKH或P2SH地址。
避免密钥重用
在一个交易中,支付者,接受者可以查看交易中所用到的所有公钥或者地址。这可以运行任意一方使用公共的区块链来跟踪这个地址或公钥过去,未来所有的交易。
如果同一个公钥被经常使用,比如人们使用比特币地址(公钥哈希)作为一个固定的支付地址,其他人就可以很容易的跟踪这个人支付,接受的习惯,包括已知掌控的地址中有多少比特币。
其实我们不必如此。如果一个公钥只使用两次,一次用来接受付款,一次用来花掉这次的付款,这样用户就可以获得极大的财务隐私。
更好的办法是,当在接收支付或者创建输出时,可使用新的公钥或者独一无二的地址跟其他技术(后续会讲到)结合起来,比如CoinJoin或者避免混合,就可以提高使用区块链来跟着用户如何接收,花掉他们比特币的难度。
避免密钥重用也可以提高安全防护,比如通过公钥(假设的),或签名比对(在当今,如下特定环境下,会有更多常规攻击的假设)来实现重建私钥。
-
独一无二的(非重用)P2PKH,P2SH地址可防止第一个类型攻击,其通过隐藏ECSDA公钥(被哈希处理过的),直到第一次发送到这些地址的satoshi被花掉,因此攻击实际上是无用的,除非他们能在1,2个小时内重建私钥,这很好的通过区块链网络保护了交易。
-
独一无二的(非重用)私钥可以防止第二种类型攻击,其通过仅为每个私钥生成一个签名,因此在对比攻击中,攻击者永远无法获得后续的签名。当今,现存的比对攻击,在签名是,没有足够的熵可用时,或熵使用通过别的方式被暴露了,比如边信道攻击.
因此,出于对于隐私,安全的考虑,在你构建应用程序时,不管什么时候,鼓励尽可能的避免公钥重用,组织用户重要比特币地址。如果你的应用程序需要提供一个固定的URI,用于接受付款,请看下面的bitcoin:
[URL章节](https://bitcoin.org/en/developer-guide#bitcoin-uri)。
交易延展性
任何比特币签名哈希类型都不会保护签名脚本,这会导致给有限的拒绝服务攻击开启了一扇门,这就叫做交易延展性。签名脚本包含secp256k1签名,secp256k1签名是不能给自己签名的,这就让攻击者可以对交易做非功能修改,这也不会让交易失效。比如,攻击者可以在签名脚本中加入一些数据。这些签名脚本在之前公钥脚本被处理前会被丢掉。
虽然这些修改是非功能性的修改 — 因此他们即不会改变交易输入,也不会修改交易输出 — 不过他们的确会改名交易的哈希值。因为每个交易会使用哈希值(作为交易id txid)来链接到之前的交易,一个被修改过的交易其txid跟其创建者txid就不一样了。
这对于立马加入到区块链中的交易,这不是个问题。但是当在交易被加入到区块链之前,交易输出被花掉时,就成问题了。
比特币开发者已经致力于减少标准交易之间为交易的延展性,其他的一个成果是:BIP141:SegWit隔离见证。这个功能已被比特币内核支持,并在2017.8月激活。当隔离见证不被使用时,新的交易不应依赖于之前还没有加入到区块链中的交易,特别是有大量的satoshi需要紧急处理时。
交易的延展性也会影响支付攻击。比特币内核RPC(远程调用)接口可以让你通过他们的交易ID(txid)跟踪交易, 但是如果交易id改变了,因为交易被修改了,它就会看起来像交易从网络中消失了。
当前交易跟踪最佳实践告诉我们交易应该通过交易输出(UTXO 它以输入的方式被花掉)来跟踪,因为不让交易无效,是无法更改UTXO的。
更进一步的最佳实践向我们明示了,如果一个交易看起来从网络中消失了,那么需要通过让丢失的交易无效后,在重发交易。有一个办法总是可行的,就是确保重发的支付花掉同样的交易输出(在丢失交易中作为交易输入)。
声明:
文中带有[?]的地方,表示我对此翻译明显感觉不太对的,后续会不断修正。
初次翻译,可能会有些地方翻译的不好,不地道,甚至错误,如果有发现,还请留言,指出,以便我好修正,谢谢!