提案は結構前からあったみたいだけど先月マージされた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ではなく、ブロックチェーン自体の中のそのトランザクションの位置により参照することが可能だ。また人が転記しやすいようにエンコードできる。この文書ではこのための標準を提案する。
サンプル
- ジェネシスコインベーストランザクション (0番目のブロックの0番目のトランザクション):
tx1:rqqq-qqqq-qmhu-qhp
- 466793番目のブロックの2205番目のトランザクション:
tx1:rjk0-uqay-zsrw-hqe
仕様
承認済みトランザクションの位置参照、つまりTxRefはブロックの高さとブロック内のトランザクションのインデックスおよびオプションでトランザクション内のOutPointのインデックスによって指定される、ブロックチェーン内の特定の場所への参照だ。
注意:この仕様の全ての値はリトルエンディアン形式でエンコードされている。
TxRef
以下の理由によりTxRefは存在しない場所を参照している可能性がある:
- 指定されたブロックがまだマイニングされていない。
- トランザクションインデックスが、指定されたブロックに含まれているトランザクションの総数を超えている。
- オプションのOutPointのインデックスがトランザクションに含まれているOutPointの総数を超えている。
したがって、実装者は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個 |
マジックコードが0x04、0x07の場合、オプションの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になる。
コード0x0、0x1、0x2、0x5はBitcoinの将来のプロジェクト用に予約されている。
他のチェーンは0x0から0x7までで始まるマジックコードとして使ってはならない。
他のチェーンのマジックコードはSLIP-XXXX "TxRef for Non-Bitcoin Chains and Networks"で指定される。
互換性
互換性に関する既知の課題はない。
論拠
- 承認済みトランザクションの参照になぜBech32エンコーディングを使用するのか?
Bech32エンコーディングフォーマットの誤り検出および訂正特性は魅力的だ。ソフトウェアが最大2文字の修正するのが妥当だと期待しているが、まだこれを指定していない。 - どうしてコロンを追加したのか?
これによりW3CのURN/URL標準への準拠性が向上する。 - TxRef内にハイフンがあるのはなぜ?
TxRefは短いので、音声で引用するか手で書くことを予想している。4文字毎にハイフンを入れると文字列が分割され、人が場所を簡単に見失わないようになる。 - 非bech32アルファベット文字列を削除するのはなぜ?
ユーザーは自分のTxRefを良いUnicode形式にしておきたいと望むことはないと思っている。コピーやペースト、手書きを組み合わせて書くと予想する。パーサーはこれらによる一般的なエラーを全て自動的に修正すべきだ。
参照実装
- Cの参照実装(マジックコード0x3と0x6をサポート): https://github.com/jonasschnelli/bitcoin_txref_code
- Goの参照実装(マジックコード0x3と0x6をサポート): https://github.com/kulpreet/txref
- C++の参照実装(マジックコード0x3と0x4、0x6, 0x7をサポート): https://github.com/dcdpr/btcr-DID-method/
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