現状のBitcoinのUTXOセットについて、その内訳を調べてみた。
UTXOセットのダンプ
Bitcoin Coreを実行すると、chainstateディレクトリ以下のLevelDBのファイルにUTXOセットのデータが格納される。LevelDBは基本的に1つのプロセスしかDBファイルを開けないのと、LevelDBで操作するのも難儀なので、調査しやすいようにまずUTXOセットをファイルにダンプする。これは、Bitcoin Coreのdumptxoutset RPCを実行することでできる(2〜3分かかる)*1。
$ bitcoin-cli dumptxoutset <生成先のパス> { "coins_written": 146009905, "base_hash": "000000000000000000042303364e5e50144b3d77362842354fb7992af10a80af", "base_height": 821628, "path": "<生成先のパス>", "txoutset_hash": "647a5f9f0e6427b999d633e981674d0af1ed5eddd4b9f8f3a7f1c59eae08146c", "nchaintx": 937337142 }
レスポンスのJSONの各値は、
coins_written:スナップショットに書かれているコインの量base_hash:スナップショットのベースとなったブロックのハッシュbase_height:スナップショットのベースとなったブロックの高さpath:スナップショットファイルのパスtxoutset_hash:UTXOセットのコンテンツのハッシュnchaintx:ベースとなったブロックを含むチェーン内のトランザクション数
出力されたのは、mainnetのブロック821,628時点のUTXOのスナップショットで、約9.1GB。
UTXOセットのデータフォーマット
ダンプしたファイルは以下の形式のデータで構成されている。
まず、先頭に
- 32バイトの
base_hash - 8バイトの
coins_written
が記録されていて、以降、UTXOの各エントリーが続く。このエントリーのデータ構造は↓
- 36バイトのOutPoint(32バイトのTXIDと4バイトのインデックス)
- UTXOが含まれるブロック高と、コインベースかどうかを示すフラグ
ブロック高を31 bitとして扱い、最下位ビットをコインベースのフラグ(コインベースであれば1、そうでなければ0)として扱った数値をvarintsエンコード - トランザクションアウトプット(TxOut)*2:
- value:UTXOが保持するsatsの量(形式はこちらのロジック参照、varintsエンコードされている)
- UTXOのscriptPubkey:
- P2PKHの場合は、プレフィックス0x00の後に20バイトの公開鍵のハッシュ値
- P2SHの場合は、プレフィックス0x01の後に20バイトのスクリプトのハッシュ値
- P2PKの場合は、公開鍵の値
(0x04で始まる)非圧縮公開鍵も33バイトの圧縮形式に変換されている。それが圧縮形式で表現されていることが分かるよう、プレフィックスを0x04 | y座標の偶奇ビットとしている。結果、P2PKの場合のプレフィックスは、0x02, 0x03, 0x04, 0x05のいずれかになる。 - それ以外のスクリプトタイプの場合は、スクリプトサイズ+6*3をvartintsエンコードした後にスクリプト全体が続く。
UTXOセットの内訳
ダンプファイルをパースしたタイプ別の内訳が↓

| タイプ | 個数 |
|---|---|
| P2PK | 45,537 |
| P2PKH | 50,789,846 |
| P2SH | 19,190,365 |
| P2WPKH | 47,532,135 |
| P2WSH | 1,325,019 |
| P2TR | 26,183,277 |
| Bare Multisig*4 | 934,122 |
| Other | 9,604 |
Ordinalsの影響だろうけど、2021年11月にアクティベートされたP2TRが結構多い(UTXOセットなので、インプットのwitnessにデータが格納されるInscriptionの画像系のデータはここには含まれない)。そして、現状のLNチャネルで使われるP2WSHは全体から見ればまだ少数(Simple Taproot Channelとかに移行すると、これもP2TRベースになる)。
ちなみに、UTXOにセットされているsatoshiの量が0のアウトプットのタイプ別の内訳は↓
| タイプ | 個数 |
|---|---|
| P2PK | 2 |
| P2PKH | 6,031 |
| P2SH | 68 |
| P2WPKH | 3 |
| Other | 8,846 |
Otherに分類されるUTXOの9割ちょっとが、0 sat UTXOになってるのが分かる。そして、その大半は、
OP_2 OP_3 <38バイトのデータ>
という形式のスクリプトになってる。これもデータの埋め込みに使われてるみたいだけど、OP_RETUNと違ってUTXOセットに残るのが難。ただこのスクリプトは、データがプッシュされているだけなので、マイナーであれば回収可能なUTXO。まぁ、0 satなので回収するメリットはないけど、その分の手数料収入放棄すれば、1ブロックで掃除できるボリュームではある。