该 BIP (Bitcoin Improvement Proposal) 提议引入一个新的比特币脚本操作码 CHECKSEQUENCEVERIFY
,结合 BIP68,允许脚本的执行路径基于UTXO的年龄进行限制。
forked from bitcoin/bips
vault
搜索此仓库
/
复制路径
BlameMore file actions
BlameMore file actions
将 BIP 2 从 Draft->Active 提升,并实现它
打开提交详情
2016年11月30日
959fecc · 2016年11月30日
打开提交详情
400 行 (296 loc) · 16.4 KB
/
顶部
预览
代码
Blame
400 行 (296 loc) · 16.4 KB
复制原始文件
下载原始文件
目录
编辑和原始操作
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>永久链接:目录<br>- 摘要<br>- 概要<br>- 动机 <br> - 具有到期截止日期的合约 <br> - 具有超时的 Escrow<br> - 追溯失效 <br> - 哈希时间锁定合约<br> - 双向支付通道<br> - 闪电网络<br> - 双向锚定侧链<br>- 规范<br>- 参考实现<br>- 部署<br>- 致谢<br>- 参考<br>- 版权 |
此 BIP 描述了比特币脚本系统的一个新操作码 (CHECKSEQUENCEVERIFY),它与 BIP 68 结合使用,允许根据所花费输出的年龄来限制脚本的执行路径。
CHECKSEQUENCEVERIFY 重新定义了现有的 NOP3 操作码。 执行时,如果以下任何条件为真,脚本解释器将终止并报错:
否则,脚本执行将继续,就像执行了 NOP 一样。
BIP 68 阻止在相应的输入达到指定的期限(以区块高度或区块时间衡量)之前,将非最终交易选择包含在区块中。 通过将 CHECKSEQUENCEVERIFY 的参数与 nSequence 字段进行比较,我们间接验证了正在花费的输出的所需最小期限; 在达到该相对期限之前,任何包括 CHECKSEQUENCEVERIFY 的脚本执行路径都将无法验证,从而导致该交易未被选择包含在区块中。
BIP 68 通过赋予序列号新的共识强制语义作为相对锁定时间,从而重新定义了交易 nSequence 字段的含义。 但是,没有办法构建比特币脚本来根据此字段做出决策。
通过使 nSequence 字段可供脚本访问,可以构造仅在发布证明后的某个最短时间后才能访问的代码路径。 这使得能够在分阶段协议中实现各种各样的应用,例如 escrow、支付通道或双向锚定。
可以在以下方式建立在资金投入后 30 天自动超时的 escrow。 Alice、Bob 和 Escrow 使用以下赎回脚本创建一个 2/3 地址。
IF
2 <Alice's pubkey> <Bob's pubkey> <Escrow's pubkey> 3 CHECKMULTISIG
ELSE
"30d" CHECKSEQUENCEVERIFY DROP
<Alice's pubkey> CHECKSIG
ENDIF
在任何时候,都可以使用 Alice、Bob 或 Escrow 中任意两者的签名来花费资金。
30 天后,Alice 可以单独签名。
在支付到 escrow 地址确认之前,时钟不会开始计时。
在很多情况下,我们希望创建可以在未来事件发生时撤销的合约。 但是,鉴于区块链的不可变性,实际上不可能追溯性地使先前已确认的承诺失效。 我们真正拥有的用于追溯失效的唯一机制是区块链重组,出于基本安全原因,它的设计非常困难且成本非常高。
尽管有此限制,我们确实有一种方法可以提供在功能上类似于追溯失效的东西,同时使用 CHECKSEQUENCEVERIFY 保留过去承诺的不可逆性。 通过构建具有多个执行分支的脚本,其中一个或多个分支被延迟,我们可以提供一个时间窗口,在此期间有人可以提供使输出可花费的失效条件,从而有效地使原本会延迟的分支失效,并可能阻止另一方首先广播交易。 如果失效条件在超时之前没有发生,则延迟的分支将变为可花费,从而遵守原始合同。
此想法的一些更具体的应用:
哈希时间锁定合约 (HTLC) 提供了一种用于链下合约协商的通用机制。 可以使执行路径需要知道可以在失效时间窗口内呈现的密钥(哈希原像)。 通过共享密钥,可以向交易对手保证永远不会广播交易,因为这将允许交易对手立即认领输出,而一个人将不得不等待时间窗口过去。 如果尚未共享密钥,则交易对手将无法使用即时路径,而必须改用延迟路径。
在交易对手广播已撤销的交易的情况下,可脚本化的相对锁定时间提供了可预测的响应时间:绝对锁定时间需要在接近超时时关闭通道并重新打开,而使用相对锁定时间,时钟在交易在区块中确认的那一刻开始计时。 它还提供了一种准确了解在非合作交易对手的情况下,在资金可以从通道中提取之前需要等待多长时间(以区块数为单位)的方法。
闪电网络扩展了双向支付通道的想法,允许通过多个双向支付通道跳来路由支付。
这些通道基于需要 Alice 和 Bob 的 2/2 多重签名的一个 anchor 交易,以及一系列花费该 anchor 交易的可撤销的承诺交易。 承诺交易将来自 anchor 的资金在 Alice 和 Bob 之间分配,最新的承诺交易可以由任何一方随时发布,从而最终确定该通道。
理想情况下,已撤销的承诺交易将永远无法成功花费; 并且最新的承诺交易可以非常快速地花费。
为了允许有效地撤销承诺交易,Alice 和 Bob 具有略微不同的最新承诺交易版本。 在 Alice 的版本中,承诺交易中支付给 Alice 的任何输出还包括强制延迟,以及一个允许 Bob 在知道该交易的撤销代码时花费该输出的替代分支。 在 Bob 的版本中,支付给 Bob 的款项也受到类似的限制。 当 Alice 和 Bob 协商新的余额和新的承诺交易时,他们还会公开旧的撤销代码,从而承诺不中继旧交易。
那么,支付给 Alice 的简单输出可能如下所示:
HASH160 <revokehash> EQUAL
IF
<Bob's pubkey>
ELSE
"24h" CHECKSEQUENCEVERIFY DROP
<Alice's pubkey>
ENDIF
CHECKSIG
这允许 Alice 随时发布最新的承诺交易并在 24 小时后花费资金,但也确保如果 Alice 中继已撤销的交易,Bob 有 24 小时的时间来认领资金。
使用 CHECKLOCKTIMEVERIFY,这将如下所示:
HASH160 <revokehash> EQUAL
IF
<Bob's pubkey>
ELSE
"2015/12/15" CHECKLOCKTIMEVERIFY DROP
<Alice's pubkey>
ENDIF
CHECKSIG
这种形式的交易意味着,如果 anchor 在 2015/12/16 未花费,Alice 可以使用此承诺,即使它已被撤销,只需立即花费它,而无需给 Bob 时间来认领它。
这意味着该通道具有一个截止日期,如果不访问区块链就无法推迟; 并且资金可能要到截止日期到达后才能使用。 CHECKSEQUENCEVERIFY 允许你避免进行这种权衡。
哈希时间锁定合约 (HTLC) 使此情况稍微复杂一些,因为原则上它们可能会支付给 Alice 或 Bob,具体取决于 Alice 是否发现了密钥 R 或是否已达到超时时间,但相同的原则适用 - 在 Alice 的承诺交易中支付给 Alice 的分支会获得延迟,并且如果知道撤销密钥,则另一方可以认领整个输出。 使用 CHECKSEQUENCEVERIFY,Alice 的承诺交易中可支付给 Alice 的 HTLC 可能如下所示:
HASH160 DUP <R-HASH> EQUAL
IF
"24h" CHECKSEQUENCEVERIFY
2DROP
<Alice's pubkey>
ELSE
<Commit-Revocation-Hash> EQUAL
NOTIF
"2015/10/20 10:33" CHECKLOCKTIMEVERIFY DROP
ENDIF
<Bob's pubkey>
ENDIF
CHECKSIG
相应地,在 Bob 的承诺交易中:
HASH160 DUP <R-HASH> EQUAL
SWAP <Commit-Revocation-Hash> EQUAL ADD
IF
<Alice's pubkey>
ELSE
"2015/10/20 10:33" CHECKLOCKTIMEVERIFY
"24h" CHECKSEQUENCEVERIFY
2DROP
<Bob's pubkey>
ENDIF
CHECKSIG
请注意,上述最终分支中使用了 CHECKSEQUENCEVERIFY 和 CHECKLOCKTIMEVERIFY,以确保 Bob 在超时完成且 Alice 有时间显示撤销密钥之后才能花费该输出。
参见可部署的闪电网络 论文。
双向锚定侧链需要一个新的 REORGPROOFVERIFY 操作码,其语义不在本 BIP 的范围内。 CHECKSEQUENCEVERIFY 用于确保自发布重组证明的返回锚定以来已过去足够的时间:
IF
lockTxHeight <lockTxHash> nlocktxOut [<workAmount>] reorgBounty Hash160(<...>) <genesisHash> REORGPROOFVERIFY
ELSE
withdrawLockTime CHECKSEQUENCEVERIFY DROP HASH160 p2shWithdrawDest EQUAL
ENDIF
有关精确的语义和这些语义的详细原理,请参阅以下再现的参考实现。
/* 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 << 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 << 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() < 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 < 0 due to
// some arithmetic being done first, you can always use
// 0 MAX CHECKSEQUENCEVERIFY.
// 在极少数情况下,由于首先进行了一些算术运算,参数可能 < 0,你始终可以使用 0 MAX CHECKSEQUENCEVERIFY。
if (nSequence < 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<uint32_t>(txTo->nVersion) < 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 < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG.
// nSequence 有两种:按区块高度锁定和按区块时间锁定,区别在于 nSequenceMasked < 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 < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked < 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;
}
以下拉取请求提供了参考实现:
此 BIP 将使用位 0 通过 “versionbits” BIP9 进行部署。
对于比特币主网,BIP9 的 starttime 将是 2016 年 5 月 1 日午夜 UTC(Epoch 时间戳 1462060800),BIP9 的 timeout 将是 2017 年 5 月 1 日午夜 UTC(Epoch 时间戳 1493596800)。
对于比特币测试网,BIP9 的 starttime 将是 2016 年 3 月 1 日午夜 UTC(Epoch 时间戳 1456790400),BIP9 的 timeout 将是 2017 年 5 月 1 日午夜 UTC(Epoch 时间戳 1493596800)。
此 BIP 必须使用相同的部署机制与 BIP68 和 BIP113 同时部署。
Mark Friedenbach 发明了序列号在实现相对锁定时间方面的应用,并编写了 CHECKSEQUENCEVERIFY 的参考实现。
参考实现和此 BIP 主要基于 Peter Todd 为密切相关的 BIP 65 所做的工作。
BtcDrak 撰写了此 BIP 文档。
感谢 Eric Lombrozo 和 Anthony Towns 贡献了用例示例。
BIP 9 Versionbits
BIP 68 通过共识强制序列号实现相对锁定时间
BIP 65 OP_CHECKLOCKTIMEVERIFY
BIP 113 用于时间锁定约束的中间过去区块时间
使用 OP_CHECKSEQUENCEVERIFY/OP_LOCKTIMEVERIFY 和撤销哈希的 HTLC
本文档已置于公共领域。
- 原文链接: github.com/jl2012/bips/b...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!