diff options
author | BtcDrak <btcdrak@gmail.com> | 2015-11-20 10:47:46 +0000 |
---|---|---|
committer | BtcDrak <btcdrak@gmail.com> | 2015-11-20 10:52:05 +0000 |
commit | b5bc89a67c4fd5a0bd0fe1af0b328793ff783ff3 (patch) | |
tree | 5ba67cd6fedfd762b15d0ff7dc61174d5a2789cb /bip-0068.mediawiki | |
parent | 641b91ba286d0b18554a7b26cccc2f90a5eb6f74 (diff) |
BIP68: Simplify language and update for current implementation
Diffstat (limited to 'bip-0068.mediawiki')
-rw-r--r-- | bip-0068.mediawiki | 231 |
1 files changed, 99 insertions, 132 deletions
diff --git a/bip-0068.mediawiki b/bip-0068.mediawiki index 12b97c7..fa05c4a 100644 --- a/bip-0068.mediawiki +++ b/bip-0068.mediawiki @@ -2,6 +2,8 @@ BIP: 68 Title: Consensus-enforced transaction replacement signaled via sequence numbers (relative lock-time) Author: Mark Friedenbach <mark@friedenbach.org> + BtcDrak <btcdrak@gmail.com> + Nicolas Dorier <nicolas.dorier@gmail.com> Status: Draft Type: Standards Track Created: 2015-05-28 @@ -9,19 +11,41 @@ ==Abstract== -This BIP describes a modification to the consensus-enforced semantics of the sequence number field to enable a signed transaction input to remain invalid for a defined period of time after confirmation of its corresponding outpoint, for the purpose of supporting consensus-enforced transaction replacement features. +This BIP describes introduces consensus-enforced semantics of the sequence number field to enable a signed transaction input to remain invalid for a defined period of time after confirmation of its corresponding outpoint, for the purpose of supporting consensus-enforced transaction replacement features. ==Motivation== -Bitcoin has sequence number fields for each input of a transaction. The original idea appears to have been that the highest sequence number should dominate and miners should prefer it over lower sequence numbers. This was never really implemented, and the half-implemented code seemed to be making an assumption that miners would honestly prefer the higher sequence numbers, even if the lower ones were much much more profitable. That turns out to be a dangerous assumption, and so most technical people have assumed that kind of sequence number mediated replacement was useless because there was no way to enforce "honest" behavior, as even a few rational (profit maximizing) miners would break that completely. The change described by this BIP provides the missing piece that makes sequence numbers do something significant with respect to enforcing transaction replacement without assuming anything other than profit-maximizing behavior on the part of miners. +Bitcoin transactions have a sequence number fields for each input of a transaction. The original idea appears to have been that the highest sequence number should dominate and miners should prefer higher sequence numbers by policy alone, although this was not implemented it assumes miners would prefer the higher sequence numbers even if the lower ones were much much more profitable. However, profit maximizing miners would break that assumption completely. The change described by this BIP repurposes the sequence number into a new usage without breaking existing usages while leaving room for future expansion and other use cases. + +The transaction nLockTime is used to prevent the mining of a transaction until a certain date. (in block height or time) +nSequence will be repurposed to prevent mining of a transaction until a certain age of the spent output. (in blocks or timespan) +This, among other usage, allows bi-directional payment channels as used in [Hashed Timelock Contrats (HTLCs)](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) and [BIP112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki#Bidirectional_Payment_Channels). ==Specification== -For transactions with an nVersion of 2 or greater, if the most significant bit (1 << 31) of a sequence number is clear, the remaining 31 bits are interpreted as an encoded relative lock-time. A sequence number with the most significant bit set is given no consensus meaning and can be included in any block, like normal, under all circumstances. +This specification defined the meaning of sequence numbers for transactions with an nVersion greater than or equal to 2 for which the rest of this specification relies on. + +If bit (1 << 31) of the sequence number is set, then no consensus meaning is applied to the sequence number and can be included in any block, like normal, under all circumstances. + +If bit (1 << 31) of the sequence number is clear, then the sequence number is interpreted as an encoded relative lock-time. + +The sequence number encoding is interpreted as follows: + +Bit (1 << 22) determines if the relative lock-time is time based or block based. +If the bit is set, the interpretation for relative lock-time in units of 512 seconds. If the bit is not set, it specifies relative lock-time in blocks. + +Note (1 << 22) was chosen because it is the highest you can go without moving to 4-byte pushes when using the Bitcoin scripting language in conjunction with OP_CHECKSEQUENCEVERIFY: i.e. 3 bytes = 24 bits where pushes are signed integers which leaving 1 bit for the flag and 22 bits for the relative lock-time encoding. -If the second most significant bit (1 << 30) is clear, the next 16 bits are interpreted as a minimum block-height constraint over the input's age. The remaining 14 bits have no consensus-enforced meaning. A sequence number of zero indicates a relative lock-time of zero blocks (bits 31 and 30 clear) and can be included in any block. A sequence number of 1 << 14 can be included in the next block after the input it is spending, or any block thereafter, but cannot be included in the same block as its parent. A sequence number of 2 << 14 can't be included until at least two blocks later, and so on. +This specification only interprets 16 bits of the sequence number as relative lock-time, so a mask of 0x0000ffff must be applied to the sequence field to extract the relative lock-time. This is to allow for future expansion. The specification allows for a year of relative lock-time. -Alternatively, if the second most significant bit (1 << 30) is set, the next 25 bits are interpreted as a minimum block-time constraint over the input's age. The remaining 5 bits have no consensus-enforced meaning. A sequence number with just that second most significant bit set (0x40000000) is interpreted as a relative lock-time of 0, measured in seconds, and can be included in the same block as the output being spent. Advancing that sequence number by 2^5 (0x40000020) constrains the transaction to be included in blocks with an nTime timestamp at least one second greater than the median time stamp of the 11 blocks prior to the block containing the coin being spent. Advancing the sequence number by an additional 2^5 (0x40000040) constrains the spend to be two seconds later, and so on. +For time based relative lock-time, 512 second granularity was chosen because bitcoin blocks are generated every 600 seconds. So when using block based or time based relative locktime, the same amount of time can be encoded with the available number of bits. Converting from a sequence number to seconds is performed by multiplying by 512 = 2^9, or equivalently shifting up by 9 bits. + +When the relative lock-time is time-based, it is interpreted as a minimum block-time constraint over the input's age. A relative time-based lock-time of zero indicates an input which can be included in any block. More generally, a relative time-based lock-time n can be included into any block produced 512 * n seconds after the mining date of the output it is spending, or any block thereafter. +The mining date of the output is equals to the Median Time Past of the previous block which mined it. + +The block produced time is either equals to median time past of its parent or to its nTime field, depending on the state of BIP113 (MTP). + +When the relative lock-time is block-based, it is interpreted as a minimum block-height constraint over the input's age. A relative block-based lock-time of zero indicates an input which can be included in any block. More generally, a relative block lock-time n can be included n blocks after the mining date of the output it is spending, or any block thereafter. This is proposed to be accomplished by replacing IsFinalTx() and CheckFinalTx(), existing consensus and non-consensus code functions that return true if a transaction's lock-time constraints are satisfied and false otherwise, with LockTime() and CheckLockTime(), new functions that return a non-zero value if a transaction's lock-time or sequence number constraints are not satisfied and zero otherwise: @@ -33,28 +57,41 @@ This is proposed to be accomplished by replacing IsFinalTx() and CheckFinalTx(), /* Setting nSequence to this value for every input in a transaction * disables nLockTime. */ - const uint32_t CTxIn::SEQUENCE_FINAL = 0xffffffff; - /* Threshold for CTxIn::nSequence: below this value it is interpreted - * as arelative lock-time, otherwise ignored. */ - const uint32_t CTxIn::SEQUENCE_LOCKTIME_THRESHOLD = (1 << 31); - /* Threshold for CTxIn::nSequence when interpreted as a relative - * lock-time: below this value it has units of blocks, otherwise - * seconds. */ - const uint32_t CTxIn::SEQUENCE_UNITS_THRESHOLD = (1 << 30); - /* Number of reserved low-order bits (depending on units used) which - * are shifted out prior to relative lock-time constraint checking. */ - const int CTxIn::SEQUENCE_BLOCKS_OFFSET = 14; - const int CTxIn::SEQUENCE_SECONDS_OFFSET = 5; - - int64_t LockTime(const CTransaction &tx, - int flags, const CCoinsView* pCoinsView, - int nBlockHeight, int64_t nBlockTime) + static const uint32_t SEQUENCE_FINAL = 0xffffffff; + + /* If this flag set, CTxIn::nSequence is NOT interpreted as a + * relative lock-time. Setting the most significant bit of a + * sequence number disabled relative lock-time. */ + static const uint32_t SEQUENCE_LOCKTIME_DISABLED_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_SECONDS_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; + + int64_t LockTime(const CTransaction &tx, int flags, const std::vector<int>* prevHeights, const CBlockIndex& block) { - CCoins coins; - + assert(prevHeights == NULL || prevHeights->size() == tx.vin.size()); + int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST) + ? block.GetAncestor(std::max(block.nHeight-1, 0))->GetMedianTimePast() + : block.GetBlockTime(); + bool fEnforceBIP68 = static_cast<uint32_t>(tx.nVersion) >= 2 && flags & LOCKTIME_VERIFY_SEQUENCE; - + // 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. @@ -63,10 +100,10 @@ This is proposed to be accomplished by replacing IsFinalTx() and CheckFinalTx(), // Will remain equal to true if all inputs are finalized // (CTxIn::SEQUENCE_FINAL). bool fFinalized = true; - - BOOST_FOREACH(const CTxIn& txin, tx.vin) { + for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { + const CTxIn& txin = tx.vin[txinIndex]; // Set a flag if we witness an input that isn't finalized. - if (CTxIn::SEQUENCE_FINAL == txin.nSequence) + if (txin.nSequence == CTxIn::SEQUENCE_FINAL) continue; else fFinalized = false; @@ -74,70 +111,35 @@ This is proposed to be accomplished by replacing IsFinalTx() and CheckFinalTx(), // Do not enforce sequence numbers as a relative lock time // unless we have been instructed to, and a view has been // provided. - if (!(fEnforceBIP68 && pCoinsView)) + if (!fEnforceBIP68) continue; - // Sequence numbers equal to or above the locktime threshold - // are not treated as relative lock-times, nor are they given - // any consensus-enforced meaning at this point. - if (txin.nSequence >= CTxIn::SEQUENCE_LOCKTIME_THRESHOLD) + // 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_DISABLED_FLAG) continue; - // Fetch the UTXO corresponding to this input. - if (!pCoinsView->GetCoins(txin.prevout.hash, coins)) { - // It is fully expected that coinbases inputs are not - // found in the UTXO set. Proceed to the next intput... - if (txin.prevout.IsNull()) - continue; - // If a non-coinbase input cannot be found, we cannot - // be certain about whether lock-time constraints have - // been satisfied. Note that it should only ever be - // possible for this to happen with wallet transactions - // that have unknown inputs. - else - return std::numeric_limits<int64_t>::max(); - } - - // coins.nHeight is MEMPOOL_HEIGHT (an absurdly high value) - // if the parent transaction was from the mempool. We can't - // know what height it will have once confirmed, but we - // assume it makes it in the same block. - int nCoinHeight = std::min(coins.nHeight, nBlockHeight); - - if (txin.nSequence < CTxIn::SEQUENCE_UNITS_THRESHOLD) { + if (prevHeights == NULL) + continue; + + int nCoinHeight = (*prevHeights)[txinIndex]; + + if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_SECONDS_FLAG) { + + int64_t nCoinTime = block.GetAncestor(std::max(nCoinHeight-1, 0))->GetMedianTimePast(); + + // 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 { // We subtract 1 from relative lock-times because a lock- // time of 0 has the semantics of "same block," so a lock- // time of 1 should mean "next block," but nLockTime has // the semantics of "last invalid block height." - nMinHeight = std::max(nMinHeight, nCoinHeight + (int)( - txin.nSequence >> CTxIn::SEQUENCE_BLOCKS_OFFSET) - 1); - } else { - // In two locations that follow we make reference to - // chainActive.Tip(). To prevent a race condition, we - // store a reference to the current tip. - // - // Note that it is not guaranteed that indexBestBlock will - // be consistent with the passed in view. The proper thing - // to do is to have the view return time information about - // UTXOs. - const CBlockIndex& indexBestBlock = *chainActive.Tip(); - - // The only time the negative branch of this conditional - // is executed is when the prior output was taken from the - // mempool, in which case we assume it makes it into the - // same block (see above). - int64_t nCoinTime = (nCoinHeight <= (indexBestBlock.nHeight+1)) - ? indexBestBlock.GetAncestor(nCoinHeight-1)->GetMedianTimePast() - : nBlockTime; - - // 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. We subtract one for the same reason as - // above. - nMinTime = std::max(nMinTime, nCoinTime + (int64_t)(( - txin.nSequence - CTxIn::SEQUENCE_UNITS_THRESHOLD) - >> CTxIn::SEQUENCE_SECONDS_OFFSET) - 1); + nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1); } } @@ -146,62 +148,30 @@ This is proposed to be accomplished by replacing IsFinalTx() and CheckFinalTx(), // are not enforced. if (fFinalized) return 0; - + if ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD) nMinHeight = std::max(nMinHeight, (int)tx.nLockTime); else nMinTime = std::max(nMinTime, (int64_t)tx.nLockTime); - if (nMinHeight >= nBlockHeight) + if (nMinHeight >= block.nHeight) return nMinHeight; + if (nMinTime >= nBlockTime) return nMinTime; return 0; - } - - int64_t CheckLockTime(const CTransaction &tx, int flags) - { - AssertLockHeld(cs_main); - - // By convention a negative value for flags indicates that the - // current network-enforced consensus rules should be used. - flags = std::max(flags, 0); - - // pcoinsTip contains the UTXO set for chainActive.Tip() - CCoinsViewMemPool viewMemPool(pcoinsTip, mempool); - const CCoinsView *pCoinsView = &viewMemPool; - - // CheckLockTime() uses chainActive.Height()+1 to evaluate - // nLockTime because when LockTime() is called within - // CBlock::AcceptBlock(), 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 call - // LockTime() with one more than chainActive.Height(). - const int nBlockHeight = chainActive.Height() + 1; - - // Timestamps on the other hand don't get any special treatment, - // because we can't know what timestamp the next block will have, - // and there aren't timestamp applications where it matters. - const int64_t nBlockTime = GetAdjustedTime(); - - return LockTime(tx, flags, pCoinsView, nBlockHeight, nBlockTime); - } -</pre> + }</pre> Code conditional on the return value of IsFinalTx() / CheckLockTime() has to be updated as well, since the semantics of the return value has been inverted. -==Rationale== - -Using sequence numbers for locking inputs makes sense, since no transaction can be in a block before its parent transactions. This means that a lower sequence number can always be included earlier than a higher one (even if the time the original coins being spent was unknown when the transaction was authored). Because of this, even rational miners should go along with the scheme: Take the lowest sequence number and collect the fees, or skip over it in the hopes that no one else takes a lower number before the next available higher number becomes spendable. And, of course, users are not constrained to make their sequence numbers go up only one at a time. So it's "take the most updated version, now, or gamble that no one in the next dozen blocks takes the most updated and that you manage to include the next to most when it finally becomes mineable." This is similar to how lock-time works. In fact, this scheme is precisely a per-input relative lock-time. - ==Example: Bidirectional payment channel== -A bidirectional payment channel can be established by two parties funding a single output in the following way: Alice funds a 1btc output which is the 2-of-2 multisig of Alice AND Bob, or Alice's key only after a sufficiently long timeout, e.g. 30 days or 4320 blocks. The channel-generating transaction is signed by Alice and broadcast to the network. +A bidirectional payment channel can be established by two parties funding a single output in the following way: Alice funds a 1 BTC output which is the 2-of-2 multisig of Alice AND Bob, or Alice's key only after a sufficiently long timeout, e.g. 30 days or 4320 blocks. The channel-generating transaction is signed by Alice and broadcast to the network. -Alice desires to send Bob a payment of 0.1btc. She does so by constructing a transaction spending the 1btc output and sending 0.1btc to Bob and 0.9btc back to herself. She provides her signature for the 2-of-2 multisig constraint, and sets a relative lock-time using the sequence number field such that the transaction will become valid 24-hours or 144 blocks before the refund timeout. Two more times Alice sends Bob a payment of 0.1btc, each time generating and signing her half of a transaction spending the 1btc output and sending 0.2btc, then 0.3btc to Bob with a relative lock-time of 29 days from creation of the channel. +Alice desires to send Bob a payment of 0.1 BTC. She does so by constructing a transaction spending the 1 BTC output and sending 0.1 BTC to Bob and 0.9 BTC back to herself. She provides her signature for the 2-of-2 multisig constraint, and sets a relative lock-time using the sequence number field such that the transaction will become valid 24-hours or 144 blocks before the refund timeout. Two more times Alice sends Bob a payment of 0.1 BTC, each time generating and signing her half of a transaction spending the 1btc output and sending 0.2 BTC, then 0.3 BTC to Bob with a relative lock-time of 29 days from creation of the channel. -Bob now desires to send Alice a refund of 0.25btc. He does so by constructing a transaction spending the 1btc output and sending 0.95btc (= 0.7btc + 0.25btc) to Alice and 0.05btc to himself. Since Bob will still have in his logs the transaction giving him 0.7btc 29 days after the creation of the channel, Alice demands that this new transaction have a relative lock-time of 28 days so she has a full day to broadcast it before the next transaction matures. +Bob now desires to send Alice a refund of 0.25 BTC. He does so by constructing a transaction spending the 1btc output and sending 0.95 BTC (= 0.7 BTC + 0.25 BTC) to Alice and 0.05 BTC to himself. Since Bob will still have in his logs the transaction giving him 0.7 BTC 29 days after the creation of the channel, Alice demands that this new transaction have a relative lock-time of 28 days so she has a full day to broadcast it before the next transaction matures. Alice and Bob continue to make payments to each other, decrementing the relative lock-time by one day each time the channel switches direction, until the present time is reached or either party desires to close out the channel. A close-out is performed by finalizing the input (nSequence = MAX_INT) and both parties signing. @@ -215,11 +185,13 @@ https://github.com/bitcoin/bitcoin/pull/6312 Credit goes to Gregory Maxwell for providing a succinct and clear description of the behavior of this change, which became the basis of this BIP text. +This BIP was edited by BtcDrak and Nicholas Dorier. + ==Deployment== -We reuse the double-threshold switch over mechanism from BIPs 34 and 66, with the same thresholds, but for nVersion = 4. The new rules are in effect for every block (at height H) with nVersion = 4 and at least 750 out of 1000 blocks preceding it (with heights H-1000..H-1) also have nVersion = 4. Furthermore, when 950 out of the 1000 blocks preceding a block do have nVersion = 4, nVersion = 3 blocks become invalid, and all further blocks enforce the new rules. +This BIP is to be deployed by either version-bits BIP9 or by isSuperMajority(). Exact details TDB. -It is recommended that this soft-fork deployment trigger include other related proposals for improving Bitcoin's lock-time capabilities, including [https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki BIP 65]: OP_CHECKLOCKTIMEVERIFY, [https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki BIP 112]: CHECKSEQUENCEVERIFY, and [https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki BIP 113] Median time-past as endpoint for lock-time calculations. +It is recommended to deploy BIP68 and BIP112 at the same time as this BIP. ==Compatibility== @@ -243,12 +215,7 @@ The most efficient way to calculate sequence number from relative lock-time is w Bitcoin mailing list discussion: https://www.mail-archive.com/bitcoin-development@lists.sourceforge.net/msg07864.html -[https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki BIP 34]: Block v2, Height in Coinbase - -[https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki BIP 65]: OP_CHECKLOCKTIMEVERIFY - -[https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki BIP 66]: Strict DER signatures - -[https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki BIP 112]: CHECKSEQUENCEVERIFY +BIP112: https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki +BIP113: https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki +Hashed Timelock Contrats (HTLCs): https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf -[https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki BIP 113]: Median time-past as endpoint for lock-time calculations |