ビットコイン・インスティテュート

ビットコインの​ストレージ設計 — ブロック​データベース、​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)

合計約 774 GB

(2026年10月)

undo ファイル

(rev00000.dat … rev0NNNN.dat)

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

coins データベース

(LevelDB)

ディスク上の UTXO セット

ブロックインデックス

(LevelDB)

hash → ファイル位置

coins キャッシュ

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

既定約 450 MiB

メモリープール

(未承認

トランザクション)

既定 300 MB 上限

チェーン状態メタデータ

(最良先端、

ブロックツリー、

nChainWork)

ネットワーク層

(新ブロック + tx)

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

2. ブロックファイル

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

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

blk00042.dat (≤ 128 MiB)

マジックバイト

(4 バイト)

ブロックサイズ

(4 バイト)

直列化済み

ブロック A

マジック

バイト

ブロック

サイズ

直列化済み

ブロック B

マジック

バイト

ブロック

サイズ

直列化済み

ブロック C

...

ファイル内の各ブロックエントリーは、4バイトのネットワークマジックナンバー(メインネット・テストネット等、ネットワークを識別する)で始まり、4バイトのリトルエンディアンサイズフィールドが続き、その後に完全なシリアライズされたブロック(ヘッダー + トランザクション + 証人データ)が格納される。v0.1の直列化境界を扱う分析は、このマジックナンバーとサイズによる枠組みを元のソースのCBlock::WriteToDiskまで遡っている。この枠組みは以来変わっていないが、Bitcoin Core 28.0からは、ブロックのディレクトリに置いた鍵で、ファイルがディスク上で既定でXORされる。

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

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

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

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

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

UTXOセットはBitcoin Coreで最もパフォーマンスが重要なデータ構造である。すべてのトランザクション検証において、参照された入力が存在し未使用であるかの検索が必要となる。コインデータベースはchainstate/ サブディレクトリにある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)
検証状態ブロックが完全に検証済みか、ヘッダーのみ検証済みか、無効としてマークされているか

ブロック取得パス

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

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

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

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

ネットワークまたはウォレットから到着したトランザクションは、まずポリシー検査と合意検証を通過してからメモリープールに受理される。どちらかの検査に失敗すれば、受理される前に破棄される。

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

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

6. 剪定

フルアーカイブノードはこれまでに生成されたすべてのブロックを保存しており、2026年10月に約774 GBで、その前の2年はそれぞれ約80 GBずつ増えた。剪定により、ノードは古いブロックファイルと取り消しファイルを破棄しつつ、完全なUTXOセットと新規ブロック検証能力を保持できる。

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

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

7. assumeUTXO

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

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

信頼モデル

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

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

8. 二つの時代の比較

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

BDB → LevelDB移行(v0.8、2013年3月)。サトシのオリジナル実装は、トランザクションインデックスとUTXO状態を単一のBerkeley DBデータベースに保存していた。ただし生のブロックデータはその対象になく、当初からフラットファイル(blk*.dat)に置かれていた。この選択について、サトシは2009年1月に初期ユーザーへ直接説明していた。「トランザクション対応のデータベースDBMに保存されているから、クラッシュや停電が起きても失われないはずだ」と。チェーンの成長に伴い、BDBのロック制限とメモリー特性がボトルネックとなった。v0.8リリースはUTXOセットとブロックインデックスのBDBをLevelDBに置き換えた。ブロックデータはv0.1以来使われてきたフラットファイル形式のままだった。

この移行は事件を伴った: 2013年3月11日、v0.7(BDB)を実行するノードとv0.8(LevelDB)を実行するノードが、LevelDBにはないBDBのロックカウント制限に起因してブロックの有効性について不一致となり、合意形成の分裂フォークが発生した。フォークはマイナーの協調行動により、長いv0.8チェーンを放棄する形で解決された。

9. 本ページの範囲

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

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

参照元の外部ソース

https://bitcoin.org/bitcoin.pdf

その他の外部ソース