ビットコインのストレージ設計 — ブロックデータベース、UTXO セット、チェーン状態管理

はじめに

本ページは設計文書シリーズL1 #7 — ストレージ設計 である。ストレージ層を扱う: Bitcoin Core ノードが検証済みデータをディスクにどう永続化するか、使用可能なコインをメモリーとディスク上でどう追跡するか、状態をどう復旧またはブートストラップするか。

トランザクション設計ページでは UTXO とは何かを説明した。ブロックとチェーン設計ページではブロックがチェーンにどう連結されるかを説明した。本ページは一段階下に移る: これらの抽象概念を耐久的かつ検索可能にするディスク上およびメモリー内の構造。

4 つの問いが内容を構成する:

  1. ブロックはどこに保存されるか? ディスク上のフラットファイル(blk*.dat)に保存され、再編成を可能にする付随の取り消しファイル(rev*.dat)を伴う。
  2. UTXO セットはどこにあるか? LevelDB データベース(コインデータベース)に置かれ、パフォーマンスのためにメモリー内にライトバックキャッシュを持つ。
  3. ノードはブロックをどう素早く見つけるか? ブロックハッシュをファイル位置にマッピングする LevelDB ブロックインデックスを通じて。
  4. ノードはすべてを永久に保存することをどう回避するか? 剪定(古いブロックファイルの破棄)と assumeUTXO(信頼された UTXO スナップショットからのブートストラップ)によって。

サトシ時代の実装(v0.1、2009 年 1 月)と現代の Bitcoin Core(v27 以降を基準)で挙動が異なる箇所は、双方を記載する。

1. ストレージアーキテクチャの概要

以下の図はフルノード内部のすべての永続データストアとそれらの間のデータフローを示す。

受信データ

メモリー上状態

ディスク上ストレージ

新ブロック

新ブロック

新 tx

接続時の

undo データ

検証済みブロックが

UTXO セットを更新

定期フラッシュ

ブロック接続時に

承認済み tx を削除

検索

最良先端を追跡

ブロックファイル

(blk00000.dat … blk0NNNN.dat)

合計約 650 GB 以上

undo ファイル

(rev00000.dat … rev0NNNN.dat)

ブロックファイル 1 つに 1 つ

coins データベース

(LevelDB)

ディスク上の UTXO セット

ブロックインデックス

(LevelDB)

hash → ファイル位置

coins キャッシュ

(UTXO ライトバックキャッシュ)

既定約 450 MiB

メモリープール

(未承認

トランザクション)

既定 300 MB 上限

チェーン状態メタデータ

(最良先端、

ブロックツリー、

nChainWork)

ネットワーク層

(新ブロック + tx)

ストアエンジン内容おおよそのサイズ(2025 年)
ブロックファイルフラットバイナリーファイル生のシリアライズされたブロック、追記専用約 650 GB
取り消しファイルフラットバイナリーファイル各使用済み入力の以前のコイン状態(ブロックファイルごとに 1 つ)約 100 GB
コインデータベースLevelDBすべての未使用トランザクション出力(UTXO セット)約 7 GB
ブロックインデックスLevelDBブロックヘッダーメタデータとファイル位置ポインター約 500 MB
コインキャッシュメモリー内ハッシュマップコインデータベースのライトバックキャッシュ設定可能(既定約 450 MiB、-dbcache で指定)
メモリープールメモリー内データ構造ブロック掲載を待つ未承認トランザクション設定可能(既定 300 MB、-maxmempool で指定)

2. ブロックファイル

検証済みブロックは、データディレクトリの blocks/ サブディレクトリに保存される blk00000.datblk00001.dat 等の名前の一連のフラットバイナリーファイルに順次書き込まれる。各ファイルは新しいファイルが開かれるまでにおよそ 128 MiB までの生のブロックデータを保持する。

ブロックファイルのレイアウト

blk00042.dat (≤ 128 MiB)

マジックバイト

(4 バイト)

ブロックサイズ

(4 バイト)

直列化済み

ブロック A

マジック

バイト

ブロック

サイズ

直列化済み

ブロック B

マジック

バイト

ブロック

サイズ

直列化済み

ブロック C

...

ファイル内の各ブロックエントリーは、4 バイトのネットワークマジックナンバー(ネットワーク — メインネット、テストネット等 — を識別する)で始まり、4 バイトのリトルエンディアンサイズフィールドが続き、その後に完全なシリアライズされたブロック(ヘッダー + トランザクション + 証人データ)が格納される。

取り消しファイル (rev*.dat)

各ブロックファイル blk0NNNN.dat に対して、対応する rev0NNNN.dat が存在する。取り消しファイルは、対応するブロック内のすべてのトランザクションが消費したすべての UTXO の以前の状態を保存する。このデータはチェーン再編成時のブロックの切断に不可欠である: ノードは使用された UTXO を復元し、作成された UTXO を除去しなければならない。

ファイルペア目的
blk0NNNN.dat順方向データ: 受信・検証された生のブロック
rev0NNNN.dat逆方向データ: ブロックの UTXO セットへの影響を取り消すために必要なコイン状態

取り消しデータがなければ、再編成にはジェネシスブロックからチェーン全体を再検証する必要がある — 現代のハードウェアでも数時間を要する操作である。

3. UTXO セット(コインデータベース)

UTXO セットは Bitcoin Core で最もパフォーマンスが重要なデータ構造である。すべてのトランザクション検証において、参照された入力が存在し未使用であるかの検索が必要となる。コインデータベースは chainstate/ サブディレクトリにある LevelDB キーバリューストアにすべての未使用トランザクション出力を格納する。

UTXO 検索フロー

ヒット

ミス

あり

なし

受信トランザクションが

入力を参照

(txid + 出力インデックス)

coins

キャッシュにあり?

UTXO をメモリーで検出

(高速パス)

coins データベースに

問い合わせ

(ディスク上 LevelDB)

キャッシュに読込み、

UTXO を返す

入力が存在しない:

トランザクション無効

キーバリュー構造

コインデータベースの各エントリーはアウトポイント(トランザクションハッシュ + 出力インデックス)をキーとし、コインのサトシ単位の額面、作成されたブロック高、コインベース出力かどうか、出力のロックスクリプトを保存する。

コインキャッシュ

トランザクション入力ごとにディスク上の LevelDB から読み取るのでは遅すぎる。Bitcoin Core は読み取りを吸収し書き込みをバッチ処理するメモリー内ライトバックキャッシュ(コインキャッシュ)を維持する。ブロックが接続されると、使用済みコインはキャッシュ内で消費済みとマークされ、新しいコインが追加される。定期的に — またはキャッシュがサイズ上限に達した時に — 蓄積された変更がディスク上の LevelDB に単一のバッチ書き込みでフラッシュされる。

パラメーター既定値効果
-dbcache450 MiBメモリー内コインキャッシュのサイズ。値が大きいほど初期ブロックダウンロード時のディスク I/O が減少する。
フラッシュ契機キャッシュ満杯またはシャットダウンダーティエントリーが LevelDB にバッチ書き込みされる。

初期ブロックダウンロード(IBD)のパフォーマンス。 IBD 中、ノードは数十万のブロックを連続して高速に処理する。-dbcache を大きく設定する(例: 4096 MiB 以上)と、UTXO セットのより多くの部分がメモリーに保持され、ディスク読み取りとバッチ書き込み頻度が最小化されるため、IBD 時間が劇的に短縮される。

4. ブロックインデックス

ブロックインデックスは blocks/index/ に保存される独立した LevelDB データベースで、ノードがこれまでに受信したすべてのブロックヘッダー — 古くなったブランチのものも含む — のカタログとして機能する。各ブロックハッシュに対して、インデックスは以下を保存する:

フィールド目的
ブロックヘッダーフィールドバージョン、前ブロックハッシュ、マークルルート、タイムスタンプ、nBits、ナンス
ファイル位置どの blk*.dat ファイルにこのブロックが格納されているか、どのバイトオフセットか
ブロック高チェーン内の位置
チェーン仕事量このブロックまでの累積プルーフ・オブ・ワーク(nChainWork
検証状態ブロックが完全に検証済みか、ヘッダーのみ検証済みか、無効としてマークされているか

ブロック取得パス

ブロックハッシュ

ブロックインデックス

(LevelDB)

ファイル: blk00042.dat

オフセット: 0x1A3F00

フラットファイルの

オフセットから

ブロックを読込み

デシリアライズ済み

ブロック

ブロックインデックスにより、ノードはフラットファイルを走査することなくハッシュで任意のブロックを特定できる。また、チェーン選択に必要なデータも提供する: ノードはディスクからフルブロックを読み込まずに、ブランチ先端間で nChainWork 値を比較して最も仕事量の多いチェーンを判定できる。

5. メモリープールストレージ

メモリープールは、検証とポリシーチェックに合格したがまだブロックに掲載されていない未承認トランザクションのメモリー内プールである。合意形成データベースには永続化されない — 各ノードが独立に維持するローカルで一時的な構造である。

メモリープールのライフサイクル

トランザクションが

ネットワークまたは

ウォレットから到着

ポリシー検査と

合意検証を通過

メモリープールに受理

検証済みブロックに

含まれる

メモリープール満杯、

最低手数料率を除外

最大保持時間超過

(既定 2 週間)

メモリープールから削除

より高い手数料率による

置換 (RBF)

Received

Validated

InMempool

Confirmed

Evicted

Expired

Replaced

特性値(v27 以降基準)
最大サイズ300 MB(-maxmempool で設定可能)
除去ポリシープールが容量に達すると最低手数料率のトランザクションから除去
期限切れ336 時間(約 2 週間)を超えたトランザクションを除去
永続化正常シャットダウン時に mempool.dat に保存; 次回起動時に読み込み
手数料置換完全 RBF が既定のメモリープールポリシー(v28.0 以降)

メモリープールと合意形成。 メモリープールはポリシーレベルの構造であり、合意形成レベルのものではない。2 つのノードが全く異なるメモリープールを持っていても、どのブロックが有効かについては合意できる。トランザクションがメモリープールに存在することはブロックへの掲載を保証しない — ローカルノードがそれを有効と見なし、中継する意思があることを意味するだけである。

6. 剪定

フルアーカイブノードはこれまでに生成されたすべてのブロックを保存する — 2025 年時点で 650 GB 超、年間約 50〜80 GB ずつ増加する。剪定により、ノードは古いブロックファイルと取り消しファイルを破棄しつつ、完全な UTXO セットと新規ブロック検証能力を保持できる。

剪定が保持するものと破棄するもの

剪定済みノードが破棄

剪定済みノードが保持

新ブロックは

引き続き検証可能

ピアに過去ブロックを

提供できない

完全な UTXO セット

(coins データベース)

完全な

ブロックインデックス

(全ヘッダー)

最近のブロックファイル

(設定可能な保持窓)

古いブロックファイル

(保持窓を超える

blk*.dat)

対応する undo ファイル

(rev*.dat)

完全な合意検証能力

完全アーカイブ

ピアとしては

機能しない

側面アーカイブノード剪定ノード
ブロックデータジェネシスからチップまでの全ブロック最新の N MiB のみ(最小 550 MiB)
UTXO セット完全完全(アーカイブと同一)
ブロックインデックス完全(全ヘッダー)完全(全ヘッダー)
新規ブロック検証完全完全(アーカイブと同一)
過去のブロック提供可能 — ピアに任意のブロックを提供可不可 — 保持ウィンドウ内のブロックのみ提供可
ディスク使用量(2025 年)約 650 GB 超最小約 10 GB

要点。 剪定ノードはフル検証ノードである。アーカイブノードとまったく同じように、すべての新規ブロックにすべての合意規則を適用する。唯一失われる能力は、初期ブロックダウンロードを行うピアに古いブロックを提供することである。剪定は -prune=<MiB>(最小 550)で設定する。

7. assumeUTXO

初期ブロックダウンロード(IBD)— ジェネシスブロックから現在のチップまですべてのブロックを検証すること — は、ハードウェアとネットワーク速度に応じて数時間から 1 日以上かかる。assumeUTXOloadtxoutset RPC は v26.0 で導入; メインネットのスナップショットパラメーター(高さ 840,000)は v28.0 で追加)は代替のブートストラップパスを提供する: ノードは事前計算された UTXO スナップショットを読み込み、スナップショット高から即座に新規ブロックの検証を開始し、バックグラウンドで完全な過去のチェーンを検証する。

assumeUTXO のブートストラッププロセス

バックグラウンド検証スナップショットノードユーザーバックグラウンド検証スナップショットノードユーザーノードは稼働状態 —新ブロック検証およびトランザクション中継が可能バックグラウンド IBD がスナップショット高に到達:スナップショットファイルを指定してノード起動UTXO スナップショットを読込みスナップショットハッシュがハードコード assumeUTXO ハッシュに一致するか確認スナップショットを稼働中 UTXO セットとして有効化ジェネシスから完全 IBD 開始(バックグラウンド)全過去ブロックを検証ジェネシスから独立したUTXO セットを構築バックグラウンド UTXO セットとスナップショット UTXO セットを比較ハッシュ一致 → スナップショット検証済み単一のチェーン状態に統合

信頼モデル

フェーズ検証レベル信頼の前提
スナップショット読み込み済み、バックグラウンド IBD 未完了新規ブロックはスナップショット UTXO セットに対して完全に検証されるノードはハードコードされたスナップショットハッシュ(Bitcoin Core 開発者がバイナリーにコンパイルしたもの)を信頼する。スナップショットが悪意あるものであった場合、バックグラウンド検証が不一致を検出するまで、ノードは無効なトランザクションを受け入れる可能性がある。
バックグラウンド IBD 完了、ハッシュ一致ジェネシスからチップまですべてのブロックの完全な検証追加の信頼なし — ノードはチェーン履歴全体を独立に検証しており、従来の IBD ノードと同一。

assumeUTXO は合意規則を変更しない。検証が行われる順序を変更する: 新規ブロックが最初(即座に有用)、過去のブロックが二番目(バックグラウンド検証)。最終状態は従来の IBD を実行したノードと同一である。

8. 二つの時代の比較

機能サトシ時代(v0.1、2009 年 1 月)現代の Bitcoin Core、v27 以降基準
主要データベースBerkeley DB (BDB) がすべての永続的状態を管理UTXO セットとブロックインデックスに LevelDB; ブロックにフラットファイル
UTXO ストレージトランザクション全体を BDB に保存; すべての出力(使用済み・未使用)を保持未使用出力のみを LevelDB に保存; 使用済み出力は破棄
UTXO 表現トランザクションインデックス型: 出力ごとの使用済みフラグベクトル付きフルトランザクションアウトポイントインデックス型: 各 UTXO を (txid, 出力インデックス) でキーとしコンパクトにシリアライズ
コインキャッシュ独立したキャッシュ層なし; BDB がすべての読み書きを処理専用のメモリー内ライトバックキャッシュ(-dbcache、既定 450 MiB)
ブロックストレージ単一の一体型 BDB データベース連続的なフラットファイル(blk*.dat)、各約 128 MiB
取り消しデータ保存なし; 再編成にはフォークポイントからの再検証が必要専用の rev*.dat ファイルが高速なロールバックのための以前のコイン状態を保存
ブロックインデックスBDB ベースのインデックスnChainWork 追跡付き LevelDB ベースのインデックス
剪定利用不可; すべてのノードがフルチェーンを保存v0.11(2015 年)以降利用可能; 最小保持量 550 MiB
assumeUTXO利用不可バックグラウンド検証付きスナップショットベースのブートストラップ(v26 で導入; メインネットパラメーターは v28)
メモリープールの永続化再起動時に永続化しないシャットダウン時に mempool.dat に保存; 起動時に再読み込み
データベース移行該当なしv0.8(2013 年)で BDB → LevelDB 移行; Bitcoin Core のストレージ層における最大の変更
初期ブロックダウンロード数分(ブロック数が少なかった)assumeUTXO なしで数時間〜1 日超; assumeUTXO スナップショット使用で数分
ディスク上のサイズ無視できる程度(チェーンが小さかった)アーカイブで約 650 GB 超; 剪定で約 10 GB; コインデータベースで約 7 GB

BDB → LevelDB 移行(v0.8、2013 年 3 月)。 サトシのオリジナル実装はすべて — ブロックデータ、トランザクションインデックス、UTXO 状態 — を単一の Berkeley DB データベースに保存していた。チェーンの成長に伴い、BDB のロック制限とメモリー特性がボトルネックとなった。v0.8 リリースは UTXO セットとブロックインデックスの BDB を LevelDB に置き換え、ブロックデータを現在も使用されているフラットファイル形式に移した。この移行は事件を伴った: 2013 年 3 月 11 日、v0.7(BDB)を実行するノードと v0.8(LevelDB)を実行するノードが、LevelDB にはない BDB のロックカウント制限に起因してブロックの有効性について不一致となり、合意形成の分裂フォークが発生した。フォークはマイナーの協調行動により、長い v0.8 チェーンを放棄することで解決された — ビットコイン史上数少ない意図的なチェーン再編成の 1 つである。

9. 本ページの範囲

本ページはストレージ層を単独で扱う。以下のトピックは範囲外であり、設計文書シリーズ内のそれぞれの専門ページで扱う:

  • トランザクション構造と UTXO モデル — UTXO がどう作成、使用、検証されるか。トランザクション設計ページで扱う。
  • ブロック構造とチェーン選択 — ブロックがどう構成され、最も仕事量の多いチェーンがどう選択されるか。ブロックとチェーン設計ページで扱う。
  • 合意規則 — ブロックがストレージ層に到達する前に受け入れるかどうかを決定する検証規則。
  • ネットワーク層のブロックリレー — ブロックがディスクに書き込まれる前にノード間でどう伝送されるか。
  • ウォレットストレージ — 鍵導出、記述子データベース、ウォレットバックアップはここで記述した合意データとは別のストレージパスを使用する。