読者です 読者をやめる 読者になる 読者になる

Develop with pleasure!

福岡でCloudとかBlockchainとか。

シーケンス番号を使ったRelative lock-timeについて(BIP-68)

BitcoinトランザクションにはnLockTimeというパラメータがあり、nLockTimeで指定した時刻が過ぎるまではそのトランザクションはブロックに入れられないよう制限ができる。nLockTimeはトランザクションに1つしか設定できないけど、このnLockTimeを相対的に制御できるよう拡張する仕組みがBIP-68で紹介されている Relative Lock-Time (RLT) 。

bips/bip-0068.mediawiki at master · bitcoin/bips · GitHub

摘要

BIP-68では、署名されたトランザクションについて、その入力のoutpointのconfirmationが終わってから指定された期間までは、その入力を無効な状態にするRelative Lock-Time (RLT) の機能について紹介する。

動機

Bitcoinトランザクションは各入力にシーケンス番号フィールドを持っている。もともとのアイディアでは、メモリプール内のトランザクションの入力と同じ入力でかつより高いシーケンス番号持つトランザクションを作ることでconrim前のトランザクションの置換を行うためのものだった。これは最初のBitcoinのリリースで実装されていたけど、トランザクションの置換により置換後のトランザクションの方が手数料が小さい場合、マイナーが置換後のトランザクションをブロックの対象にするインセンティブが無いため失敗した。
このBIPによる変更では、既存の機能を壊すことなく新しいユースケースのためにこのシーケンス番号を利用する。また将来の拡張や他のユースケースのための余地を残す。

トランザクションのnLockTimeは、特定の日付までトランザクションのマイニングをさせないために使われる。nSequenceは、出力が一定の年齢になるまでトランザクションのマイニングをさせないために再利用される。これは、他の用途としてHashed Timelock Contracts (HTLCs)BIP-112で使わるような双方向のペイメントチャネルを可能にする。

仕様

  • bit(1 << 31*1)のシーケンス番号がセットされた場合、シーケンス番号はノーコンセンサスを意味し、任意のブロックに含めることができる。
  • bit(1 << 31)のシーケンス番号がセットされていない場合、シーケンス番号はエンコードされたrelative lock-timeとして解釈される。

(32bit目のbitが立っている場合はノーコンセンサスで、bitが0の場合はrelative lock-timeとして解釈される)

シーケンス番号のエンコーディングは以下のように解釈される。

bit (1 << 22)でrelative lock-timeが時間ベースかブロックベースか決められ(23bit目が時間ベースかブロックベースかのフラグとして扱われている)、bitがセットされている場合は、relative lock-timeは時間ベースとして判断され、512秒という単位でタイムスパンを指定する。タイムスパンは前のブロックの出力のmedian-time-pastから始まり、前のブロックのMTPが終点となる。(median-time-pastを使用するのは時間ベースの場合のみ)
bitがセットされていない場合、relative lock-timeはブロックベースとして判断されブロック数を指定する。

flag (1<<22) は、(BIP-112の)OP_CHECKSEQUENCEVERIFYの3バイトのPUSHDATAとしてBitcoinスクリプトで使われる3バイトの符号付き整数の最上位bitである。

この仕様ではrelative lock-timeとしてシーケンス番号の(シーケンス番号32bitの内)16bitのみを解釈するので、relative lock-timeを抽出するために”0x0000ffff”のマスクをシーケンス番号フィールドに適用する必要がある。この16bitの仕様は、相対的に1年間のrelative lock-timeを許容し、残りの16bitは将来の拡張のために確保されている。

時間ベースのrelative lock-timeでは、Bitcoinのブロックが600秒(10分)毎に生成されるため、512秒という粒度が採用された。そのためブロックベースもしくは時間ベースの使用時、同じ時間は有効なbitの数でエンコードすることができる。シーケンス番号から秒数に変換するには、512(2^9)を掛けるか、もしくは9bitほどシフトアップする。

relative lock-timeが時間ベースの場合、最小のblock-timeは入力の年齢以上であるという制約がある。relative time-based lock-timeがゼロの場合は、その入力は任意のブロックに含めることができるということを意味する。より一般的に言うと、relative time-based lock-time nは、出力がマイニングされた日から512*n秒後に任意のブロックに含めることができる。出力のマイニング日は、そのブロックがマイニングされた前のブロックのmedian-time-pastと等しい。

ブロックの生成時刻は、前のブロックのmedian-time-pastと等しい。

relative lock-timeがブロックベースの場合、最小のblock-heightは入力の年齢以上であるという制約がある。 relative block-based lock-timeがゼロの場合は、その入力任意のブロックに含めることができるということを意味する。より一般的に言うと、relative block lock-time nは、出力がマイニングされた日からnブロック後に任意のブロックに含めることができる。

実装

参照実装は以下のプルリクエストで提供されている。

github.com

まとめ&所感

  • nLockTimeはトランザクションに設定されていて、マイナーがそのトランザクションをブロックに入れるためのにはnLockTimeに指定されている時間より後でなければ入れられない。
  • Relative lock-timeでは、トランザクションの入力のシーケンス番号にエンコードされたrelative lock-timeをセットし、相対的な時間によるロックができるようになる。
  • 同じ入力を持ちながらロックタイムを変更したトランザクションを作成することで、双方向ペイメントチャネルなどでの利用が考えられる。
  • Relative lock-timeでは時間ベースかブロックベースのロックタイムを設定できる。(ロックタイム=nとして)時間ベースの場合はn*512秒間のロック、ブロックベースの場合はその後nブロック間のロックとなる。
  • median time pastについてははBIP-113を要確認。
  • ただ、これ(もともとシーケンス番号の仕組みがあるからだろうけど)トランザクションの入力毎に設定する必要あるんだろうか?

*1:1<<31 = 2147483648