该BIP (Bitcoin Improvement Proposal) 提议引入一个新的操作码 OP_CHECKOUTPUTSHASHVERIFY,用于Tapscript版本0。这个新的操作码可以用于交易拥塞控制和支付通道的实例化等。该操作码验证输出的 SHA256 双哈希是否与提供的值匹配,从而实现有限的智能合约功能,例如拥塞控制交易、通道工厂和钱包保险库,同时尽量减少对现有代码库的影响。
跳转到内容Skip to content
JeremyRubin/ bips-archive Public
forked from TheBlueMatt/bips
op-checkoutputshashverify
搜索此仓库
/
复制路径
BlameMore file actions
BlameMore file actions
打开提交详情
May 20, 2019
b53d120 · May 20, 2019
打开提交详情
293 lines (220 loc) · 13.4 KB
/
顶部
预览
代码
Blame
293 lines (220 loc) · 13.4 KB
复制 raw 文件
下载 raw 文件
概要
编辑和 raw 操作
BIP: bip-coshv
Title: OP_CHECKOUTPUTSHASHVERIFY
Author: Jeremy Rubin <j@rubin.io>
Status: Draft
Type: Standards Track
Created:
License: BSD-3-Clause
## 目录<br>固定链接:目录<br>- 摘要<br>- 概要<br>- 动机 <br> - 拥塞控制交易<br> - 通道工厂<br> - 钱包保险库<br> - 币合<br>- 设计 <br> <br> <br> - 以下脚本是 32 字节的最小数据推送<br> - 此交易中只花费了一个输入<br> - 序列化输出的 SHA256 双哈希与提供的值匹配<br> - 设计折衷和风险<br>- 规范<br>- 部署<br>- 实现<br>- 参考文献<br>- 版权 |
本 BIP 提议一个新的操作码 OP_CHECKOUTPUTSHASHVERIFY,在 Tapscript version 0 中激活。
这个新的操作码具有交易拥塞控制和支付通道实例化等应用,这些应用在本 BIP 的动机部分中描述。
CHECKOUTPUTSHASHVERIFY 在 Tapscript 执行期间使用操作码 OP_RESERVED1 (0x89)。
CHECKOUTPUTSHASHVERIFY 验证以下条件:
如果 CHECKOUTPUTSHASHVERIFY 之后的操作不是 32 字节的数据推送,则忽略它。 否则,如果不满足条件,执行失败。
Covenants -- 或对一枚币如何花费的限制,超越了密钥所有权 -- 是构建智能合约的非常强大的结构。 然而,考虑到它们的复杂性以及引入同质化风险的可能性,到目前为止,人们还没有认真考虑将它们纳入比特币。
此 BIP 旨在引入一个最小可行的 covenant,它启用了一组有限的实用功能。 例如:
当对区块空间的需求很大时,进行支付可能会变得非常昂贵。 通过使用 CHECKOUTPUTSHASHVERIFY,大量支付处理器可以将所有支付聚合成单个 O(1) 交易以进行确认。 然后,在稍后的某个时间,当对区块空间的需求减少时,支付可以从该 UTXO 中扩展出来。
如果没有 CHECKOUTPUTSHASHVERIFY,使用 Schnorr 签名(即使使用 ECDSA 给定多方方案)仍然可以做到这一点。 然而,不可能以非交互方式进行,这从根本上限制了该方法的可行性。
要构建一个拥塞控制交易,用户有多种选择 -- 它可以简单地是从 1 个输出到 N 的单步,或者,用户可以使用 CHECKOUTPUTSHASHVERIFY 提交到输出树,这允许他们确认他们喜欢的任意数量的付款。 此外,Taproot 可以提交到可变大小的扩展 -- 例如,一个节点扩展 2、4、8 等。这允许在交易开销和立即可用的区块空间之间进行权衡。 在这种情况下,Merkle 树查找是 O(log(log(N))) 额外的开销,但可以对该树进行 Huffman 编码,使其成为 E[O(1)],具体取决于区块需求。 树的每个节点也可以尝试“选择加入”以优先使用基于 Taproot 签名的花费,但如果参与者离线或恶意,则扩展可以进行到更小的组。
这种方法的总体开销(没有优化)从每个用户的角度来看是 O(log(N)) 个交易,期望只有 1 个额外的交易,从网络的角度来看是 2N。 然而,考虑到此类交易不需要签名,因此实际开销较小。
下图展示了这些交易与正常交易和批量交易相比的结构。
下面显示了一个模拟,显示了在 5% 的网络采用率和 50% 的网络采用率下,这可能对 mempool 积压产生的影响。 此模拟的代码在此 BIP 的子目录中提供。
这个用例与上面的用例类似,只是叶节点应该设置为一个通道(可能在付款人和收款人之间或收款人选择的目标)。
对于设置,这些通道已经对时间不敏感,因为所有惩罚都可以相对于实际实例化进行时间锁定。
这允许使用这种延迟方法发送的币获得即时流动性。
当冷存储解决方案需要更高的安全性时,可以有默认的 Tapscript 路径,将资金从一个目标移动到另一个目标。
例如,可以设置一个冷钱包,一个客户支持部门可以在没有进一步授权的情况下,将一部分资金(使用多个预设金额)移动到一个由隔离的支持部门运营的温钱包中。 然后,支持部门可以将一些资金发放给一个热钱包,并将剩余的资金发送回冷存储,并采用类似的提款机制。
所有这些都可以在没有 CHECKOUTPUTSHASHVERIFY 的情况下实现,但 CHECKOUTPUTSHASHVERIFY 消除了对协调和在线签名者的需求,并减少了支持部门不当转移资金的能力。
此外,所有这些设计都可以与相对时间锁结合使用,以便合规和风险部门进行干预。
这种方法使得建立一个无需信任的币合变得更加容易。
所有参与者都同意一个提交到其输出哈希的 UTXO,然后参与者可以使用他们喜欢的任何输入来资助该交易。
然后,可以确认该交易。
如果需要,Tapscript 路径可以被基于签名的花费所取代,以提高同质化。
CHECKOUTPUTSHASHVERIFY 的目标是对现有代码库产生最小的影响 -- 在未来,当我们意识到更复杂但被证明是安全的使用案例时,可能会启用新的 covenant 类型。
至关重要的是,由于这是一个 Tapscript,因此参与者可以合作使用签名替换 Tapscript 路径。 如果可以更新其他依赖项(如通道状态),这会消除输出被单独花费的要求和输出哈希的完全匹配。
下面我们将逐一讨论这些规则:
CHECKOUTPUTSHASHVERIFY 使用操作码之后的推送,而不是操作码之前的推送。 如果 CHECKOUTPUTSHASHVERIFY 使用堆栈中的数据,则可以在脚本中构造提交的数据。 通过使用数据前瞻,我们确保在花费时知道输出。
脚本程序员仍然能够有条件地检查哪个哈希,例如OP_IF OP_CHECKOUTPUTSHASHVERIFY <outputs 1> OP_ELSE <outputs 2> OP_ENDIF
。 然而,通过保持输出字面哈希,我们限制了可能性。
在任何情况下,考虑到 Tapscript 的 API,用户更有可能将具有多个OP_CHECKOUTPUTSHASHVERIFY
操作的任何代码编译到单独的分支中。
如果我们允许在交易中花费多个输入,那么两个输出可能请求支付到同一组输出,导致一半的预期支付被丢弃。 虽然有安全的方法来允许多个输入,但该设计要复杂得多,并且用例不太清楚。
此外,对哪些输入可以共同花费的限制对于需要稳定 TXID 的支付通道结构至关重要。
这是一个已经计算出的哈希,因此它可以使我们免于额外的验证开销。 因此,OP_CHECKOUTPUTSHASHVERIFY
不会带来大量的额外验证开销。
在堆栈上公开此哈希可能会允许解析输出,但这并不是一个问题,因为它们在脚本构造时已经完全已知。
Covenants 从历史上看一直存在争议,因为它们存在同质化风险 -- 可以铸造对它们的支出方式有永久性限制的币。
在此处介绍的方法中,covenants 受到以下严格限制。 所有 covenants 都用一个基于多重签名的密钥包装,该密钥可以抢占 covenant 的要求。 此外,OP_CHECKOUTPUTSHASHVERIFY covenants 的结构使得输出必须在构建时精确已知。 因此,只能创建以有限的步长扩展的 covenants,并且在安全意义上等同于创建所有可到达最终状态的输入的交易集。 此外,covenants 被限制为仅可作为单个输入花费,从而防止了“半花费”问题。
这些 covenants,就像它们受到的限制一样,也存在一些风险。 提供给 OP_CHECKOUTPUTSHASHVERIFY 的原像可能是未知的,或者 Taproot 是用具有未知私钥的公钥构建的。 知道某个地址可以从中花费与发送者花费到任何地址(尤其是 OP_RETURN)的能力不兼容。 如果发件人需要知道收件人可以在花费前删除 covenant,他们可以请求收件人提供挑战字符串的签名。 最后的风险是滥用“转发地址合约”。 转发地址是一个可以以预定义方式自动执行的脚本。 例如,一个热钱包可能有一些币,在相对超时后可以自动转移到冷存储地址。 问题是重用这些密钥可能非常不安全。 例如,假设创建一个地址,将 1 BTC 转发到冷存储。 创建一个输出到这个地址,金额少于 1 BTC 将被冻结,直到使用 Taproot 签名路径。 如果向该地址支付了超过 1 BTC 的金额,并且 redeemscript 已公开发布,那么任何人都可以导致超过 1 BTC 的资金作为巨额矿工费支付。 以后可能会引入操作码,提交最多应该花费多少费用,或者其他会使可重用密钥的使用更安全的限制。 目前,最好不要重用 Taproot 密钥,除非你确定所有分支都与你所需的付款兼容。 这种限制和风险并非 OP_CHECKOUTPUTSHASHVERIFY 独有,Taproot 脚本可能包含许多逻辑分支,多次花费到这些分支是不安全的(例如,哈希时间锁定分支应该在每次使用时使用唯一的哈希实例化)。
由 MES16 提出的更强大的 covenants(如果实现)将使 OP_CHECKOUTPUTSHASHVERIFY 类型的 covenant 变得多余。 它们还将在提高调整费用的能力方面带来一些好处,而不是依赖子为父付或其它机制。 然而,这些特性带来了大大增加的复杂性和产生意外行为的空间。 或者,基于 CHECKSIGFROMSTACK 或 SIGHASH_NOINPUT 的 covenant 设计也可能能够实现 covenants。 SIGHASH_NOINPUT 存在额外的风险,这使其无法包含在比特币中。 CHECKSIGFROMSTACK 比 OP_CHECKOUTPUTSHASHVERIFY 更复杂,并且会带来 OP_CHECKOUTPUTSHASHVERIFY 中没有的额外验证开销。 考虑到此方法易于实施和分析,以及用户应用程序可实现的优势,因此提出了 OP_CHECKOUTPUTSHASHVERIFY 方法。
以下代码是验证OP_CHECKOUTPUTSHASHVERIFY
的主要逻辑。
case OP_CHECKOUTPUTSHASHVERIFY:
{
// 当未启用时,不要验证...
if (flags & SCRIPT_VERIFY_OUTPUTS_HASH) {
CScript::const_iterator lookahead = pc;
opcodetype argument;
// 预读一个操作码作为前瞻参数
if (!script.GetOp(lookahead, argument, vchPushValue))
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
// 如果前瞻参数正好是 32 字节,检查 OutputHash
// 这是为了我们以后可以为此操作码添加不同的语义
if (vchPushValue.size() == 32) {
// Argument 应该 == 0x20 -- 无论如何稍后都会失败
if (!CheckMinimalPush(vchPushValue, argument)) {
return set_error(serror, SCRIPT_ERR_MINIMALDATA);
}
// 如果允许多个输入,则具有相同 OutputsHashVerify 的两个输入
// 将仅支付一半的预期金额!
if (!checker.CheckOnlyOneInput()) {
return set_error(serror, SCRIPT_ERR_OUTPUTSHASHVERIFY);
}
// 最后,检查输出哈希是否与传递的值匹配
if (!checker.CheckOutputsHash(vchPushValue)) {
return set_error(serror, SCRIPT_ERR_OUTPUTSHASHVERIFY);
}
}
}
}
break;
该部署旨在与 Tapscript 一起完成 https://github.com/sipa/bips/blob/bip-schnorr/bip-tapscript.mediawiki。
一个实现和测试可在此处获得:https://github.com/JeremyRubin/bitcoin/tree/congestion-control。
本文档根据 3-clause BSD 许可证获得许可。
- 原文链接: github.com/JeremyRubin/b...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!