《精通比特币第二版》中文版第六章交易2/3
精力有限,后期修订以github为主,建议大家移步github链接阅读更新版本,感谢理解:
https://github.com/tianmingyun/MasterBitcoin2CN
本文约5500字。
6.3.3 交易费
大多数交易包含交易费,这是为了在网络安全方面给比特币矿工一种补偿。费用也可以作为一个安全机制本身,使经济上不利于攻击者通过交易来淹没网络。在挖矿一章中,对于挖矿、费用和矿工得到的 奖励,有更详细的讨论。
这一节解释交易费是如何被包含在日常交易中的。大多数钱包自动计算并计入交易费。但是, 如果你编程构造交易,或者使用命令行接口,你必须手动计算并计入这些费用。
交易费可当作是为了包含(挖矿)一笔交易到下一个区块中的一种鼓励,也可当作是对于欺诈交易和任何种类的系统滥 用,在每一笔交易上通过征收一笔小成本的税而造成的一种妨碍。交易费被挖出这个区块的矿工得到,并且记录在这个 交易的区块链中。
交易费基于交易的尺寸,用千字节来计算,而不是比特币的价值。总的来说,交易费基于市场所设置,生效于比特币网 络中。矿工依据许多不同的标准,按重要性对交易进行排序,这包括费用,并且甚至可能在某种特定情况下免费处理交 易。交易费影响处理优先级,这意味着有足够费用的交易会更可能地被包含在下一个挖出的区块中;与此同时,交易费不足或者没有交易费的交易可能会被推迟,基于尽力而为的原则在几个区块之后被处理,甚至可能根本不被处理。交易 费不是强制的,而且没有交易费的交易也许最终会被处理,但是,包含交易费将提高处理优先级。
随着时间的过去,交易费的计算方式和交易费在交易优先级上的影响一直在发展。起初,交易费是网络中的一个固定常 数。渐渐地,交易费的结构被放宽了,以便被市场基于网络容量和交易量而强制影响。自从至少2016年初以来,比特币的能力限制已经造成交易之间的竞争,从而导致更高的费用,并有效地使自由交易成为过去。 零费用或非常低的费用交易很少被开采,有时甚至不会在网络上传播。
在Bitcoin Core中,费用转移策略由minrelaytxfee选项设置。 当前默认的minrelaytxfee是每千字节0.00001比特币或者millibitcoin的1%。 因此,默认情况下,费用低于0.0001比特币的交易被视为免费的,只有在存储空间不满时才会处理; 否则,它们被丢弃。 比特币节点可以通过调整minrelaytxfee的值来覆盖默认费用策略。
任何创建交易的比特币服务(包括钱包,交易所,零售应用程序等)都必须实施动态费用。动态费用可以通过第三方费用估算服务或内置的费用估算算法来实现。如果您不确定,请从第三方服务开始,如果您希望删除第三方依赖项,您应当有设计和部署自己的算法的经验。
费用估算算法根据“竞争”交易提供的能力和费用计算适当的费用。这些算法的范围从简单(最后一个块中的平均值或中位数)到复杂(统计分析)。他们估计必要的费用(以字节为单位),这将使得交易具有很高的可能性被选择并包含在一定数量的块内。大多数服务为用户提供高,中,低优先费用的选择。高优先级意味着用户支付更高的费用,但交易可能会被包含在下一个块中。中低优先级意味着用户支付较低的交易费用,但交易可能需要更长时间才能确认。
许多钱包应用程序使用第三方服务进行费用计算。一个流行的服务是http://bitcoinfees.21.co,它提供了一个API和一个可视图,显示了satoshi / byte中不同优先级的费用。
提示静态费用在比特币网络上不再可行。 设置静态费用的钱包将导致用户体验不佳,因为交易往往会被“卡住”,并保持未确认。 不了解比特币交易和费用的用户被“卡住”交易感到沮丧,因为他们认为他们已经失去了资金。
下面费用估算服务bitcoinfees.21.co中的图表显示了10个satoshi / byte增量的费用的实时估计,以及每个范围的费用交易的预期确认时间(分钟和块数)。 对于每个费用范围(例如,61-70 satoshi /字节),两个横条显示过去24小时(102,975)中未确认交易的数量(1405)和交易总数,其费用在该范围内。 根据图表,此时推荐的高优先费用为80 satoshi / byte,这可能导致交易在下一个块(零块延迟)中开采。 长远来看,中间交易规模为226字节,因此交易规模的建议费用将为18,080 satoshis(0.00018080 BTC)。
图6-2bitcoinfees.21.co提供的费用估算服务费用估算数据可以通过简单的HTTP REST API(https://bitcoinfees.21.co/api/v1/fees/recommended)来检索。 例如,在命令行中使用curl命令:
$ curl https://bitcoinfees.21.co/api/v1/fees/recommended
{"fastestFee":80,"halfHourFee":80,"hourFee":60}
API返回一个具有当前费用估计的JSON对象,以最快的确认(最快的Fee),在三个块(halfHourFee)和六个块(hourFee)内确认,以每个字节为单位。
6.3.4 把交易费加到交易中
交易的数据结构没有交易费的字段。相反地,交易费通过所有输入的总和,以及所有输出的总和之间的差来表示。从所 有输入中扣掉所有输出之后的多余的量会被矿工收集走。
交易费被作为输入减输出的余量:
交易费 = 求和(所有输入) - 求和(所有输出)
对于交易来说,这是一个很让人摸不着头脑的元素,但又是很重要的问题。因为如果你要构造你自己的交易,你必须确 认你没有疏忽地包含了一笔少于输入的、量非常大的费用。这意味着你必须计算所有的输入,如果必要的话进行找零, 不然的话,结果就是你给了矿工一笔可观的劳动费!
举例来说,如果你消耗了一个20比特币的UTXO来完成1比特币的付款,你必须包含一笔19比特币的找零回到你的钱 包。否则,那剩下的19比特币会被当作交易费,并且会被挖出你的交易到一个区块中的矿工收走。尽管你会受到高优先 级的处理,并且让一个矿工喜出望外,但这很可能不是你想要的。
提示如果你忘记了在手动构造的交易中增加找零的输出,系统会把找零当作交易费来处理。“不用找了!”也许不是你想要的结果。
让我们来看看在实际中它如何工作,重温一下Alice在咖啡店的交易。Alice想为咖啡支付0.015比特币。为了确保这笔交 易能立即被处理,Alice想支付一笔交易费,比如说0.001。这意味着总交易成本会变成0.016。因此她的钱包需要凑齐 0.016或更多的UTXO。如果需要,还要加上找零。我们假设他的钱包有一个0.2比特币的UTXO可用。他的钱包就会消耗 掉这个UTXO,创造一个新的0.015的输出给Bob的咖啡店,另一个0.184比特币的输出作为找零回到Alice拥有的钱包, 并留下未分配的0.001比特币内含在交易中。
现在让我们换个例子。Eugenia,我们在菲律宾的儿童募捐项目主管,完成了一次为孩子购买教材的筹款活动。她在世 界范围内接收到了好几千个小数额的捐款,总额是50比特币。所以她的钱包塞满了非常小的UTXO。现在她想用比特币 从本地的一家出版商购买几百本的教材。
现在Eugenia的钱包应用想要构造一个单笔大额付款交易,它必须从可用的、由很多小数额构成的大的UTXO集合中寻 求钱币来源。这意味着交易的结果是从上百个小数额的UTXO中作为输入,但只有一个输出用来付给出版商。输入数量 这么巨大的交易会比一千字节要大,也许总尺寸会达到两至三千字节。结果是它需要更高的交易费来满足0.0001比特币的网络费。
Eugenia的钱包应用会通过测量交易的大小,乘以每千字节需要的交易费,来计算适当的交易费。很多钱包会通过多付 交易费的方式来确保大交易被立即处理。高交易费不是因为Eugenia付的钱很多,而是因为她的交易很复杂并且尺寸很 大——交易费是与参加交易的比特币值无关的。
6.4比特币交易脚本和脚本语言
Bitcoin交易脚本语言,称为脚本,是一种类似Forth的逆波兰表达式堆栈执行语言。 如果听起来不知所云,是你可能还没有学习20世纪60年代的编程语言,但是没关系,我们将在本章中解释一下。 放置在UTXO上的锁定脚本和解锁脚本都以此脚本语言编写。 当一笔比特币交易被验证时,每一个输入值中的解锁脚本被与其对应的锁定脚本同时 (互不干扰地)执行,从而查看这笔交易是否满足使用条件。
脚本是一种非常简单的语言,被设计为在范围上有限制,并且可以在一系列硬件上执行,可能与嵌入式设备一样简单。 它需要最少的处理,并且不能做许多现代编程语言可以做的花哨的事情。 为了用于验证可编程货币,这是一个认真考虑的安全功能。
如今,大多数经比特币网络处理的交易是以“Alice付给Bob”的形式存在的。同时,它们是以一种称为“P2PKH”(Pay-toPublic-Key-Hash)脚本为基础的。然而,通过使用脚本来锁定输出和解锁输入意味着通过使用编程语言,比特币交易可以包含无限数量的条件。当然,比特币交易并不限于“Alice付给Bob” 的形式和模式。
这只是这个脚本语言可以表达的可能性的冰山一角。在这一节,我们将会全面展示比特币交易脚本语言的各个组成部 分;同时,我们也会演示如何使用它去表达复杂的使用条件以及解锁脚本如何去满足这些花费条件。
提示比特币交易验证并不基于一个不变的模式,而是通过运行脚本语言来实现。这种语言可以表达出多到数不尽的条 件变种。这也是比特币作为一种“可编程的货币”所拥有的权力。
6.4.1 图灵非完备性
比特币脚本语言包含许多操作,但都故意限定为一种重要的方式——没有循环或者复杂流控制功能以外的其他条件的流 控制。这样就保证了脚本语言的图灵非完备性,这意味着脚本的复杂性有限,交易可执行的次数也可预见。脚本并不是 一种通用语言,施加的这些限制确保该语言不被用于创造无限循环或其它类型的逻辑炸弹,这样的炸弹可以植入在一笔 交易中,通过引起拒绝服务的方式攻击比特币网络。受限制的语言能防止交易激活机制被人当作薄弱环节而加以利用。
6.4.2 非主权验证
比特币交易脚本语言是无国家主权的,没有国家能凌驾于脚本之上,也没有国家会在脚本被执行后对其进行保存。所以 需要执行脚本的所有信息都已包含在脚本中。可以预见的是,一个脚本能在任何系统上以相同的方式执行。如果您的系 统对一个脚本进行验证,可以确信的是每一个比特币网络中的其他系统也将对其进行验证,这意味着一个有效的交易对 每个人而言都是有效的,而且每一个人都明白这一点。这种对于结果的可预见性是比特币系统的一项重要良性特征。
6.4.3 脚本创建(锁定与解锁)
比特币的交易验证引擎依赖于两类脚本来验证比特币交易:一个锁定脚本和一个解锁脚本。
锁定脚本是一个放在一个输出值上的“障碍”,同时它明确了今后花费这笔输出的条件。由于锁定脚本往往含有一个公钥 (即比特币地址),在历史上它曾被称作一个脚本公钥代码(scriptPubKey)。由于认识到这种脚本技术存在着更为宽泛的可能性,在本书中,我们将它称为一个“锁定脚本”。在大多数比特币应用源代码中,脚本公钥代码便是我们所说的锁定脚本。您还将看到被称为验证脚本(witness script)的锁定脚本(参见[segwit]章节)或更一般地作为加密难题或者加密拼图(cryptographic puzzle)。 这些术语在不同的抽象层次上都意味着同样的东西。
解锁脚本是一个“解决”或满足被锁定脚本在一个输出上设定的花费条件的脚本,同时它将允许输出被消费。解锁脚本是 每一笔比特币交易输出的一部分,而且往往含有一个被用户的比特币钱包(通过用户的私钥)生成的数字签名。由于解 锁脚本常常包含一个数字签名,因此它曾被称作ScriptSig。你也会看到解锁脚本被称为见证人witness(参见[segwit]章节)。在大多数比特币应用的源代码中,ScriptSig便是我们所说的解锁脚本。考虑到更宽泛的锁定脚本要求,在本书中,我们将它称为“解锁脚本”。但并非所有解锁脚本都一定会包含签 名。
每一个比特币客户端会通过同时执行锁定和解锁脚本来验证一笔交易。每个输入都包含一个解锁脚本,并引用了之前存在的UTXO。 验证软件将复制解锁脚本,检索输入引用的UTXO,并从该UTXO复制锁定脚本。 然后依次执行解锁和锁定脚本。 如果解锁脚本满足锁定脚本条件,则输入有效(请参阅单独执行解锁和锁定脚本部分)。 所有输入都是独立验证的,作为交易总体验证的一部分。
请注意,UTXO被永久地记录在块链中,因此是不变的,并且不受在新交易中引用的失败尝试的影响。 只有正确满足输出条件的有效交易才能将输出视为“已用”,并从未用空的交易输出集(UTXO set)中删除。
下图是解锁和锁定最常见类型的比特币交易(对公钥哈希的付款)的脚本的示例,显示了在脚本验证之前从解锁和锁定脚本的并置产生的组合脚本 。
图6-3结合scriptSig和scriptPubKey来评估交易脚本
6.4.3.1脚本执行堆栈
Bitcoin的脚本语言被称为基于堆栈的语言,因为它使用称为堆栈的数据结构。堆栈是一个非常简单的数据结构,可以被视为一叠卡片。一个栈允许两个操作:push和pop。 Push在堆栈顶部添加一个项目。 Pop从堆栈中删除顶级项。堆栈上的操作只能作用于堆栈上的最上面的项目。堆栈数据结构也称为后进先出或“LIFO”队列。
脚本语言通过从左到右处理每个项目来执行脚本。数字(数据常量)被推到堆栈上。操作员从堆栈中推送或弹出一个或多个参数,对其进行操作,并可能将结果推送到堆栈上。例如,OP_ADD将从堆栈中弹出两个项目,添加它们,并将结果推送到堆栈上。
条件运算符评估一个条件,产生一个TRUE或FALSE的布尔结果。例如,OP_EQUAL从堆栈中弹出两个项目,如果它们不相等,则它们将为TRUE(TRUE由数字1表示),否则为FALSE(由零表示)。比特币交易脚本通常包含条件运算符,以便它们可以产生表示有效事务的TRUE结果。
6.4.3.2一个简单的脚本
现在让我们将关于脚本和堆栈的内容应用到一些简单的例子中。
在下图中,脚本“ 2 3 OP_ADD 5 OP_EQUAL ”演示了算术加法操作符 OP_ADD ,该操作符将两个数字相加,然后把结果推送到 堆栈, OP_EQUAL 是验算之前的两数之和是否等于 5 。为了简化起见,前缀OP_在一步步的演示示例过程中将被省略。有关可用脚本操作符和函数的更多详细信息,请参见[tx_script_ops]。
虽然大多数的解锁脚本都指向一个比特币地址或公钥,因而如果想要使用资金则需验证所有权,但脚本本身并不需要如 此的复杂。任何解锁和锁定脚本的组合如果结果为真,则为有效。前面被我们用于说明脚本语言的简单算术运算同样也 是一个有效的锁定脚本,该脚本能用于锁定交易输出。
使用部分算数运算示例脚本作用锁定脚本:
3 OP_ADD 5 OP_EQUAL
该脚本能被以解锁脚本为输入的一笔交易所满足,解锁脚本为:
2
验证软件将锁定和解锁脚本组合起来:
2 3 OP_ADD 5 OP_EQUAL
正如在图6-4中所看到的,当脚本被执行时,结果是OP_TRUE,从而使得交易有效。不仅该笔交易的输出锁定脚本有 效,同时UTXO也能被任何知晓这个运算技巧(知道是数字2)的人所使用。
如果堆栈顶部的结果显示为真(标记为{0×01}),即为任何非零值或脚本执行后堆栈为空情形,则交易有效。如 果堆栈顶部的结果显示为假(0字节空值,标记为{})或脚本执行被操作符禁止,如OP_VERIFY、 OP_RETURN,或有条件终止如OP_ENDIF,则交易无效。详见附录相关内容。
以下是一个稍微有些复杂的脚本,它用于计算 2+7-3+1 。注意,当脚本包含多个操作符时,堆栈允许一个操作符的结果 作用于下一个操作符。
2 7 OP_ADD 3 OP_SUB 1 OP_ADD 7 OP_EQUAL
请试着用纸笔自行演算脚本,当脚本执行完毕时,你会在堆栈得到正确的结果。
本章未完。待续。
参考内容:
1、本文部分内容摘自《精通比特币》第一版中译本,特此说明并致谢。
我正在发起“和我一起阅读《精通比特币第二版》”活动。
我把这作为一次认知学习法的实践。
我希望将认知学习法与《精通比特币第二版》的研读结合起来,尝试总结出一套可行的区块链知识技能快速入门的方法。
这也将成为我们大家一起合作编写的一本书《认知学习比特币》的雏形(所有有价值的讨论都将成为这本书的素材)。
而且我更希望通过本次认知学习方法论的实践以及迭代,将这种经过实践的学习方法迁移到更多领域的学习中。
所以我们会有第二季,第三季......
欢迎扫描二维码加入。
欲知详情请扫描二维码