Develop with pleasure!

福岡でCloudとかBlockchainとか。

チェーン上のトランザクションの新たな参照方法の標準TxRefを定義したBIP-136

提案は結構前からあったみたいだけど先月マージされたBIP-136↓

https://github.com/bitcoin/bips/blob/master/bip-0136.mediawiki

Bitcoinトランザクションを識別する際は、基本的にトランザクションのハッシュのエンディアンを逆にしたTXIDを使用する。フルノードでこのTXIDをキーにしてトランザクションを取得したい場合は予め-txindexオプションを有効にしてTXIDによるインデックスを作成しなければならない。このインデックスの作成が高価なのと、TXID自体32バイトと長い。そのため↑のBIP-136では、TXIDに変わってブロックチェーン上のトランザクションを参照する新しい識別子TxRefを提案している。

TxRefは何番目のブロックの何番目のトランザクションという、ブロック高とトランザクションの位置をエンコードしたデータになる。そのため、reorgなんかが起こると参照先のトランザクションが別のものに変わったり、なくなっている可能性があるという制約が付く。

具体的なユースケースがあるのか?と思って調べたら、どうも分散IDの文脈で、Bitcoinブロックチェーンを利用したDID methodの1つであるBTCR DID methodでチェーン上のトランザクションの位置を指すのにTxRefエンコーディングを使ってるっぽい↓

https://w3c-ccg.github.io/didm-btcr/#txref

注意点としては、やっぱりreorgの影響かな。BIPにも100承認以上とあるけど、TXIDと違って別のTxを参照する可能性があるので承認がある程度ないと使いづらい。

以下、BIPの内容↓

イントロダクション

概要

この文書は、Bitcoinブロックチェーン内のトランザクションの位置および参照トランザクション内の特定のOutPointインデックスを参照するための標準的な方法として、人が便利に使用できるフォーマット「TxRef」を提案する。このフォーマットの主な目的は、承認されたトランザクションを参照する際の標準的で信頼性のある簡潔な方法を提供することだ。

注意:IDと実際のトランザクションとの間に強力な暗号学的リンクがあるTxIDとは違い、TxRefは特定のトランザクションへの弱いリンクを提供するだけだ。TexRefはトランザクションブロックチェーン内でのオフセットを指すが、これは実際のトランザクションを指している場合と指していない場合がある(実際のトランザクションは再編成によって変わることがある)。TxRefは、成熟度が100ブロック未満のブロックチェーン内の位置には使用しないことを推奨する。

動機

Bitcoinの初期バージョン以降、TxID(トランザクション識別子)はコンセンサスプロトコルのコア部分であり、ユーザー間で個々のトランザクションを識別するために日常的に使われてきた。

しかし、多くのユースケースにおいて、実用上の制限がある。

  • TxIDは、フルノードが検索するのには高価である(ブロックチェーンのリニアなスキャンか、高価なTxIDのインデックスを必要とする)。
  • TxIDは、SPVウォレットが検索するにはサードパーティのサービスを必要とする。
  • TxIDは非常に長いHEXエンコード値(64文字)である。

ブロックチェーンに埋め込まれているトランザクションの場合、そのTxIDではなく、ブロックチェーン自体の中のそのトランザクションの位置により参照することが可能だ。また人が転記しやすいようにエンコードできる。この文書ではこのための標準を提案する。

サンプル

以下はBitcoinトランザクションのサンプル。

仕様

承認済みトランザクションの位置参照、つまりTxRefはブロックの高さとブロック内のトランザクションのインデックスおよびオプションでトランザクション内のOutPointのインデックスによって指定される、ブロックチェーン内の特定の場所への参照だ。

注意:この仕様の全ての値はリトルエンディアン形式でエンコードされている。

TxRef

以下の理由によりTxRefは存在しない場所を参照している可能性がある:

したがって、実装者はTxRefを早い段階でユーザーに表示しないよう注意する必要がある:

エンコーディング

TxRefはBIP-173で定義されている標準のBech32エンコーディングを使用しているため、以下で構成される。

  • Human-readable、つまりHRPの部分は、namespaceを提供する。MainnetとTestnetを区別するための以下のように定義する。
    • Mainnetの場合は:tx
    • Testnetの場合は:txtest
    • これら2つと他のプロジェクトに関連するものを含む完全なHRPのリストについては、SLIP-0173を参照。
  • セパレータ: 1
  • データパート

注意:分散IDの仕様など他の仕様では、HRP内の他の場所に含まれる情報が暗黙的にエンコードされている。この場合、ここで指定されているようなHRPを含まないことを選択するかもしれない。

移植性と可読性を高めるため、セパレータを追加する必要がある。

  • 1の後にコロンを追加する。
  • コロンの後、4文字毎にハイフン(-)を追加する。

bech32のコードセパレータの後にある非bech32アルファベット文字は、パースの際に無視/削除しなければない(終端文字を除く)。

TxRefのテキストエンコーディングは、

Bit Character Characters Value
Human-readable部分 1-2 2 BitcoinのMainnetはtx、Testnetはtxtest
セパレータ 3 1 1
コロン 4 1 :
データ 0-19 5-8 4
ハイフン 9 1 -

データ - ハイフンパターンは、データ全体の長さに渡って繰り返される(ハイフンがエンコードされた20bitまたは4データ文字毎に挿入される)。

データ

オプションのトランザクションのOutPointが含まれるかどうかで、上記文字列にエンコードされた75ビットもしくは90ビットのデータになる。これらのbitは次のように定義されている。

Bitcoin MainnetとTestnetのTxRefバイナリフォーマット

Bit Bit(s) Type values Notes
マジックコード 0-4 5 チェーンのネームスペースコード Bitcoinの場合は0x03、OutPointを含むMainnetの場合は0x04。Testnetが0x06でOutPointを含むTestnetが0x07
バージョン 5 1 将来のための確保 必ず0x0
ブロック高 6-29 24 Txのブロック高 ブロック0(ジェネシス)〜ブロック16777215 2328年まで
トランザクションインデックス 30-44 15 ブロック内のTxインデックス Tx0(コインベース)〜32767番目のTxまで ブロック内の最大Txが16665個

マジックコードが0x040x07の場合、オプションのOutPointがエンコーディングに含まれる。

Bit Bit(s) Type values Notes
OutPoint インデックス 45-59 15 Tx内のOutPointのインデックス OutPoint 0〜32767番目のOutPointまで

最後に30bitのチェックサムを含める。

Bit Bit(s) Type values Notes
チェックサム 45-74 or 60 - 89 30 Bech32チェックサム

マジックに関して

マジックコードはチェーン間のnamespaceを提供する。BitcoinのMainnetとTestnetには5bitのマジックコードが使われている(他のプロジェクトやチェーンではかなり長くなるかもしれない):

  • Bitcoin Mainnetの場合、マジックコードは0x3で、エンコードすると文字rになる。
  • OutPointを含むBitcoin Mainnetの場合マジックコードは0x4で、エンコードすると文字yになる。
  • Bitcoin Testnetの場合、マジックコードは0x6で、エンコードすると文字xになる。
  • OutPointを含むBitcoin Testnetの場合マジックコードは0x7で、エンコードすると文字8になる。

コード0x00x10x20x5Bitcoinの将来のプロジェクト用に予約されている。

他のチェーンは0x0から0x7までで始まるマジックコードとして使ってはならない。

他のチェーンのマジックコードはSLIP-XXXX "TxRef for Non-Bitcoin Chains and Networks"で指定される。

互換性

互換性に関する既知の課題はない。

論拠

  1. 承認済みトランザクションの参照になぜBech32エンコーディングを使用するのか?
    Bech32エンコーディングフォーマットの誤り検出および訂正特性は魅力的だ。ソフトウェアが最大2文字の修正するのが妥当だと期待しているが、まだこれを指定していない。
  2. どうしてコロンを追加したのか?
    これによりW3CのURN/URL標準への準拠性が向上する。
  3. TxRef内にハイフンがあるのはなぜ?
    TxRefは短いので、音声で引用するか手で書くことを予想している。4文字毎にハイフンを入れると文字列が分割され、人が場所を簡単に見失わないようになる。
  4. 非bech32アルファベット文字列を削除するのはなぜ?
    ユーザーは自分のTxRefを良いUnicode形式にしておきたいと望むことはないと思っている。コピーやペースト、手書きを組み合わせて書くと予想する。パーサーはこれらによる一般的なエラーを全て自動的に修正すべきだ。

参照実装

Appendix

Test Vector

以下を含む2つのTest Vectorをセットがある。

  • Bech32エンコードされたTest Vector。実装が正しいHuman-readableパートとセパレーターを含む円k−土を受け入れるかどうかテストするのに使用する。
  • Bitcoin TxRef Test Vector。完全な仕様、特にブロック高およびトランザクションインデックスの正しい値かどうかテストするのに使用する。
TxRef用のBech32エンコーディング

注意:すべてのTest Vectorは文字列が準拠しているかどうかをテストするのに役立つ。すべての実際のアプリケーション(Bitcoin向けの)は、書きのBitcoinのTest Vectorに準拠している必要がある。

以下の文字列は有効なHuman Readable PartとBech32チェックサムを持つ。

  • TX1A12UEL5L
  • tx1an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs
  • tx1abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw
  • tx11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j

以下のリストは無効なTxRefとその理由を示している。

  • bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty: Human-Readable Partが無効
  • tx1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5チェックサムが無効
Bitcoin TxRef(mainnetおよびtestnet)

以下のリストは正しくエンコードされたBitcoin mainnetのTxRefとhex値(ブロック高およびトランザクションインデックス)。

  • tx1:rqqq-qqqq-qmhu-qhp: (0x0, 0x0)
  • tx1:rqqq-qqll-l8xh-jkg: (0x0, 0x7FFF)
  • tx1:r7ll-llqq-qghq-qr8: (0xFFFFFF, 0x0)
  • tx1:r7ll-llll-l5xt-jzw: (0xFFFFFF, 0x7FFF)

以下のリストは正しくエンコードされたBitcoin testnetのTxRefとhex値(ブロック高およびトランザクションインデックス)。

  • txtest1:xqqq-qqqq-qkla-64l: (0x0, 0x0)
  • txtest1:xqqq-qqll-l2wk-g5k: (0x0, 0x7FFF)
  • txtest1:x7ll-llqq-q9lp-6pe: (0xFFFFFF, 0x0)
  • txtest1:x7ll-llll-lew2-gqs: (0xFFFFFF, 0x7FFF)

以下のリストは(奇妙フォーマットされているが)有効なBitcoin TxRefとhex値(ブロック高およびトランザクションインデックス)。

  • tx1:rjk0-uqay-zsrw-hqe: (0x71F69, 0x89D)
  • TX1RJK0UQAYZSRWHQE: (0x71F69, 0x89D)
  • TX1RJK0--UQaYZSRw----HQE: (0x71F69, 0x89D)
  • tx1 rjk0 uqay zsrw hqe: (0x71F69, 0x89D)
  • tx1!rjk0\uqay*zsrw^^hqe: (0x71F69, 0x89D)

以下のリストは無効なTxRefとその理由。

  • tx1:t7ll-llll-ldup-3hh: 0x3の代わりにマジックが0xBになっている。(0xFFFFFF, 0x7FFF)
  • tx1:rlll-llll-lfet-r2y: バージョンが0でなく1になっている。(0xFFFFFF, 0x7FFF)
  • tx1:rjk0-u5ng-gghq-fkg7: 有効なBech32だが、8ではなく10x5 bitのパッケージになっている。
  • tx1:rjk0-u5qd-s43z: 有効なBech32だが、8ではなく6x5bitのパッケージになっている。
OutPointを含むBitcoin TxRef(mainnetおよびtestnet)

以下のリストは正しくエンコードされたOutPointを含むBitcoin mainnetのTxRefとhex値(ブロック高およびトランザクションインデックス、TXOインデックス)。

  • tx1:yqqq-qqqq-qqqq-ksvh-26: (0x0, 0x0, 0x0)
  • tx1:yqqq-qqll-lqqq-v0h2-2k: (0x0, 0x7FFF, 0x0)
  • tx1:y7ll-llqq-qqqq-a5zy-tc: (0xFFFFFF, 0x0, 0x0)
  • tx1:y7ll-llll-lqqq-8tee-t5: (0xFFFFFF, 0x7FFF, 0x0)
  • tx1:yqqq-qqqq-qpqq-5j9q-nz: (0x0, 0x0, 0x1)
  • tx1:yqqq-qqll-lpqq-wd7a-nw: (0x0, 0x7FFF, 0x1)
  • tx1:y7ll-llqq-qpqq-lktn-jq: (0xFFFFFF, 0x0, 0x1)
  • tx1:y7ll-llll-lpqq-9fsw-jv: (0xFFFFFF, 0x7FFF, 0x1)
  • tx1:yjk0-uqay-zrfq-g2cg-t8: (0x71F69, 0x89D, 0x123)
  • tx1:yjk0-uqay-zu4x-nk6u-pc: (0x71F69, 0x89D, 0x1ABC)

以下のリストは正しくエンコードされたOutPointを含むBitcoin testnetのTxRefとhex値(ブロック高およびトランザクションインデックス、TXOインデックス)。

  • txtest1:8qqq-qqqq-qqqq-cgru-fa: (0x0, 0x0, 0x0)
  • txtest1:8qqq-qqll-lqqq-zhcp-f3: (0x0, 0x7FFF, 0x0)
  • txtest1:87ll-llqq-qqqq-nvd0-gl: (0xFFFFFF, 0x0, 0x0)
  • txtest1:87ll-llll-lqqq-fnkj-gn: (0xFFFFFF, 0x7FFF, 0x0)
  • txtest1:8qqq-qqqq-qpqq-622t-s9: (0x0, 0x0, 0x1)
  • txtest1:8qqq-qqll-lpqq-q43k-sf: (0x0, 0x7FFF, 0x1)
  • txtest1:87ll-llqq-qpqq-3wyc-38: (0xFFFFFF, 0x0, 0x1)
  • txtest1:87ll-llll-lpqq-t3l9-3t: (0xFFFFFF, 0x7FFF, 0x1)
  • txtest1:8jk0-uqay-zrfq-xjhr-gq: (0x71F69, 0x89D, 0x123)
  • txtest1:8jk0-uqay-zu4x-aw4h-zl: (0x71F69, 0x89D, 0x1ABC)

Bitcoin TxRef ペイロード値の選択

ブロック高とトランザクションインデックスの特定のビット長を選択した理由を示すいくつかの計算結果がある。

ブロック高の値:

0〜0xFFFFFF(16,777,216ブロック)の間の24 bit。

  • 毎年52500ブロック増え、アドレス可能なブロックは319年分である。
  • しtがって、2328年より前にこの仕様は拡張されるべきだ(我々には十分な時間がある)。
トランザクションの位置の値:

0x0から0x7FFF(32,768トランザクション)の15 bit。

  • 現実的な最小のトランザクションは83バイトで、1ブロック内で最大トランザクション数は12047。
    • 4B version + 1B tx_in count + 36B previous_output + 1B script length + 0B signature script + 4B sequence + 1B tx_out count + 8B amount + 1B script length + 23B pubkey script + 4B lock_time = 83B
  • 極端に最小のトランザクションは60バイトで、1ブロック内の最大トランザクション数は16665。
    • 4B version + 1B tx_in count + 36B previous_output + 1B script length + 0B signature script + 4B sequence + 1B tx_out count + 8B amount + 1B script length + 0B pubkey script + 4B lock_time = 60B