该 BIP (Bitcoin Improvement Proposal) 提议引入相对锁定时间 (RLT) 的共识强制语义,通过序列号字段使已签名的交易输入在其对应的输出被确认后的一段时间内保持无效。此举旨在通过重新利用序列号,实现如 HTLCs 这样的双向支付通道,同时不破坏现有功能,并为未来扩展留下空间。
forked 自 bitcoin/bips
bip-anyprevout
搜索此仓库
/
复制路径
Blame更多文件操作
Blame更多文件操作
打开提交详情
2016年11月30日
959fecc · 2016年11月30日
打开提交详情
265 行 (197 loc) · 13.8 KB
/
顶部
预览
代码
Blame
265 行 (197 loc) · 13.8 KB
复制原始文件
下载原始文件
大纲
编辑和原始操作
BIP: 68
Layer: Consensus (soft fork)
Title: Relative lock-time using consensus-enforced sequence numbers
Author: Mark Friedenbach <mark@friedenbach.org>
BtcDrak <btcdrak@gmail.com>
Nicolas Dorier <nicolas.dorier@gmail.com>
kinoshitajona <kinoshitajona@gmail.com>
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0068
Status: Final
Type: Standards Track
Created: 2015-05-28
## 目录<br>Permalink: 目录<br>- 摘要<br>- 动机<br>- 规范<br>- 实现<br>- 致谢<br>- 部署<br>- 兼容性<br>- 参考 |
此 BIP 引入了相对锁定时间(RLT)共识强制执行的序列号字段语义,以使签名的交易输入在其对应的 outpoint 确认后的定义时间内保持无效。
比特币交易为每个输入都有一个序列号字段。最初的想法似乎是,mempool 中的交易将通过使用具有更高序列值的相同输入来替换。虽然这没有得到正确的实现,但它假设矿工会更喜欢更高的序列号,即使较低的序列号更有利可图。但是,仅出于利润动机的矿工将完全打破该假设。此 BIP 描述的更改重新调整了序列号的用途以用于新的用例,而不会破坏现有功能。它还为未来的扩展和其他用例留出了空间。
交易 nLockTime 用于防止在特定日期之前挖掘交易。nSequence 将被重新用于防止在在花费的输出在块或时间跨度中达到一定存在时间之前挖掘某个交易。除其他用途外,这还允许 哈希时间锁定合约(HTLC) 和 BIP112 中使用的双向支付通道。
本规范定义了对于 nVersion 大于或等于 2 的交易的序列号的含义,本规范的其余部分依赖于此。
所有对 median-time-past (MTP) 的引用均按照 BIP113 中的定义。
如果序列号的位 (1 << 31) 已设置,则序列号不应用任何共识含义,并且可以在当前所有可能的情况下包含在任何块中。
如果序列号的位 (1 << 31) 未设置,则该序列号被解释为编码的相对锁定时间。
序列号编码解释如下:
位 (1 << 22) 确定相对锁定时间是基于时间还是基于区块:如果该位已设置,则相对锁定时间以 512 秒的粒度指定一个时间跨度。该时间跨度从输出的上一个区块的 median-time-past 开始,到上一个区块的 MTP 结束。如果该位未设置,则相对锁定时间指定区块数。
标志 (1<<22) 是一个 3 字节有符号整数中的最高有效位,用于比特币脚本中作为带有 OP_CHECKSEQUENCEVERIFY (BIP 112) 的 3 字节 PUSHDATA。
本规范仅将序列号的 16 位解释为相对锁定时间,因此必须将 0x0000ffff 的掩码应用于序列字段以提取相对锁定时间。16 位规范允许一年的相对锁定时间,其余位允许将来的扩展。
对于基于时间的相对锁定时间,选择 512 秒的粒度是因为比特币区块每 600 秒生成一次。因此,当使用基于区块或基于时间时,可以使用可用位数对相同的时间量进行编码。从序列号转换为秒数是通过乘以 512 = 2^9 来执行的,或者等效地向上移动 9 位。
当相对锁定时间是基于时间的时候,它被解释为对输入存在时间的最小区块时间约束。相对的、基于时间的、零锁定时间表示一个可以被包含在任何区块中的输入。更一般地,相对的、基于时间的锁定时间 n 可以被包含在输出被挖掘的日期(即上一个挖掘它的区块的 median-time-past)之后 512 * n 秒产生的任何区块中,或之后的任何区块。 输出的挖掘日期等于挖掘它的前一个区块的 median-time-past。
区块产生的时间等于其前一个区块的 median-time-past。
当相对锁定时间是基于区块的时候,它被解释为对输入存在时间的最小区块高度约束。相对的、基于区块的、零锁定时间表示一个可以被包含在任何区块中的输入。更一般地,相对的、基于区块的锁定时间 n 可以被包含在输出被挖掘的日期之后的 n 个区块中,或之后的任何区块。
新规则不适用于 coinbase 交易的输入的 nSequence 字段。
以下拉取请求提供了参考实现
enum {
/* Interpret sequence numbers as relative lock-time constraints. */
LOCKTIME_VERIFY_SEQUENCE = (1 << 0),
};
/* Setting nSequence to this value for every input in a transaction
* disables nLockTime. */
static const uint32_t SEQUENCE_FINAL = 0xffffffff;
/* 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;
/* In order to use the same number of bits to encode roughly the
* same wall-clock duration, and because blocks are naturally
* limited to occur every 600s on average, the minimum granularity
* for time-based relative lock-time is fixed at 512 seconds.
* Converting from CTxIn::nSequence to seconds is performed by
* multiplying by 512 = 2^9, or equivalently shifting up by
* 9 bits. */
static const int SEQUENCE_LOCKTIME_GRANULARITY = 9;
/**
* Calculates the block height and previous block's median time past at
* which the transaction will be considered final in the context of BIP 68.
* Also removes from the vector of input heights any entries which did not
* correspond to sequence locked inputs as they do not affect the calculation.
*/
static std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block)
{
assert(prevHeights->size() == tx.vin.size());
// Will be set to the equivalent height- and time-based nLockTime
// values that would be necessary to satisfy all relative lock-
// time constraints given our view of block chain history.
// The semantics of nLockTime are the last invalid height/time, so
// use -1 to have the effect of any height or time being valid.
int nMinHeight = -1;
int64_t nMinTime = -1;
// tx.nVersion is signed integer so requires cast to unsigned otherwise
// we would be doing a signed comparison and half the range of nVersion
// wouldn't support BIP 68.
bool fEnforceBIP68 = static_cast<uint32_t>(tx.nVersion) >= 2
&& flags & LOCKTIME_VERIFY_SEQUENCE;
// Do not enforce sequence numbers as a relative lock time
// unless we have been instructed to
if (!fEnforceBIP68) {
return std::make_pair(nMinHeight, nMinTime);
}
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
const CTxIn& txin = tx.vin[txinIndex];
// Sequence numbers with the most significant bit set are not
// treated as relative lock-times, nor are they given any
// consensus-enforced meaning at this point.
if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) {
// The height of this input is not relevant for sequence locks
(*prevHeights)[txinIndex] = 0;
continue;
}
int nCoinHeight = (*prevHeights)[txinIndex];
if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) {
int64_t nCoinTime = block.GetAncestor(std::max(nCoinHeight-1, 0))->GetMedianTimePast();
// NOTE: Subtract 1 to maintain nLockTime semantics
// BIP 68 relative lock times have the semantics of calculating
// the first block or time at which the transaction would be
// valid. When calculating the effective block time or height
// for the entire transaction, we switch to using the
// semantics of nLockTime which is the last invalid block
// time or height. Thus we subtract 1 from the calculated
// time or height.
// Time-based relative lock-times are measured from the
// smallest allowed timestamp of the block containing the
// txout being spent, which is the median time past of the
// block prior.
nMinTime = std::max(nMinTime, nCoinTime + (int64_t)((txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) << CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - 1);
} else {
nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1);
}
}
return std::make_pair(nMinHeight, nMinTime);
}
static bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair<int, int64_t> lockPair)
{
assert(block.pprev);
int64_t nBlockTime = block.pprev->GetMedianTimePast();
if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime)
return false;
return true;
}
bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block)
{
return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block));
}
bool CheckSequenceLocks(const CTransaction &tx, int flags)
{
AssertLockHeld(cs_main);
AssertLockHeld(mempool.cs);
CBlockIndex* tip = chainActive.Tip();
CBlockIndex index;
index.pprev = tip;
// CheckSequenceLocks() uses chainActive.Height()+1 to evaluate
// height based locks because when SequenceLocks() is called within
// ConnectBlock(), the height of the block *being*
// evaluated is what is used.
// Thus if we want to know if a transaction can be part of the
// *next* block, we need to use one more than chainActive.Height()
index.nHeight = tip->nHeight + 1;
// pcoinsTip contains the UTXO set for chainActive.Tip()
CCoinsViewMemPool viewMemPool(pcoinsTip, mempool);
std::vector<int> prevheights;
prevheights.resize(tx.vin.size());
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
const CTxIn& txin = tx.vin[txinIndex];
CCoins coins;
if (!viewMemPool.GetCoins(txin.prevout.hash, coins)) {
return error("%s: Missing input", __func__);
}
if (coins.nHeight == MEMPOOL_HEIGHT) {
// Assume all mempool transaction confirm in the next block
prevheights[txinIndex] = tip->nHeight + 1;
} else {
prevheights[txinIndex] = coins.nHeight;
}
}
std::pair<int, int64_t> lockPair = CalculateSequenceLocks(tx, flags, &prevheights, index);
return EvaluateSequenceLocks(index, lockPair);
}
感谢 Gregory Maxwell 提供了对此更改行为的简洁明了的描述,这成为了此 BIP 文本的基础。
此 BIP 由 BtcDrak、Nicolas Dorier 和 kinoshitajona 编辑。
此 BIP 将使用位 0 通过 “versionbits” BIP9 部署。
对于比特币主网,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 必须与 BIP112 和 BIP113 同时部署,使用相同的部署机制。
Bitcoin Core 参考客户端软件对序列号的唯一用途是禁用对交易中 nLockTime 约束的检查。此 BIP 保留了该应用程序的语义。
从规范部分可以看出,此 BIP 未定义许多位,以允许其他用例,因为设置位 (1 << 31) 时,剩余的 31 位在此 BIP 下没有任何意义。此外,当位 (1 << 31) 未设置时,位 (1 << 23) 到 (1 << 30) (包括 1 << 30)根本没有任何意义。
此外,此 BIP 仅指定 16 位来实际编码相对锁定时间,这意味着还有 6 位未使用(包括 1 << 16 到 1 << 21)。这允许通过软分叉来增加粒度,或者在将来增加最大可能的相对锁定时间的可能性。
从相对锁定时间计算序列号的最有效方法是使用位掩码和移位:
// 0 <= nHeight < 65,535 区块 (1.25 年)
nSequence = nHeight;
nHeight = nSequence & 0x0000ffff;
// 0 <= nTime < 33,554,431 秒 (1.06 年)
nSequence = (1 << 22) | (nTime >> 9);
nTime = (nSequence & 0x0000ffff) << 9;
比特币邮件列表讨论:https://www.mail-archive.com/bitcoin-development@lists.sourceforge.net/msg07864.html
BIP9: https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki
BIP112: https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki
BIP113: https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki
哈希时间锁定合约(HTLC):https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf
- 原文链接: github.com/ajtowns/bips/...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!