比特币现金BCH重启的智能合约操作码OP_CODE的详解 —— Steve Shadders

在比特币的最初版本中存在几个被禁用的操作码,但在5月15日升级比特币现金协议时他们被建议重新激活。

作为《启用这些旧操作码之规范》的共同作者,我承认我不理解为什么社区希望我们清楚地解释提出这个建议的原因。在开发者中,脚本语言中基本操作的用例非常常见而无需说明。我们每天都多次使用算术、字符串操作和按位逻辑等基本操作,如果没有它们,就几乎不可能编出任何有用的代码。

然而,比特币现金社区远不只有开发者。事实上,以上论点即使对开发者有吸引力,仍然没有给出具体的例子来说明在比特币现金环境中这些操作码是如何被使用的。也没有解释为什么它们被禁用,或者为什么重新启用它们是安全的。这些都是比特币现金社区有权听到的解释,我们试着纠正这点。

被禁用操作码的历史

LSHIFT bug和RETURN bug

2010年7月28日在测试网络上发现并演示了两个bug。第一个导致比特币在某些机器上处理包含OP_LSHIFT的交易时崩溃。第二个利用了交易处理代码中的另一个bug,允许攻击者消费掉不属于他们的比特币。两者都没有在主网络上被利用,且两者都在比特币0.3.5版中得以修正。

发现这些bug之后,许多当时未使用的脚本语言被禁用以确保安全。

本质上出于谨慎和没有足够的时间去充分探索和修复需要处理的边缘用例,因而决定简单地禁用任何存在疑问甚至是暗示疑问的操作码。比特币早期的关注点是如何获得更简单的安全支付选项并进行彻底的测试。对更复杂用途的探索被不可避免地推迟到后来。

Peter Todd对为什么OP_CAT(及其他代码)被禁用的解释(比如我们惊慌了):

https://twitter.com/ryaneshea/status/672461252736761856

nchain2

更多操作码历史:

https://scalingbitcoin.org/stanford2017/Day1/SB2017_script_2_0.pdf

同一演示文稿的视频在这里:

https://www.youtube.com/watch?v=LDF8bOEqXt4&feature=youtu.be&t=2h23m30s

为什么重新启用它们?

比特币是用一种丰富的脚本语言创建的。如果它的用途仅限于两个私钥之间的直接支付,就算包括多重签名交易,那也根本不需要脚本语言。这些功能完全可以简单地通过硬编码实现,代码还能大大地简化了。但比特币是建立在一种具有丰富指令集的脚本语言之上的,这表明它始终是一个用更复杂的规则集去管理资金转移的基础平台。将比特币恢复到最初的预定设计(修复bug)本身就是一个原因。

7年过去了,现在人们对这些操作码的边缘用例有了更好的理解。此外,它们当初是在仓促的情况下被迫禁用的。BCH社区现在已经有了充裕的时间来彻底解决这些问题。

7年也给了人们很多时间来思考如何使用这些操作码。实际上,加密生态系统各个部分(例如Elements Alpha)已启用它们,以解锁其中一些用例。

为什么只建议重新启用一些?

只是为了延续谨慎的做法。在5月15日的协议升级中只启用一些操作码不仅限制了风险,而且使所有参与的开发人员都能够更加关注每一个操作码。保持很小的变更范围,BCH开发人员社区就有机会改进这些特性的启用过程。这一过程包括调度、开发规范、吸引同行评审、提炼、达成对高质量阈值的一致认同,构建和测试验收及发布方法,当然还有对上述所有步骤的执行。

什么是用例?

以下是近年来发表或讨论过的用例汇编。其中很多用例在多个操作码下被引用,因为它们需要不止一个操作码。毫无疑问,这并不是一份完整的列表。

OP_CAT

https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-May/014375.html

多方哈希锁:

安全和紧凑地验证许多哈希和哈希预映射。这将显著地减少链下的Tumblebit交易。例如,交易TxA检查交易TxB释放的预映射x1, x2, …, x10 得到 y1=H(x1), y2=H(x2), …, y10=H(x10)。

现在代入y1,…y10并检查预映射哈希是否正确。

有了OP_CAT,你只需要在TxA中存储一个哈希,即yhash。

ytotal = H(OP_CAT(H(OP_CAT(y1, y2)),y3)…y10)

然后TxA可以将TxB提供的所有预映射转为哈希,并确认它们哈希到TxA。这将使TxA的大小从大约1032B减少到32+1016B。

https://blockstream.com/2015/08/24/treesignatures.html

简单的默克尔树验证:

这个用例能使多重签名的规模变得更大。当前脚本大小限制的理论极限是四十亿之一。在886字节的脚本中可达到一个更实用的限制——二十万之一,如果没有OP_CAT则需要8mb。

OP_SPLIT

https://scalingbitcoin.org/stanford2017/Day1/SB2017_script_2_0.pdf

弱哈希与OP_LEFT:

弱哈希比通常的哈希要小。它们在比特币地址中被用作可提供一定程度的错误检查的校验,(一个32位校验和错误未被发现的几率为2^32之一)。它们可以通过取出一个哈希并剥离前面(或后面)的n个字节来生成。

微型工作量证明:

确保scriptSig安全的计算成本是昂贵的,因为收款人要生成一个微型工作量证明。签名或哈希要以特定的位序列开始。对于小于2^32的数字,这可以通过使用OP_SPLIT和OP_LESSTHAN来实现。更大的数字也可以用OP_SPLIT与OP_EQUALS,但仅限于2^n的难度且n必须是8的倍数(你只能使用整个字节)。对于较大的数字,将OP_SPLIT和OP_AND组合可达到2的任意幂的有效难度。如果你想让工作量证明平均花费80亿次尝试来解决这个脚本,可能需要最后的33位为零:

SIZE 5 SUB SPLIT 0x01FFFFFFFF AND IF RETURN ELSE //finish script

解释:

SIZE 5 SUB – 获取pow_hash的长度,并减去5 SPLIT –以 len(pow_hash)-5为分割点,将最后五个字节剥离 0x01FFFFFFFF AND – 将最左边7个字节设为零 IF RETURN –如果最右边的33位不都为0,则脚本失败 ELSE //finish script1

检查字节数组的各个部分,比如检查签名的SIGHASH_FLAGS:

这个用例为强行限制资金的使用方式。

| 1 PICK SIZE 1 SUB SPLIT 1 ROLL DROP

解释:

1 PICK –复制签名到栈顶 SIZE 1 SUB –获取签名长度并减去1 SPLIT –以len(sig) -1为分割点,将最后一个字节剥离 1 ROLL DROP –将分割字节的左部移到栈顶,并将其放在栈顶的签名的最后一个字节

0x80 AND VERIFY 解释:

0x80 – 将0x80推到堆栈上(这里是ANYONECANPAY标志但也可以为其他标志) AND – 如已设置SIGHASH_ANYONECANPAY标志,签名和 0x80的最后一个字节返回0x80。否则,返回0x00。 VERIFY – 如果标志未设置,则脚本失败。 //do remainder of P2PKH script1

堆栈状态现在为: ,根据p2pkh需要。完整的脚本将为:

| 1 PICK SIZE 1 SUB SPLIT 1 ROLL DROP 0x80 AND VERIFY DUP HASH160 EQUALVERIFY CHECKSIG

OP_SPLIT与OP_DATASIGVERIFY的使用:

如果一个交易产生签名数据,如“BCHUSD:20180228:120000:132500:119500:130000” (BCHUSD市场,2018年2月28日,开盘价120000 美分 / BCH,最高价132500,最低价119500,收盘价 130000)。在验证签名之后,OP_SPLIT将被用于从该数据中提取数值以进行决策。例子:确认数据是针对BCHUSD市场的,日期是2018-02-28,收盘价大于125000。

按位

AND/OR:设置和检查位标志,这是一种很有用的方法,可以简洁地表示一大组布尔值。

如果实现其中任何一个操作,其他两个都是微不足道的添加(最简单的实现方法是一个用例陈述和一行代码)。所有其他因素,如对操作长度和格式的限制,都是通过实现第一个来处理的。

OP_AND

检查和清除位标志

要求签名使用特定的sighash标志(参见OP_SPLIT下的详细描述)。

OP_OR

设置位标志。检查未设置的位标志。

OP_XOR

https://scalingbitcoin.org/stanford2017/Day1/SB2017_script_2_0.pdf

用OP_XOR生成确定性随机数: 组合不同方的机密值。

http://www.cs.technion.ac.il/~idddo/cointossBitcoin.pdf

使用OP_XOR和OP_MOD将两次抛硬币合并为一个结果。本文的大部分内容都是关于两方在不信任的情况下进行抛硬币的协议,最后一个阶段是用xor和mod把参与者选择的随机值组合为一个结果。

这里有类似的描述:https://github.com/jl2012/bips/blob/mastopcodes/bip-mastopcodes.mediawiki#Trustfree_betting

https://en.wikipedia.org/wiki/Xorshift

用XOR快速生成确定性随机数: – 注:这个用例也需要用OP_LSHIFT,不建议对可能的硬分叉使用OP_LSHIFT。

算术

智能合约中的任何链计算都需要算术。目前可以使用非常大的脚本对高阶操作符进行模拟。OP_MUL是一系列的OP_ADD。OP_DIV是一系列的OP_SUB,如果结果小于除数,则递增计数器并在每个步骤中进行检查。OP_MOD是一系列的OP_SUB,一旦有负数结果,就采用OP_ABS的值。由于在脚本中不存在循环(而且从未是原始设计的一部分),并且脚本的大小有限制,因此这得有一个实际的限制。当操作的两个值都为变量时(相反情况是有一个值为常量),情况也变得更加复杂。

使用谨慎的方法是有必要的,这就是为什么并不是所有算术运算符都是为同一个硬分叉提出来的。

OP_MOD

加密数学 – 当前的32位限制要求使用OP_SPLIT来实现这一点。然而,增加算术输入的有效位长度的先决条件就是包含它。

http://www.cs.technion.ac.il/~idddo/cointossBitcoin.pdf – 也需要OP_XOR

OP_DIV

没有特定的用例,但它是OP_MOD行为的子集,所有适用于DIV的边缘用例都已经由MOD处理。

数据类型

脚本虽然没有显式数据类型系统,但在实践中隐式地使用了两种数据类型:数字和字节数组。算术、字符串和按位等运算符被设计为使用特定的数据类型(分别为数字和字节数组)。为了缓解规范的同行评审过程中对这些操作码会偶尔误用不正确数据类型的担忧,决定引入两种新的操作码,以便在类型之间提供安全且显式的数据转换。这仅仅是为了让脚本语言更安全,更容易使用,而不是添加特定的用例。这个好处不仅适用于本文所述的操作码,而且适用于许多现有的操作码。

OP_NUM2BIN

参见“Script data types”章节的规范:

https://github.com/shadders/uahf-spec/blob/reenable-op-codes/reenable-op-codes.md

OP_BIN2NUM

参见“Script data types”章节的规范:

https://github.com/shadders/uahf-spec/blob/reenable-op-codes/reenable-op-codes.md

结论

此列表并非详尽无遗。但它确实说明了一些用例,因为这些操作码是脚本语言的基本构建块,其用途非常广泛。这些例子都是人们在相信自己永远不可能看到光明的背景下所想到的。既然它们的使用存在真实的可能性,那么我们有理由相信,创造性思维将会更多地关注如何进一步释放比特币现金经济

​ 转自:https://nchain.com/zh/blog/%E9%8 ... %E7%94%A8%E4%BE%8B/​​​​​

你可能感兴趣的:(比特币现金BCH重启的智能合约操作码OP_CODE的详解 —— Steve Shadders)