在比特币原始版本中有几个禁用的操作码被禁用,但在5月15日比特币现金协议升级中将被重新激活。
作为启用这些旧操作代码规范的共同作者,我承认未能理解社区对这个修改的明确解释的胃口。在开发人员中,可以认为脚本语言中基本操作的用例非常普遍,因此不需要声明。我们每天都会多次使用像算术,字符串操作和按位逻辑这样的基本操作,而在没有它们的情况下编写任何有用的代码几乎是不可想象的。
然而比特币现金社区不仅仅是开发人员。事实上,上述论点即使对开发者有吸引力,仍然没有提供这些操作码如何用于比特币现金环境的具体例子。这也不能解释为什么他们被禁用或为什么重新启用它们是安全的。这些都是比特币现金社区有权收听的解释,所以我们试着补救。
禁用操作码的历史
LSHIFT 和 RETURN 错误
2010年7月28日,在测试网络上发现并演示了两个错误。一是在处理包含OP_LSHIFT
的交易时,会导致比特币程序在某些机器上崩溃。二是利用交易处理代码中的另一个错误,并允许攻击者花费他们没有的币。在主网络上都没有被利用,并且两者都在比特币版本0.3.5修复。
在发现这些错误之后,许多目前未使用的脚本文件因安全而被禁用。
基本上,由于缺乏足够的谨慎和缺乏充分时间来充分探索和解决需要解决的边缘案例,所以决定只是简单地禁用任何有怀疑甚至暗示疑虑的操作码。在比特币的早期阶段,我们非常重视对安全付款方式进行更简单的选择并进行全面测试。对更复杂用途的探索必然推迟到晚些时候。
Peter Todd 解释为什么OP_CAT(和其它)被禁用(即我们惊慌失措):
https://twitter.com/ryaneshea…
更多关于操作代码的历史记录:
https://scalingbitcoin.org/st…
相同介绍的视频在这里:
https://www.youtube.com/watch…
为什么重新启用它们?
比特币是用丰富的脚本语言创建的。如果它的使用目的仅限于从一个私钥到另一个私钥的直接支付,甚至包括多重签名交易,则根本不需要脚本语言。这些功能可以简单地进行硬编码,大大简化了代码。比特币是建立在具有丰富指令集的脚本语言的基础之上的事实表明,它始终打算成为一个基础平台,使得更复杂的规则集能够管理资金转移。将比特币恢复到最初预期的设计(修复了错误)本身就是一个原因。
7年过去了,现在围绕这些操作代码的边缘案例得到了更好的理解。此外,禁用这些措施的决定是仓促和勉强采取的。BCH社区现在已经有了充分的时间来彻底解决这些问题。
7年也为人们提供了很多时间来思考如何使用这些操作代码。实际上,它们已经在加密生态系统的各个部分(例如Elements Alpha)中启用,以解锁其中一些用例。
为什么只有一些操作码建议重新启用?
只是为了继续谨慎的做法。仅为5月15日协议升级启用少量操作码不仅可以限制风险,还可以使所有相关开发人员更加注意每个操作代码。通过将变化的范围保持得很小,它使BCH开发人员社区有机会优化启用这些功能的过程。这个过程包括调度,开发规格,吸引同行评审,提炼,与现有的协议达成高度兼容,建立和测试验收和发布方法,并且当然执行以上所有内容。
什么是一些用例?
以下是近年来已发布或讨论的用例汇编。其中很多都在多个操作码下引用,因为它们需要多个操作码。这份清单毫无疑问是不完整的。
OP_CAT
https://lists.linuxfoundation…
多方哈希锁:
安全且紧凑地验证许多哈希和哈希原像。这将大大降低链下 Tumblebit 交易的大小。例如交易TxA检查交易TxB的原像 x1,x2,…,x10,使得y1 = H(x1),y2 = H(x2),…,y10 = H(x10)。
目前需要有y1,… y10,才能检查正确的 hash 原像。
使用OP_CAT,你只需要在TxA中存储一个 yhash
ytotal = H(OP_CAT(H(OP_CAT(y1,y2)),y3)... y10)
然后,TxA可以对TxB提供的所有原像进行哈希处理,并确认它们hash。这会将TxA的大小从大约10 32B减小到32 + 10 16B。
https://blockstream.com/2015/…
简单的merkle树验证:
这可以在更大规模上实现多重签名。按照目前脚本大小限制,可以实现理论极限是40亿分之一。在886字节的脚本中,可以达到250000分之一1的限制,这在没有OP_CAT的情况下需要约8mb。
OP_SPLIT
https://scalingbitcoin.org/st…
OP_LEFT弱散列:
弱散列只是比平常小的散列。它们在比特币地址中用作校验和以提供一定程度的错误检查(32位校验出现未检测到错误的概率为2 ^ 32分之1)。它们可以通过散列并获取开头(或最后)n个字节来生成。
迷你工作证明:
确保对于接收者,计算出使用迷你POW的脚本签名是昂贵的。通过要求签名或散列以特定的位串开头。对小于2 ^ 32的数字可以使用OP_SPLIT和OP_LESSTHAN来实现。OP_EQUALS也可以与OP_SPLIT一起用于较大的数字,但限于2 ^ n的难度,其中n必须是8的倍数(您只能使用整个字节)。对于更大的数字,OP_SPLIT和OP_AND的组合允许任何2的幂的有效难度。例如,如果希望PoW平均需要80亿次尝试来解决该脚本,则可能需要最后的33个比特为零:
<pow_hash> SIZE 5 SUB SPLIT 0x01FFFFFFFF AND IF RETURN ELSE //完成脚本
说明:
- SIZE 5 SUB – 获取pow_hash的长度并减去5
- SPLIT – 使用len(pow_hash)-5作为分割点,分割最后5个字节的字节
- 0x01FFFFFFFF AND – 置零最左边的7位。
- IF RETURN – 如果最右边的33位不全是0,则脚本失效
- ELSE
- //完成脚本
检查字节数组的部分。例如查看签名的SIGHASH_FLAGS:
这是强制限制资金花费方式的一个例子。
<sig> <pubkey> | 1 PICK SIZE 1 SUB SPLIT 1 ROLL DROP
说明:
- 1 PICK – 将sig复制到堆栈顶部
- SIZE 1 SUB – 获取sig的长度并减去1
- SPLIT – 使用len(sig)-1作为分割点分割最后一个字节
- 1 ROLL DROP – 将分割字节的左边部分移动到堆栈顶部,并放下它,在堆栈顶部留下sig的最后一个字节。
0x80 和 验证
说明:
- 0x80 – 将0x80推入堆栈(这是ANYONECANPAY标志,但可能是其他标志)
- AND – sig的最后一个字节 & 0x80,返回SIGHASH_ANYONECANPAY,否则返回0x00。
- 验证 – 如果未设置标志则脚本失败。
- //做P2PKH脚本的其余部分
堆栈状态现在是:<sig> <pubkey>,这是p2pkh所需要的。完整的脚本将是:
<sig> <pubkey> | 1 PICK SIZE 1 SUB SPLIT 1 ROLL DROP 0x80 AND VERIFY DUP HASH160 <pubkeyhash> 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/st…
使用OP_XOR生成确定性随机数:
结合不同方面的秘密价值。
http://www.cs.technion.ac.il/…
使用OP_XOR和OP_MOD将两个抛硬币结合成一个结果。大多数论文是关于在不信任的情况下在两方之间进行抛硬币的协议,最后阶段是使用xor和mod将参与者选择的随机值组合成结果。
类似这里描述 https://github.com/jl2012/bip…
https://en.wikipedia.org/wiki…
使用异或的快速确定性随机数生成:
- 注意:这也需要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/… – 也需要OP_XOR
OP_DIV
没有特定用例,但它是OP_MOD行为的一个子集,并且所有适用于DIV的边缘情况都已由MOD解决。
数据输入
尽管脚本没有明确的数据类型系统,但在实践中隐含地使用了两种数据类型。数字和字节数组。像算术,字符串和位运算符被设计为使用特定的数据类型(分别为数字,字节数组和多个字节数组)。为了减轻同行评审规范中关于这些操作码误用于不正确数据类型的担忧,决定引入两个新的操作码来提供类型间数据的安全和明确的转换。这仅仅是为了使脚本语言更安全且更易于使用,而不是添加特定用例。这个好处不仅适用于本文提到的操作代码,而且适用于许多现有的操作代码。
OP_NUM2BIN
请参阅这里的“脚本数据类型”部分:
https://github.com/shadders/u…
OP_BIN2NUM
请参阅这里的“脚本数据类型”部分:
https://github.com/shadders/u…
结论
这份清单并非详尽无遗。但它确实说明,因为这些操作代码是脚本语言的基本组成部分,所以它们的实用性非常广泛。这些都是原本不可能实现的例子。现在,他们的使用是一个真正的可能性,这是合理的,期望创造性的头脑会更多地关注,以释放比特币现金经济的进一步潜力。