ビットコインのタイムロックあれこれ

#タイムロックって何？
ビットコインはタイムロックという機能を備えています。これは、特定の時間に達するまでトランザクションもしくはアウトプットを使用可能にしない、という機能です。トランザクションにlocktimeフィールド(nLocktime)があるので知っている人は多いと思いますが、nLocktime以外にもタイムロックを実現する方法はあります。本記事は以下のサイトの大雑把なまとめになります。

参考サイト
https://en.bitcoin.it/wiki/Timelock
https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch07.asciidoc#Timelocks

#タイムロックの分類
タイムロックは絶対時間/相対時間で制御するものに分類され、その中でもトランザクション単位/アウトプット単位のタイムロックに分類されます。

|  |絶対時間  |相対時間  |
|---|---|---|
|トランザクション単位  |nLocktime  |nSequence(BIP68)  |
|アウトプット単位  |CLTV(BIP65)  |CTV(BIP112)  |

それぞれ順に見ていきましょう。

#絶対時間を使用したタイムロック
文字通り、絶対時間でタイムロックを指定します。2020年の1月1日とか、ブロック高が580000などのように表現します。

##nLocktime
ビットコインの実装当初から提供されている、トランザクション単位のタイムロックです。nLocktimeはこのトランザクションがブロックに追加される最も早い絶対時間を表し、ブロック高もしくはUnixタイムスタンプで表現します。

###問題点
nLocktimeは将来の支払いを可能にしますが、その支払いは必ずしも保証されません。
例として、AliceがBobに1BTC支払うトランザクションABを考えます。このトランザクションには現在から一ヶ月後のnLocktimeが設定されています。
この時、Aliceがインプットに指定したUTXOは束縛されていません。AliceはトランザクションABを作成した後、
同一のUTXOを使用してCarolに1BTC支払うトランザクションAC(タイムロック無し)を作成することが可能です。

BobはトランザクションABを受け取り、一ヶ月にAliceから1BTC送金されることを期待していますが、実際はそのインプットはCarolへ送金されているので、Bobはお金を受け取ることが出来ない、という状況が発生します。

##Check Lock Time Verify(CLTV)
nLocktimeには上記の問題点があります。そのため、タイムロックの時点まで資金を使えないようにする機能が必要だということで、[OP_CHECKLOCKTIMEVERIFY](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki)が提案されました。nLocktimedではUTXOが束縛されていないことが問題となっていましたが、CLTVではUTXO(redeem script)にタイムロックが適用されるので、これを解決することができます。CLTVを使用することで資金をタイムロックの時点まで使用不可能にすることができます。

OP_CHECKLOCKTIMEVERIFYはP2SHトランザクションのredeem script(locking script)に指定します。
AliceからBobへ、現在から三ヶ月のタイムロックを施したトランザクションは以下のようになります。
`<now + 3 months> CHECKLOCKTIMEVERIFY DROP DUP HASH160 <Bob's Public Key Hash> EQUALVERIFY CHECKSIG`
https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch07.asciidoc#check-lock-time-verify-cltv

Bobは三ヶ月経過しないと資金を使用できないですし、この資金はBobの鍵によってロックされているため、Alcieが使用することはできません。

#相対時間を使用したタイムロック
特定のトランザクションが承認されてからの経過時間(相対時間)でタイムロックを指定します。とあるトランザクションが承認されてから24時間後とか、1000ブロック後などのように表現します。

##nSequence
シーケンス番号(nSequence)は、トランザクションのインプットのフィールドの1つです。nSequenceはlocktimeに示す時間/ブロック高に到達していないトランザクションの書き換えを行うためのフィールドですが、現在使われていません。基本的には整数最大値(0xFFFFFFFF)に設定され、無視されます。

[BIP68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki)は、このnSequenceフィールドに新しく相対時間のタイムロックの意味合いを持たせたものです。トランザクションのインプットが参照するUTXOがブロックチェーンに追加されてからの相対時間を秒/ブロック高で指定します。
仕様は以下の図のようになります。図はnSequenceの各ビットを表しています。

- Disable Flag : 本提案である、相対時間タイムロックの使用/不使用をセット
- Type Flag : タイムロックに秒(512秒単位[^1])/ブロック高どちらを使用するかセット
- Value : 相対時間/ブロック高をセット

![encoding.png](https://qiita-image-store.s3.amazonaws.com/0/296896/6e26831a-fb9a-44bb-827c-1bcba98f89cf.png)
https://github.com/bitcoin/bips/blob/master/bip-0068/encoding.png
[^1]: ブロック生成間隔が約10分(600秒)のため、512秒単位で指定される。即ち、Valueにnが設定されるとn * 512秒の相対時間となる。

##CHECK SEQUENCE VERIFY(CSV)
nLocktimeとCLTVの関係のように、相対時間をredeem script内で使用するための新たなオペコードが[OP_CHECKSEQUENCEVERIFY](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki)です。スクリプトの書き方ははCLTVの時とほとんど一緒です。以下のサイトにOP_CSVを使用したスクリプトの例があります。
https://techmedia-think.hatenablog.com/entry/2016/08/15/160924


#(注意)Median time past - タイムロックの比較は格納されるブロックのタイムスタンプではない
タイムロックは、そのトランザクションが格納されるブロックのタイムスタンプと比較されません。これは、マイナーが虚偽のタイムスタンプを発行することで、タイムロックの時刻に達しておらず、本来ならばブロックに取り入れるべきではないトランザクションをブロックに格納することが可能になるからです。
(マイナーは信頼できる第三者ではないので、ブロックのタイムスタンプに対して嘘をつくことができる。)
これを防ぐために、[median time past](https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki)という考えが提案されました。

タイムロックは過去11ブロックのタイムスタンプの中央値と比較されます。ブロック生成間隔が約10分なので、トランザクションが有効になる時刻はデフォルトでタイムロックに指定した時間より約1時間遅くなります。