bip-anyprevout · ajtowns/bips 中的 bips/bip-0112.mediawiki

  • ajtowns
  • 发布于 2025-01-28 20:42
  • 阅读 22

该BIP(Bitcoin Improvement Proposal)描述了一种新的比特币脚本操作码CHECKSEQUENCEVERIFY,结合BIP68,允许基于输出的年龄限制脚本的执行路径。它通过重新定义NOP3操作码,使得可以根据交易的nSequence字段来限制脚本的执行,从而实现诸如带过期时间的合约、追溯失效、HTLCs、双向支付通道和闪电网络等应用。

跳转到内容

ajtowns/ bips Public

forked from bitcoin/bips

折叠文件树

文件

bip-anyprevout

搜索此仓库

/

bip-0112.mediawiki

复制路径

BlameMore 文件操作

BlameMore 文件操作

最近提交

fedstenfedsten

更新 bip-0112.mediawiki

May 16, 2018

a5c5c76 · May 16, 2018

历史

历史

打开提交详情

查看此文件的提交历史。

400 行 (296 loc) · 16.4 KB

/

bip-0112.mediawiki

顶部

文件元数据和控件

  • 预览

  • 代码

  • Blame

400 行 (296 loc) · 16.4 KB

Raw

复制原始文件

下载原始文件

大纲

编辑和原始操作

  BIP: 112
  Layer: Consensus (soft fork)
  Title: CHECKSEQUENCEVERIFY
  Author: BtcDrak <btcdrak@gmail.com>
          Mark Friedenbach <mark@friedenbach.org>
          Eric Lombrozo <elombrozo@gmail.com>
  Comments-Summary: No comments yet.
  Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0112
  Status: Final
  Type: Standards Track
  Created: 2015-08-10
  License: PD
## 目录<br>Permalink: 目录<br>- 摘要<br>- 概要<br>- 动机 <br> - 具有到期截止日期的合约 <br> - 带超时的托管<br> - 追溯失效 <br> - 哈希时间锁定合约<br> - 双向支付通道<br> - 闪电网络<br> - 双向锚定侧链<br>- 规范<br>- 参考实现<br>- 部署<br>- 鸣谢<br>- 参考<br>- 版权

摘要

Permalink: 摘要

这个BIP描述了比特币脚本系统的一个新的操作码(CHECKSEQUENCEVERIFY),结合BIP 68,允许基于被花费的输出的年龄来限制脚本的执行路径。

概要

Permalink: 概要

CHECKSEQUENCEVERIFY 重新定义了现有的 NOP3 操作码。 当执行时,如果以下任何一个条件为真,脚本解释器将以错误终止:

  • 堆栈为空;或
  • 堆栈上的顶部项目小于 0;或
  • 堆栈上的顶部项目未设置禁用标志 (1 << 31);并且
    • 交易版本小于 2;或
    • 交易输入序号禁用标志 (1 << 31) 已设置;或
    • 相对锁定时间类型不同;或
    • 顶部堆栈项大于交易输入序列(当根据 BIP68 进行屏蔽时);

否则,脚本执行将继续,就像执行了 NOP 一样。

BIP 68阻止非最终交易被选择包含在一个区块中,直到相应的输入达到指定的年龄,以区块高度或区块时间衡量。通过将CHECKSEQUENCEVERIFY的参数与nSequence字段进行比较,我们间接验证了被花费的输出的期望的最小年龄;在达到相对年龄之前,任何包括CHECKSEQUENCEVERIFY的脚本执行路径都将无法验证,导致交易无法被选择包含在一个区块中。

动机

Permalink: 动机

BIP 68 重新定义了交易 nSequence 字段的含义,通过赋予 序列号作为相对锁定时间的共识强制语义。然而,没有办法构建比特币脚本来基于这个字段做出决策。

通过使 nSequence 字段可被脚本访问,就有可能构建代码路径,这些路径只有在发布证明后的某些最短时间内才能访问。这使得在分阶段协议中实现广泛的应用,例如托管、支付通道或双向锚定。

具有到期截止日期的合约

Permalink: 具有到期截止日期的合约

带超时的托管

Permalink: 带超时的托管

一个在资金投入后 30 天自动超时的托管可以通过以下方式建立。Alice、Bob 和 Escrow 创建一个 2-of-3 地址,其 redeemscript 如下。

    IF
        2 &lt;Alice's pubkey> &lt;Bob's pubkey> &lt;Escrow's pubkey> 3 CHECKMULTISIG
    ELSE
        "30d" CHECKSEQUENCEVERIFY DROP
        &lt;Alice's pubkey> CHECKSIG
    ENDIF

在任何时候,都可以使用 Alice、Bob 或 Escrow 中任意两位的签名来花费资金。

30 天后,Alice 可以单独签名。

时钟在支付到托管地址确认后才开始计时。

追溯失效

Permalink: 追溯失效

在许多情况下,我们希望创建在未来事件发生时可以撤销的合约。然而,鉴于区块链的不可变性,实际上不可能追溯地使先前已经确认的承诺无效。我们真正拥有的追溯失效的唯一机制是区块链重组,出于基本安全原因,这种重组被设计得非常困难且成本非常高。

尽管有这个限制,我们确实有一种方法可以提供在功能上类似于追溯失效的东西,同时使用 CHECKSEQUENCEVERIFY 保持过去承诺的不可逆性。通过构建具有多个执行分支的脚本,其中一个或多个分支被延迟,我们提供了一个时间窗口,在此时间窗口内,有人可以提供一个失效条件,允许花费输出,从而有效地使本应延迟的分支失效,并可能阻止另一方首先广播该交易。如果失效条件在超时之前没有发生,则延迟的分支变为可花费的,从而兑现了原始合约。

这个想法的一些更具体的应用:

哈希时间锁定合约

Permalink: 哈希时间锁定合约

哈希时间锁定合约 (HTLC) 提供了一种用于链下合约协商的通用机制。可以使执行路径需要知道可以在失效时间窗口内呈现的密钥(哈希原像)。通过共享密钥,可以向交易对手保证交易永远不会被广播,因为这将允许交易对手立即索取输出,而一方必须等待时间窗口过去。如果密钥未被共享,则交易对手将无法使用即时路径,而必须使用延迟路径。

双向支付通道

Permalink: 双向支付通道

可脚本化的相对锁定时间提供了一个可预测的响应时间,以防交易对手广播已撤销的交易:绝对锁定时间需要关闭通道并在接近超时时重新打开它,而使用相对锁定时间,时钟在交易在一个区块中确认的那一刻开始计时。它还提供了一种手段来精确地知道在非合作交易对手的情况下,在可以将资金从通道中取出之前需要等待多长时间(以区块数计)。

闪电网络

Permalink: 闪电网络

闪电网络扩展了双向支付通道的想法,允许通过多个双向支付通道跳跃来路由支付。

这些通道基于一个锚交易,该交易需要 Alice 和 Bob 的 2-of-2 多重签名,以及一系列可撤销的承诺交易,这些交易花费锚交易。承诺交易将来自锚的资金在 Alice 和 Bob 之间分配,任何一方可以随时发布最新的承诺交易,从而完成通道。

理想情况下,已撤销的承诺交易将永远无法成功花费;并且最新的承诺交易应该能够非常快速地花费。

为了允许有效地撤销承诺交易,Alice 和 Bob 拥有略有不同的最新承诺交易版本。在 Alice 的版本中,承诺交易中支付给 Alice 的任何输出还包括强制延迟,以及一个允许 Bob 在知道该交易的撤销代码的情况下花费该输出的替代分支。在 Bob 的版本中,支付给 Bob 的款项也受到类似的限制。当 Alice 和 Bob 协商新的余额和新的承诺交易时,他们还会透露旧的撤销代码,从而承诺不转发旧的交易。

一个简单的输出,支付给 Alice,可能看起来像这样:

    HASH160 &lt;revokehash> EQUAL
    IF
        &lt;Bob's pubkey>
    ELSE
        "24h" CHECKSEQUENCEVERIFY DROP
        &lt;Alice's pubkey>
    ENDIF
    CHECKSIG

这允许 Alice 随时发布最新的承诺交易并在 24 小时后花费资金,但同时也确保如果 Alice 转发已撤销的交易,Bob 有 24 小时的时间来索取资金。

使用 CHECKLOCKTIMEVERIFY,这将如下所示:

    HASH160 &lt;revokehash> EQUAL
    IF
        &lt;Bob's pubkey>
    ELSE
        "2015/12/15" CHECKLOCKTIMEVERIFY DROP
        &lt;Alice's pubkey>
    ENDIF
    CHECKSIG

这种形式的交易意味着,如果锚在 2015/12/16 仍未花费,Alice 即使已被撤销也可以使用此承诺,只需立即花费它,从而不给 Bob 任何时间来索取它。

这意味着通道有一个截止日期,如果不访问区块链就无法将其推迟;而且资金可能要到截止日期才能使用。CHECKSEQUENCEVERIFY 允许你避免做出这样的权衡。

哈希时间锁定合约 (HTLC) 使这稍微复杂一些,因为原则上它们可以支付给 Alice 或 Bob,具体取决于 Alice 是否发现了密钥 R 或是否达到超时,但同样的原则适用 - Alice 的承诺交易中支付给 Alice 的分支会有一个延迟,如果知道撤销密钥,则另一方可以索取整个输出。使用 CHECKSEQUENCEVERIFY,在 Alice 的承诺交易中,可支付给 Alice 的 HTLC 可能如下所示:

    HASH160 DUP &lt;R-HASH> EQUAL
    IF
        "24h" CHECKSEQUENCEVERIFY
        2DROP
        &lt;Alice's pubkey>
    ELSE
        &lt;Commit-Revocation-Hash> EQUAL
        NOTIF
            "2015/10/20 10:33" CHECKLOCKTIMEVERIFY DROP
        ENDIF
        &lt;Bob's pubkey>
    ENDIF
    CHECKSIG

相应地,在 Bob 的承诺交易中:

   HASH160 DUP &lt;R-HASH> EQUAL
   SWAP &lt;Commit-Revocation-Hash> EQUAL ADD
   IF
       &lt;Alice's pubkey>
   ELSE
       "2015/10/20 10:33" CHECKLOCKTIMEVERIFY
       "24h" CHECKSEQUENCEVERIFY
       2DROP
       &lt;Bob's pubkey>
   ENDIF
   CHECKSIG

请注意,CHECKSEQUENCEVERIFY 和 CHECKLOCKTIMEVERIFY 都用于上述的最后一个分支中,以确保 Bob 无法花费输出,直到超时完成并且 Alice 有时间揭示撤销密钥。

请参阅 可部署的闪电网络 论文。

双向锚定侧链

Permalink: 双向锚定侧链

双向锚定侧链需要一个新的 REORGPROOFVERIFY 操作码,其语义超出了本 BIP 的范围。CHECKSEQUENCEVERIFY 用于确保自发布返回锚定以来有足够的时间来发布重组证明:

    IF
        lockTxHeight &lt;lockTxHash> nlocktxOut [&lt;workAmount>] reorgBounty Hash160(&lt;...>) &lt;genesisHash> REORGPROOFVERIFY
    ELSE
        withdrawLockTime CHECKSEQUENCEVERIFY DROP HASH160 p2shWithdrawDest EQUAL
    ENDIF

规范

Permalink: 规范

有关精确的语义和这些语义的详细原理,请参阅参考实现,如下所示。

/* Below flags apply in the context of BIP 68 */
/* If this flag set, CTxIn::nSequence is NOT interpreted as a
 * relative lock-time. */
static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1 &lt;&lt; 31);

/* If CTxIn::nSequence encodes a relative lock-time and this flag
 * is set, the relative lock-time has units of 512 seconds,
 * otherwise it specifies blocks with a granularity of 1. */
static const uint32_t SEQUENCE_LOCKTIME_TYPE_FLAG = (1 &lt;&lt; 22);

/* If CTxIn::nSequence encodes a relative lock-time, this mask is
 * applied to extract that lock-time from the sequence field. */
static const uint32_t SEQUENCE_LOCKTIME_MASK = 0x0000ffff;

case OP_NOP3:
{
    if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {
        // not enabled; treat as a NOP3
        // 未启用; 视为 NOP3
        if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
            return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
        }
        break;
    }

    if (stack.size() &lt; 1)
       return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);

    // Note that elsewhere numeric opcodes are limited to
    // operands in the range -2**31+1 to 2**31-1, however it is
    // legal for opcodes to produce results exceeding that
    // range. This limitation is implemented by CScriptNum's
    // default 4-byte limit.
    // 请注意,其他地方的数字操作码仅限于 -2**31+1 到 2**31-1 范围内的操作数,但是
    // 操作码产生超出该范围的结果是合法的。 这种限制由 CScriptNum 的
    // 默认 4 字节限制实现。
    //
    // Thus as a special case we tell CScriptNum to accept up
    // to 5-byte bignums, which are good until 2**39-1, well
    // beyond the 2**32-1 limit of the nSequence field itself.
    // 因此,作为一种特殊情况,我们告诉 CScriptNum 接受最多 5 字节的 bignum,它很好用,直到 2**39-1,远远
    // 超过 nSequence 字段本身的 2**32-1 限制。
    const CScriptNum nSequence(stacktop(-1), fRequireMinimal, 5);

    // In the rare event that the argument may be &lt; 0 due to
    // some arithmetic being done first, you can always use
    // 0 MAX CHECKSEQUENCEVERIFY.
    // 在极少数情况下,由于首先完成了一些算术运算,参数可能 &lt; 0,你始终可以使用
    // 0 MAX CHECKSEQUENCEVERIFY。
    if (nSequence &lt; 0)
        return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME);

    // To provide for future soft-fork extensibility, if the
    // operand has the disabled lock-time flag set,
    // CHECKSEQUENCEVERIFY behaves as a NOP.
    // 为了提供未来的软分叉可扩展性,如果
    // 操作数已设置禁用的锁定时间标志,
    // CHECKSEQUENCEVERIFY 的行为类似于 NOP。
    if ((nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0)
        break;

    // Compare the specified sequence number with the input.
    // 将指定的序列号与输入进行比较。
    if (!checker.CheckSequence(nSequence))
        return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);

    break;
}

bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) const
{
    // Relative lock times are supported by comparing the passed
    // in operand to the sequence number of the input.
    // 通过将传入的操作数与输入的序列号进行比较来支持相对锁定时间。
    const int64_t txToSequence = (int64_t)txTo->vin[nIn].nSequence;

    // Fail if the transaction's version number is not set high
    // enough to trigger BIP 68 rules.
    // 如果交易的版本号设置得不够高而无法触发 BIP 68 规则,则失败。
    if (static_cast&lt;uint32_t>(txTo->nVersion) &lt; 2)
        return false;

    // Sequence numbers with their most significant bit set are not
    // consensus constrained. Testing that the transaction's sequence
    // number do not have this bit set prevents using this property
    // to get around a CHECKSEQUENCEVERIFY check.
    // 最高有效位已设置的序列号不受共识约束。 测试交易的序列
    // 编号没有设置此位可防止使用此属性
    // 绕过 CHECKSEQUENCEVERIFY 检查。
    if (txToSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG)
        return false;

    // Mask off any bits that do not have consensus-enforced meaning
    // before doing the integer comparisons
    // 在进行整数比较之前,屏蔽掉任何不具有共识强制含义的位
    const uint32_t nLockTimeMask = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | CTxIn::SEQUENCE_LOCKTIME_MASK;
    const int64_t txToSequenceMasked = txToSequence & nLockTimeMask;
    const CScriptNum nSequenceMasked = nSequence & nLockTimeMask;

    // There are two kinds of nSequence: lock-by-blockheight
    // and lock-by-blocktime, distinguished by whether
    // nSequenceMasked &lt; CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG.
    // 有两种 nSequence:按块高度锁定 和按块时间锁定,区别在于
    // nSequenceMasked &lt; CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG。
    //
    // We want to compare apples to apples, so fail the script
    // unless the type of nSequenceMasked being tested is the same as
    // the nSequenceMasked in the transaction.
    // 我们想比较苹果和苹果,所以如果测试的 nSequenceMasked 的类型与
    // 交易中的 nSequenceMasked 相同,则脚本会失败。
    if (!(
        (txToSequenceMasked &lt;  CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked &lt;  CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) ||
        (txToSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG)
    ))
        return false;

    // Now that we know we're comparing apples-to-apples, the
    // comparison is a simple numeric one.
    // 既然我们知道我们正在比较苹果对苹果,那么
    // 比较是一个简单的数值比较。
    if (nSequenceMasked > txToSequenceMasked)
        return false;

    return true;
}

参考实现

Permalink: 参考实现

以下拉取请求提供了参考实现:

bitcoin/bitcoin#7524

部署

Permalink: 部署

这个 BIP 将使用 bit 0 通过 "versionbits" BIP9 部署。

对于比特币 mainnet,BIP9 的 starttime 将是 2016 年 5 月 1 日午夜 UTC(Epoch 时间戳 1462060800),BIP9 的 timeout 将是 2017 年 5 月 1 日午夜 UTC(Epoch 时间戳 1493596800)。

对于比特币 testnet,BIP9 的 starttime 将是 2016 年 3 月 1 日午夜 UTC(Epoch 时间戳 1456790400),BIP9 的 timeout 将是 2017 年 5 月 1 日午夜 UTC(Epoch 时间戳 1493596800)。

这个 BIP 必须与 BIP68 和 BIP113 同时部署,使用相同的部署机制。

鸣谢

Permalink: 鸣谢

Mark Friedenbach 发明了将序列号应用于实现相对锁定时间的方法,并编写了 CHECKSEQUENCEVERIFY 的参考实现。

参考实现和这个 BIP 很大程度上基于 Peter Todd 为密切相关的 BIP 65 所做的工作。

BtcDrak 编写了这个 BIP 文档。

感谢 Eric Lombrozo 和 Anthony Towns 贡献了示例用例。

参考

Permalink: 参考

BIP 9 Versionbits

BIP 68 通过共识强制序列号实现的相对锁定时间

BIP 65 OP_CHECKLOCKTIMEVERIFY

BIP 113 用于时间锁定约束的中间过去区块时间

使用 OP_CHECKSEQUENCEVERIFY/OP_LOCKTIMEVERIFY 和撤销哈希的 HTLC

闪电网络

可部署的闪电网络

将比特币扩展到每天数十亿笔交易

软分叉部署注意事项

版本位

Jeremy Spilman 小额支付通道

版权

Permalink: 版权

本文档置于公共领域。

  • 原文链接: github.com/ajtowns/bips/...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
ajtowns
ajtowns
江湖只有他的大名,没有他的介绍。