mirror of
https://github.com/ChristopherA/Learning-Bitcoin-from-the-Command-Line.git
synced 2025-06-08 00:16:26 +00:00
Update 9_3_Using_CSV_in_Scripts.md
This commit is contained in:
parent
4b22f05835
commit
d6a8ab53c4
@ -2,33 +2,35 @@
|
||||
|
||||
> **NOTE:** This is a draft in progress, so that I can get some feedback from early reviewers. It is not yet ready for learning.
|
||||
|
||||
`nLockTime` and `OP_CHECKLOCKTIMEVERIFY` (or CLTV) are just one side of the timelock equation. On the other are `nSequence` and `OP_CHECKSEQUENCEVERIFY`, which can be used to check against relative times rather than absolute times.
|
||||
`nLockTime` and `OP_CHECKLOCKTIMEVERIFY` (or CLTV) are just one side of the timelock equation. On the other side are `nSequence` and `OP_CHECKSEQUENCEVERIFY`, which can be used to check against relative times rather than absolute times.
|
||||
|
||||
> **VERSION WARNING:** CSV became available with Bitcoin Core 0.12.1, in spring 2016.
|
||||
|
||||
## Understand nSequence
|
||||
|
||||
Every UTXO used in a transaction has an `nSequence` (or if you prefer `sequence`) value. It's been a prime tool for Bitcoin expansions as discussed previously in [§5.2: Resending a Transaction with RBF](5_2_Resending_a_Transaction_with_RBF.md) and [§6.4 Sending a Transaction with a Locktime.md](6_4_Sending_a_Transaction_with_a_Locktime.md), where it was used to signal RBF and `nLockTime`, respectively. However, there's one more use for `nSequence`, described by [BIP 68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki): you can use it to create a relative timelock on a transaction.
|
||||
Every input into in a transaction has an `nSequence` (or if you prefer `sequence`) value. It's been a prime tool for Bitcoin expansions as discussed previously in [§5.2: Resending a Transaction with RBF](5_2_Resending_a_Transaction_with_RBF.md) and [§6.4 Sending a Transaction with a Locktime.md](6_4_Sending_a_Transaction_with_a_Locktime.md), where it was used to signal RBF and `nLockTime`, respectively. However, there's one more use for `nSequence`, described by [BIP 68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki): you can use it to create a relative timelock on a transaction.
|
||||
|
||||
A relative timelock is a lock that's placed on a specific input of a transaction and that's calculated in relation to the mining date of the UTXO being used in th einput. For example, if a UTXO was mined at block #468260 and a transaction was created where the input for that UTXO was given an `nSequence` of 100, then the new transaction could not be mined until at least block #468360.
|
||||
A relative timelock is a lock that's placed on a specific input of a transaction and that's calculated in relation to the mining date of the UTXO being used in the input. For example, if a UTXO was mined at block #468260 and a transaction was created where the input for that UTXO was given an `nSequence` of 100, then the new transaction could not be mined until at least block #468360.
|
||||
|
||||
Easy!
|
||||
|
||||
> **SEQUENCE NOTE (III):** This is the third use of the `nSequence` value in Bitcoin. Any `nSequence` value from 1 to 0xf0000000-1 will be interpreted as a relative timelock if `nVersion ≥ 2` (which was the default starting in Bitcoin Core 0.14.0). You should be careful to ensure that relative timelocks don't conflict with the other two uses of `nSequence`, for signalling `nTimeLock` and RBF. `nTimeLock` usually sets a value of 0xffffffff-1, where a relative timelock is disallowed; and RBF usually sets a value of "1", where a relative timelock is irrelevent, because it defines a timelock of 1 block. In general, remember: with a `nVersion` value of 2, a `nSequence` value of 0x00000001 to 0xf0000000-1 allows relative timelock, RBF, and `nTimeLock`; a `nSequence` value of 0xf0000000 to 0xffffffff-2 allows RBF and `nTimeLock`; a `nSequence` value of 0xffffffff-1 allows only `nTimeLock`; a `nSequence` value of 0xffffffff allows none; and `nVersion` can be set to 1 to disallow relative timelocks for any value of `nSequence`. Whew!
|
||||
> **SEQUENCE NOTE (III):** This is the third use of the `nSequence` value in Bitcoin. Any `nSequence` value from 1 to 0xf0000000-1 will be interpreted as a relative timelock if `nVersion ≥ 2` (which is the default starting in Bitcoin Core 0.14.0). You should be careful to ensure that relative timelocks don't conflict with the other two uses of `nSequence`, for signalling `nTimeLock` and RBF. `nTimeLock` usually sets a value of 0xffffffff-1, where a relative timelock is disallowed; and RBF usually sets a value of "1", where a relative timelock is irrelevent, because it defines a timelock of 1 block.
|
||||
|
||||
> In general, remember: with a `nVersion` value of 2, a `nSequence` value of 0x00000001 to 0xf0000000-1 allows relative timelock, RBF, and `nTimeLock`; a `nSequence` value of 0xf0000000 to 0xffffffff-2 allows RBF and `nTimeLock`; a `nSequence` value of 0xffffffff-1 allows only `nTimeLock`; a `nSequence` value of 0xffffffff allows none; and `nVersion` can be set to 1 to disallow relative timelocks for any value of `nSequence`. Whew!
|
||||
|
||||
### Create a CSV Relative Block Time
|
||||
|
||||
The format for using `nSequence` to represent relative time locks is defined in [BIP 68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki) and is slightly more complex than just inputting a number, like you did for `nTimeLock`. Instead, the BIP specifications breaks up the four byte number into three parts:
|
||||
|
||||
* The first two bytes are used to specify a relative locktime.
|
||||
* The 23rd bit is used to signal if the lock refers to a time rather than a blockheight.
|
||||
* The 32nd bit is used to signal if relative timelocks are deactivated.
|
||||
* The 23rd bit is used to positively signal if the lock refers to a time rather than a blockheight.
|
||||
* The 32nd bit is used to positively signal if relative timelocks are deactivated.
|
||||
|
||||
If you want to create a block-based relative timelock, the construction is still quite easy: you set `nSequence` to a value between 1 and 0xffff (65535). The new transaction can be mined that numebr of blocks after the associated UTXO was mined.
|
||||
If you want to create a block-based relative timelock, the construction is still quite easy: you set `nSequence` to a value between 1 and 0xffff (65535). The new transaction can be mined that number of blocks after the associated UTXO was mined.
|
||||
|
||||
### Create a CSV Relative Time
|
||||
|
||||
You can instead set `nSequence` as a relative time, where the lock lasts for 512 seconds time the value of `nSequence`.
|
||||
You can instead set `nSequence` as a relative time, where the lock lasts for 512 seconds times the value of `nSequence`.
|
||||
|
||||
In order to do that:
|
||||
|
||||
@ -36,13 +38,19 @@ In order to do that:
|
||||
2. Convert that to seconds.
|
||||
3. Divide by 512.
|
||||
4. Round that value up or down and set it as `nSequence`.
|
||||
5. Set bit 23 to true.
|
||||
5. Set the 23rd bit to true.
|
||||
|
||||
To set a time 6 months n the future, you would first calculate as follows:
|
||||
To set a time 6 months n the future, you must first calculate as follows:
|
||||
```
|
||||
$ seconds=$((6*30*24*60*60))
|
||||
$ nvalue=$(($seconds/512))
|
||||
```
|
||||
Then, turn it into hex:
|
||||
```
|
||||
$ hexvalue=$(printf '%x\n' $nvalue)
|
||||
```
|
||||
Finally, bitwise-or the 23rd bit into the hex value you created:
|
||||
```
|
||||
$ relativevalue=$(printf '%x\n' $((0x$hexvalue | 0x400000)))
|
||||
$ echo $relativevalue
|
||||
4224679
|
||||
@ -51,14 +59,14 @@ If you convert that back you'll see that 4224679 = 10000000111011010100111. The
|
||||
|
||||
## Create a Transaction with a Relative Timelock
|
||||
|
||||
So you want to create a relative timelock? All you have to do is issue a tranaction where the `nSequence` in an input is set in accordance with the above: with the `nSequence` for that input set such that the first two bytes define the timelock, the 23rd bit defines the type of timelock, and the 32nd bit is set to false. It's a straight up two-byte number for a timelock based on relative blockheight and it's a two-byte number `0x400000` for a timelock based on relative time.
|
||||
So you want to create a simple transaction with a relative timelock? All you have to do is issue a tranaction where the `nSequence` in an input is set as shown above: with the `nSequence` for that input set such that the first two bytes define the timelock, the 23rd bit defines the type of timelock, and the 32nd bit is set to false.
|
||||
|
||||
Issue the transaction, but it can't legally be mined until enough blocks or enough time has passed beyond the time that the transaction forming the UTXO was mined.
|
||||
Issue the transaction and you'll see that it can't legally be mined until enough blocks or enough time has passed beyond the time that the UTXO was mined.
|
||||
|
||||
Except pretty much no one does this. The new [BIP 68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki) definitions for `nSequence` were incorporated into Bitcoin Core at the same time as [BIP 112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki) which describes the CSV opcode, which works with `nSequence`, just like the CLTV opcode works with `nTimeLock`. Just like CLTV, CSV offers increased capabilities. So almost all usage of relative timelocks has been with the CSV opcode, not with the raw `nSequence` value on its own.
|
||||
Except pretty much no one does this. The [BIP 68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki) definitions for `nSequence` were incorporated into Bitcoin Core at the same time as [BIP 112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki). which describes the CSV opcode, the `nSequence` equivalent to the CLTV opcode. Just like CLTV, CSV offers increased capabilities. So, almost all usage of relative timelocks has been with the CSV opcode, not with the raw `nSequence` value on its own.
|
||||
|
||||
| | Absolute Timelock | Relative Timelock |
|
||||
|:------------------:|-------------------|-------------------|
|
||||
| | Absolute Timelock | Relative Timelock |
|
||||
|:--------------------:|-------------------|-------------------|
|
||||
| **Lock Transaction** | nTimeLock | nSequence |
|
||||
| **Lock Output** | OP_CHECKLOCKTIMEVERIFY| OP_CHECKSEQUENCEVERIFY |
|
||||
|
||||
@ -79,7 +87,7 @@ In this case we'll probably use a shorthand:
|
||||
<+6Months> OP_CHECKSEQUENCEVERIFY
|
||||
```
|
||||
|
||||
> **WARNING:** Remember that your a relative time lock is a time span since the mining of the UTXO used as an input. It is _not_ a timespan after you create the transaction. If you use a UTXO that's already been confirmed a hundred times, and you place a relative timelock of 100 blocks on it, it will be eligible for mining immediately. Relative timelocks have some very specific uses, but they probably don't apply if your only goal is to determine some set time in the future.
|
||||
> **WARNING:** Remember that a relative timelock is a time span since the mining of the UTXO used as an input. It is _not_ a timespan after you create the transaction. If you use a UTXO that's already been confirmed a hundred times, and you place a relative timelock of 100 blocks on it, it will be eligible for mining immediately. Relative timelocks have some very specific uses, but they probably don't apply if your only goal is to determine some set time in the future.
|
||||
|
||||
### Understand How CSV Really Works
|
||||
|
||||
@ -87,7 +95,7 @@ CSV has many of the same subtleties in usage as CLTV:
|
||||
|
||||
* The `nVersion` field must be set to 2 or more.
|
||||
* The `nSequence` field must be set to less than 0xf0000000.
|
||||
* There must be an operand on the stack that's between 0 and 0xf0000000-1.
|
||||
* When CSV is run, there must be an operand on the stack that's between 0 and 0xf0000000-1.
|
||||
* Both the stack operand and `nSequence` must have the same value on the 23rd bit.
|
||||
* The `nSequence` must be greater than or equal to the stack operand.
|
||||
|
||||
@ -104,7 +112,7 @@ A script that would lock funds until six months had passed following the mining
|
||||
|
||||
### Encode a CLTV Script
|
||||
|
||||
When you encode a CLTV script, be careful how you encode the integer value for the relative locktime. It should be passed as a 3-byte integer, which means that you're ignoring the top byte which could inactivate the relative locktime. Since it's an integer, be sure you convert it to little-endian.
|
||||
When you encode a CLTV script, be careful how you encode the integer value for the relative locktime. It should be passed as a 3-byte integer, which means that you're ignoring the top byte, which could inactivate the relative locktime. Since it's an integer, be sure you convert it to little-endian.
|
||||
|
||||
This can be done with the `integer2lehex.sh` shell script from the previous chapter.
|
||||
|
||||
@ -133,6 +141,6 @@ To spend a UTXO locked with a CSV script, you must set the `nSequence` of that i
|
||||
|
||||
## Summary: Using CSV in Scripts
|
||||
|
||||
`nSequence` and CSV offer an alternative to `nLockTime` and CLTV where you lock a transaction based on a relative time since the input was mined, rather than a set time in the future. Other than that they work almost identically, other than the fact that the `nSequence` value is encoded slightly differently than the `nLockTime` value, with specific bits meaning specific things.
|
||||
`nSequence` and CSV offer an alternative to `nLockTime` and CLTV where you lock a transaction based on a relative time since the input was mined, rather than basing the lock on a set time in the future. They work almost identically, other than the fact that the `nSequence` value is encoded slightly differently than the `nLockTime` value, with specific bits meaning specific things.
|
||||
|
||||
_What is the power of CSV?_ CSV isn't just a lazy way to lock, when you don't want to calculate a time in the future. Instead, it's a totally different paradigm, a lock that you would use if it was important to create a specific minimum duration between when a transaction is mined and when its funds can be respent. The most obvious usage is (once more) for an escrow, when you want a precise time between the input of funds and their output. However, it has much more powerful possibilities in off-chain transactions, including payment channels. These applications are by definition built on transactions that are not actually put onto the blockchain, which means that if they are later put on the blockchain an enforced time-lapse can be very helpful. [Hashed Timelock Contracts](https://en.bitcoin.it/wiki/Hashed_Timelock_Contracts) have been one such implementation, empowering the Lightning payment network.
|
||||
|
Loading…
x
Reference in New Issue
Block a user