ビットコインソースコードマップ
- 17 時間前
- 読了時間: 13分
前々からビットコインのコードを読めるようになりたい願望があったのでこの度Claude先生にソースコードを読み込んでもらってファイル・ディレクトリ・関数単位でモジュール単位でまとめてもらい、それぞれの機能が何をするためのものなのか、そしてコードの変更にはフォークが必要となる部分なのかをビットコインソースコードマップとして可視化してもらいました。
個別のファイルはC++が読めればClaude先生の解説を交えながらの拝読であればおそらく読めるのではないかと思うんですが、ディレクトリ構造全体の把握はいかんせんファイル数が多くて本業プログラマーではない私にとってはかなりハードルが高くどこから始めればいいのかわからなくて断念した過去があるので、Claude先生の性能が向上して嬉しい限りです。
以下、Claude先生にまとめてもらいフォーマットが崩れないように成形したソースコードマップです。

ビットコインソースコードマップ
src/直下(心臓部)— Bitcoin Core の動作の大半はここ
═════════════════════════════════════════
validation.cpp(約6,400行)— Core の中枢。全データがここを通る。
│
├── AcceptToMemoryPool() TX をメモリプールに入れるか審査
│ ├── 構文チェック → consensus/tx_check.cpp を呼ぶ 🔴 フォーク必要
│ ├── UTXO存在確認 → coins.h を呼ぶ 🔴 フォーク必要
│ ├── 手数料/RBF判定 → policy/ を呼ぶ 🟢 フォーク不要
│ ├── 標準性チェック → policy/policy.h を呼ぶ 🟢 フォーク不要
│ └── 署名検証 → script/interpreter.cpp を呼ぶ 🔴 フォーク必要
│
├── CheckBlock() ブロック単体の構文チェック 🔴 フォーク必要
│ ├── PoW検証 → pow.cpp を呼ぶ 🔴 フォーク必要
│ ├── マークルルート確認 → consensus/merkle.cpp を呼ぶ 🔴 フォーク必要
│ ├── ブロック weight 上限チェック 🔴 フォーク必要
│ └── vtx[0] が coinbase であること確認 🔴 フォーク必要
│
├── ConnectBlock() ブロックをチェーンに接続、UTXOを更新
│ ├── 全TXの署名検証 → script/interpreter.cpp を呼ぶ 🔴 フォーク必要
│ ├── 入力合計 ≥ 出力合計のチェック 🔴 フォーク必要
│ ├── coinbase 報酬上限チェック 🔴 フォーク必要
│ ├── UTXO消費/生成 → coins.h を呼ぶ 🔴 フォーク必要
│ └── undoデータ保存 → node/blockstorage.h を呼ぶ 🟢 フォーク不要
│
├── DisconnectBlock() リオーグ時にブロックを巻き戻す
│ ├── undoデータ読み込み → node/blockstorage.h を呼ぶ 🟢 フォーク不要
│ └── UTXO復元 → coins.h を呼ぶ 🔴 フォーク必要
│
├── ActivateBestChain() 累積PoW最大のチェーンに切り替える
│ ├── FindMostWorkChain() → chain.h の nChainWork で比較 🔴 フォーク必要
│ ├── DisconnectTip() → DisconnectBlock() を呼ぶ 🔴🟢 混合
│ └── ConnectTip() → ConnectBlock() を呼ぶ 🔴🟢 混合
│
└── ContextualCheckBlock() チェーン文脈でのブロック検証
├── coinbase に高さ埋め込み(BIP 34) 🔴 フォーク必要
├── witness commitment(BIP 141) 🔴 フォーク必要
└── nTime が MTP 以降か(BIP 113) 🔴 フォーク必要
─────────────────────────────────────────
net_processing.cpp(約6,200行)— P2Pメッセージの「読み手」
│
├── ProcessMessage() 受信メッセージを種類別に振り分ける(約25種類)
│ ├── "version"/"verack" → ハンドシェイク処理 🟢 フォーク不要
│ ├── "inv" → 相手が持つTX/ブロックの通知 🟢 フォーク不要
│ ├── "tx" → TX本体を受け取る 🟢 フォーク不要
│ ├── "cmpctblock" → Compact Block 復元 🟢 フォーク不要
│ ├── "block" → ブロック本体受け取り 🟢 フォーク不要
│ ├── "headers" → ヘッダ同期 🟢 フォーク不要
│ └── "addr"/"addrv2" → ピアアドレスの共有 🟢 フォーク不要
│
├── SendMessages() 定期的に送信キューを処理 🟢 フォーク不要
│ ├── inv をバッチ送信 🟢 フォーク不要
│ └── ping/pong で接続生存確認 🟢 フォーク不要
│
└── RelayTransaction() TX を他ノードに伝播 🟢 フォーク不要
※ データの「運び方」はコンセンサスではない
※ ただしメッセージ形式の互換性は他ノードとの通信に必要
─────────────────────────────────────────
net.cpp(約4,200行)— TCP接続の「配達員」 🟢 全体がフォーク不要
│
├── CConnman 接続マネージャ本体 🟢 フォーク不要
│ ├── Start() P2P接続を開始 🟢 フォーク不要
│ ├── Stop() 全接続を閉じる 🟢 フォーク不要
│ └── ピアごとにソケット管理、送受信バッファ 🟢 フォーク不要
│
├── CNode 1つのピア接続を表す 🟢 フォーク不要
│
└── V2Transport BIP 324 暗号化通信 🟢 フォーク不要
└── bip324.h ChaCha20-Poly1305 の暗号化/復号 🟢 フォーク不要
※ 接続管理はローカルの実装。コンセンサスに影響しない
─────────────────────────────────────────
txmempool.h(CTxMemPool)— 未確認TXの待合室
│
├── mapTx 複数インデックスで管理 🟢 フォーク不要
│ ├── txid で検索 🟢 フォーク不要
│ ├── ancestor fee rate でソート 🟢 フォーク不要
│ └── entry time でソート 🟢 フォーク不要
│
├── 祖先/子孫の追跡 🟢 フォーク不要
├── メモリプールサイズ上限 🟢 フォーク不要
├── 排除アルゴリズム 🟢 フォーク不要
│
└── validation.cpp の AcceptToMemoryPool() が審査して追加する
※ メモリプールは各ノードのローカル状態
※ 何を入れるか入れないかは各ノードの自由
─────────────────────────────────────────
coins.h — UTXO セット
│
├── Coin 1つのUTXO = CTxOut + 高さ + coinbaseフラグ
│ └── Coin のデータ内容 🔴 フォーク必要
│
└── 階層キャッシュ: CCoinsViewMemPool ← mempool内の未確認出力も見える 🟢 フォーク不要
│
▼
CCoinsViewCache ← メモリキャッシュ 🟢 フォーク不要
│ フラッシュのタイミング 🟢 フォーク不要
│ DIRTY/FRESH フラグ最適化 🟢 フォーク不要
▼
CCoinsViewDB ← LevelDB 🟢 フォーク不要
※ 最終的な UTXO 状態は全ノードで一致必須 → 🔴
※ そこに至る内部実装 → 🟢
─────────────────────────────────────────
chain.h — ブロックの「住所録」
│
├── CBlockIndex 1ブロックのメタデータ
│ ├── phashBlock ブロックハッシュ 🔴 フォーク必要
│ ├── pprev 前のブロックへのポインタ 🟢 フォーク不要
│ ├── nHeight 高さ 🔴 フォーク必要
│ ├── nFile/nDataPos blk*.dat 内の位置 🟢 フォーク不要
│ ├── nChainWork 累積PoW 🔴 フォーク必要
│ └── nStatus 検証状態 🟢 フォーク不要
│
└── CChain アクティブチェーン 🟢 フォーク不要
├── Tip() チェーン先端 🟢 フォーク不要
├── [nHeight] 高さでO(1)アクセス 🟢 フォーク不要
└── Genesis() ジェネシスブロック 🔴 フォーク必要
※ チェーン選択の「結果」は全ノードで一致必須
※ 選択に至る内部データ構造は自由
─────────────────────────────────────────
init.cpp(約2,400行)— 全モジュールの生成と破棄 🟢 全体がフォーク不要
│
├── 起動順序 🟢 フォーク不要
│ ① secp256k1 → ② スケジューラー → ③ RPC(warmup)
│ → ④ CConnman作成 → ⑤ CTxMemPool → ⑥ ChainstateManager
│ → ⑦ PeerManager → ⑧ ウォレット
│ → ⑨ P2P接続開始 → ⑩ RPC受付開始
│
├── 停止順序 🟢 フォーク不要
│ RPC停止 → ネットワーク停止 → mempool保存
│ → UTXOフラッシュ → 各モジュール逆順破棄
│
└── NodeContext(node/context.h)に全インスタンスを格納 🟢 フォーク不要
※ 起動/停止の順序や方法はローカルの実装詳細
─────────────────────────────────────────
pow.cpp(約170行)— 難易度とPoW 🔴 全体がフォーク必要
├── GetNextWorkRequired() 2016ブロックごとの難易度調整 🔴 フォーク必要
│ ├── 調整間隔(2016ブロック) 🔴 フォーク必要
│ ├── 上限/下限(4倍/1/4) 🔴 フォーク必要
│ └── 目標ブロック時間(10分) 🔴 フォーク必要
└── CheckProofOfWork() ブロックハッシュ ≤ ターゲット 🔴 フォーク必要
※ 難易度計算を変えたら他ノードと難易度が合わなくなる
─────────────────────────────────────────
versionbits.cpp(約400行)— ソフトフォーク活性化
├── 状態マシンのロジック自体 🔴 フォーク必要
│ DEFINED → STARTED → LOCKED_IN → ACTIVE / FAILED
├── 閾値(95%) 🔴 フォーク必要
├── 調整期間(2016ブロック) 🔴 フォーク必要
└── 各 deployment のパラメータ(→ consensus/params.h) 🔴 フォーク必要
※ 活性化ルールを変えたら、いつルールが有効になるかがノード間で食い違い、チェーン分裂する。
│
│ 心臓部が必要に応じて呼び出す
▼
ディレクトリ(専門部隊)— 特定の仕事に特化したファイル群
═════════════════════════════════════════
primitives/(データの形)
├── transaction.h CTransaction, CTxIn, CTxOut, COutPoint
│ ├── シリアライズ形式(バイトの並び順) 🔴 フォーク必要
│ │ ※ 変えると txid が変わり全ノードと不一致
│ ├── witness フラグ(marker=0x00, flag=0x01) 🔴 フォーク必要
│ └── フィールドの定義(version, vin, vout, nLockTime) 🔴 フォーク必要
│
└── block.h CBlockHeader(80バイト), CBlock
├── ヘッダの6フィールド構造 🔴 フォーク必要
│ ※ 変えるとブロックハッシュが変わる
├── CBlock が CBlockHeader を継承する設計 🟢 フォーク不要
└── fChecked 等のメモリ上フラグ 🟢 フォーク不要
─────────────────────────────────────────
consensus/(コンセンサスルール) 🔴 全体がフォーク必要
├── tx_check.cpp TX単体の構文チェック 🔴 フォーク必要
├── tx_verify.cpp TX文脈チェック(タイムロック、金額) 🔴 フォーク必要
├── merkle.cpp マークルルート計算 🔴 フォーク必要
├── amount.h MAX_MONEY = 21,000,000 BTC 🔴 フォーク必要
├── consensus.h MAX_BLOCK_WEIGHT = 4,000,000 🔴 フォーク必要
├── validation.h GetBlockWeight() の計算式 🔴 フォーク必要
└── params.h ソフトフォーク活性化パラメータ 🔴 フォーク必要
※ このディレクトリは「変えたら即チェーン分裂」の集合体
─────────────────────────────────────────
script/(署名検証エンジン)
├── script.h opcode定義(OP_CHECKSIG等)🔴 フォーク必要
│ ※ opcode の追加/変更はソフトフォーク
├── interpreter.cpp スタックマシン本体
│ ├── EvalScript() opcode実行ルール 🔴 フォーク必要
│ └── VerifyScript() 検証分岐ロジック 🔴 フォーク必要
│ ├── P2PKH 検証 🔴 フォーク必要
│ ├── P2SH 検証(BIP 16) 🔴 フォーク必要
│ ├── P2WPKH/P2WSH 検証(BIP 141) 🔴 フォーク必要
│ └── P2TR 検証(BIP 341) 🔴 フォーク必要
│
├── sign.cpp 署名「生成」ロジック 🟢 フォーク不要
│ └── ProduceSignature() 🟢 フォーク不要
│ ※ 署名の「作り方」は自由。検証に通ればいい。
│
├── descriptor.cpp Output Descriptor パーサー 🟢 フォーク不要
│ ※ アドレス生成方法はローカルの問題
├── miniscript.cpp Miniscript 🟢 フォーク不要
│ ※ Script への変換ツール。コンセンサスではない
└── sigcache.h 署名検証結果のキャッシュ 🟢 フォーク不要
※ パフォーマンス最適化
※ 検証(interpreter.cpp)= 🔴、生成/ツール = 🟢
─────────────────────────────────────────
secp256k1/(楕円曲線暗号ライブラリ) 🔴 全体がフォーク必要
├── secp256k1.c ECDSA 署名/検証 🔴 フォーク必要
├── modules/schnorrsig/ Schnorr 署名(BIP 340) 🔴 フォーク必要
├── modules/ellswift/ ElligatorSwift(BIP 324) 🟢 フォーク不要
└── modules/musig/ MuSig2(BIP 327)🟢 フォーク不要
※ 署名「検証」のロジック → 🔴(結果が変わるとチェーン分裂)
※ 署名「生成」や鍵交換 → 🟢(正しい署名が作れれば方法は自由)
※ ただし実装のバグは全ノードで同じ挙動を壊すので極めて危険
─────────────────────────────────────────
wallet/(送金機能 — オプション) 🟢 全体がフォーク不要
├── wallet.h CWallet 本体 🟢 フォーク不要
├── scriptpubkeyman.h 鍵生成と管理 🟢 フォーク不要
├── spend.h CreateTransaction() 🟢 フォーク不要
├── coinselection.h コイン選択アルゴリズム 🟢 フォーク不要
├── fees.h 手数料ロジック 🟢 フォーク不要
└── sqlite.h ウォレットDB 🟢 フォーク不要
※ ウォレットはコンセンサスに一切関与しない
※ どんなTXを作ろうが、検証に通りさえすれば自由
※ Contributor として最初に触りやすい領域
─────────────────────────────────────────
policy/(メモリプールのポリシー) 🟢 全体がフォーク不要
├── policy.h IsStandard() — 標準的TXの基準 🟢 フォーク不要
├── rbf.h Replace-by-Fee のルール 🟢 フォーク不要
├── fees/ CBlockPolicyEstimator — 手数料率推定 🟢 フォーク不要
├── packages.h パッケージリレーのルール 🟢 フォーク不要
└── truc_policy.h TRUC(v3 TX)ポリシー 🟢 フォーク不要
※ ポリシー = 各ノードが独自に決められるローカルルール
※ コンセンサス(ブロックに入れるか)とは別問題
─────────────────────────────────────────
node/(ノード固有の補助ロジック)🟢 ほぼフォーク不要
├── blockstorage.h blk*.dat / rev*.dat の読み書き 🟢 フォーク不要
├── miner.h BlockAssembler — ブロック組み立て 🟢 フォーク不要
│ ※ ただし結果のブロックは consensus/ ルールを満たす必要あり
├── context.h NodeContext — インスタンス格納 🟢 フォーク不要
├── mempool_persist.h mempool.dat の保存/復元 🟢 フォーク不要
├── chainstate.h チェーン状態の初期化 🟢 フォーク不要
├── txdownloadman.h TXダウンロード管理 🟢 フォーク不要
├── txorphanage.h 孤児TX管理 🟢 フォーク不要
└── txreconciliation.h Erlay(BIP 330) 🟢 フォーク不要
─────────────────────────────────────────
rpc/(外部からの操作窓口) 🟢 全体がフォーク不要
├── blockchain.cpp getblock, getblockchaininfo 🟢 フォーク不要
├── rawtransaction.cpp getrawtransaction, sendrawtransaction 🟢 フォーク不要
├── mining.cpp getblocktemplate 🟢 フォーク不要
├── mempool.cpp getmempoolinfo, getrawmempool 🟢 フォーク不要
├── net.cpp getpeerinfo 🟢 フォーク不要
└── server.h RPCサーバー本体 🟢 フォーク不要
※ 入口にすぎない。コンセンサスに関与しない
interfaces/(モジュール間の境界)🟢 全体がフォーク不要
├── chain.h ウォレット → チェーンへのアクセス 🟢 フォーク不要
├── node.h GUI → ノードへのアクセス 🟢 フォーク不要
├── wallet.h GUI → ウォレットへのアクセス 🟢 フォーク不要
└── mining.h マイニングインターフェース 🟢 フォーク不要
※ 内部のモジュール分離の仕組み。外部との合意に影響しない
まとめ
═════════════════════════════════════════
🔴 フォーク必要(変えたら全ノードと不一致 → チェーン分裂):
validation.cpp のコンセンサスチェック部分
consensus/ ディレクトリ全体
script/interpreter.cpp(署名「検証」ロジック)
secp256k1/ の署名「検証」部分
pow.cpp 全体
versionbits.cpp 全体
primitives/ のシリアライズ形式
chain.h のハッシュ計算・累積PoW計算
🟢 フォーク不要(各ノードが自由に変更可能):
net.cpp / net_processing.cpp(P2P通信の実装)
txmempool.h(メモリプールの管理方法)
coins.h のキャッシュ設計(最終UTXO状態が同じなら自由)
init.cpp(起動/停止の手順)
wallet/ ディレクトリ全体
policy/ ディレクトリ全体
node/ ディレクトリ全体
rpc/ ディレクトリ全体
interfaces/ ディレクトリ全体
script/sign.cpp, descriptor.cpp, miniscript.cpp(署名「生成」側)
判断基準:
「この変更をした後、他の全ノードと同じブロック/TXを
有効/無効と判断できるか?」
YES → 🟢 フォーク不要
NO → 🔴 フォーク必要
もしコントリビューターになりたいのなら
AI時代に、お金にもならず、名声を得るわけでもなく、ただただ熱意だけでCやC++や暗号学を学んでビットコインの開発に参加するのは個人的には狂人の類だとは思いますが、人類が「仕事」から解放される時代になるんだったらこれほど暇つぶしになる楽しいタスクもないと思うので、Claude先生にコントリビューターになるための方法論を解説してもらいました。
Contributor への5段階
① 設計を理解する
② C++ を読めるようにする
③ PR レビューで信頼を積む ← 最も重要
④ テストを書く / ドキュメントを改善する
⑤ コードの PR を出す
① → ② の橋渡し
「どのファイルが何をしているか」を理解できたら次は実際のコードを読める必要があります。ただしCore 全体を理解する必要はなく、特定の領域に絞れば十分に通用します。
参入しやすい領域:
領域 | 理由 |
test/functional/ (Python) | Pythonで書かれたテスト。C++を書かなくても貢献できる |
doc/ | ドキュメントの修正。最も敷居が低い |
rpc/ | 薄い層なので理解しやすい。RPC の改善は需要がある |
wallet/ | 独立性が高く、コンセンサスに影響しないので安全 |
避けるべき領域: validation.cpp, consensus/, script/。
ここはコンセンサスに直結するので、新人が触るには荷が重過ぎます。公式にも「consensus code を最初に変えようとするな」と明記されています。
③ PR レビュー — ここが本番
Bitcoin Core のプロジェクトでは、レビューとテストが最も高く評価されており、新しいコントリビューターが貢献する最も効果的な方法とされています。PRを書くより先にレビューで信頼を積むのが正攻法。
具体的なステップ:
毎月の PR Review Club に参加する ➡️ Bitcoincore
毎月第1水曜・木曜の17:00 UTC に #bitcoin-core-pr-reviews IRC チャンネルで開催
事前に指定PRのdiffを読み、質問に答えを用意して参加する
新しいコントリビューターがコードベースとレビュープロセスを学ぶことを目的としている
レビューの作法:
Concept ACK はレビュアーが変更の目標に同意していることを意味するが、コードを確認したりテストしたことまでは確認していない ➡️ Jonatack
新しいコントリビューターとして、レビュー中に何を行い、何を考えたかのコンテキストを提供するために、レビューコメントをより詳しく書くことが推奨される
新しいコントリビューターとして、NACKを出すのは慎重にすべきであり、自分が理解不足やコンテキスト不足である可能性をデフォルトで想定するべ
1 PR 出すごとに 5〜15 PR レビューするのが目安:
良い目安は、PRを1つ出すごとに5〜15のPRをレビュー(または5〜15のオープンIssueを解決・テスト)すること
④ 最初の貢献
リファクタリングのPRは新しいコントリビューターが行うべきではありません。コードがどこに属するかを知り、オープンPRのリベース作業を含む全体的な影響を理解するには、一定レベルの経験が必要となります。
最初に狙うべきもの:
good first issue ラベルの Issue
テストカバレッジの追加(test/functional/)
ドキュメントの改善
TODO/FIXME コメントの解消(git grep "TODO\|FIXME")
具体的なロードマップ
Month 1-2: 基盤固め
├── 設計の理解に努める
├── Bitcoin Core をソースからビルドする
├── regtest でトランザクション/ブロック操作に慣れる
└── C++ の読み書き: "A Tour of C++" (Stroustrup)
Month 3-4: レビュー開始
├── PR Review Club に毎月参加する
├── good first issue を眺めて、理解できるものを探す
├── 気になる PR の diff を読んで、自分なりの ACK/NACK を書く練習
└── IRC #bitcoin-core-dev を眺める
Month 5-6: 最初の PR
├── テスト追加 or ドキュメント改善 の PR を1つ出す
├── レビューコメントへの対応を丁寧にやる
└── 並行して他の PR レビューを続ける(PR 1 : レビュー 10 の比率)
Ongoing:
├── Chaincode BOSS Challenge への応募を検討
│ (年1回のコホート制、3ヶ月のプログラム)
├── Delving Bitcoin でプロトコルの議論を追う
└── 特定の領域(wallet, rpc, test 等)で専門性を積む


