高級
LevelDB
深入了解 Bitcoin Core 使用的 LevelDB 鍵值資料庫,儲存區塊索引和 UTXO 集。
12 分鐘
什麼是 LevelDB?
LevelDB 是 Google 開發的快速鍵值儲存庫,Bitcoin Core 用它來儲存區塊索引和 UTXO 集(chainstate)。 它使用 LSM-tree(Log-Structured Merge-tree)結構,針對寫入密集型工作負載優化。
Bitcoin Core 中的 LevelDB
blocks/index/
- • 區塊頭索引
- • 區塊在 blk*.dat 中的位置
- • 區塊元數據
chainstate/
- • UTXO 集
- • 當前最佳區塊哈希
- • 數據庫版本
數據結構
區塊索引格式
// blocks/index 的鍵值格式
// 區塊索引條目
// Key: 'b' + block_hash (33 bytes)
// Value: CDiskBlockIndex 序列化
interface BlockIndexEntry {
version: number;
height: number;
status: number; // 驗證狀態
nTx: number; // 交易數量
nFile: number; // blk*.dat 檔案編號
nDataPos: number; // 區塊在檔案中的位置
nUndoPos: number; // undo 數據位置
header: BlockHeader; // 區塊頭
}
// 檔案資訊
// Key: 'f' + file_number (5 bytes)
// Value: 檔案統計資訊
interface FileInfo {
blocks: number; // 區塊數量
size: number; // 檔案大小
undoSize: number; // undo 檔案大小
heightFirst: number; // 最低區塊高度
heightLast: number; // 最高區塊高度
timeFirst: number; // 最早時間戳
timeLast: number; // 最晚時間戳
}
// 最後一個區塊檔案編號
// Key: 'l' (1 byte)
// Value: 最後的檔案編號
// 重新索引標記
// Key: 'R' (1 byte)
// Value: 1 表示需要重新索引
// 區塊標誌
// Key: 'F' + flag_name
// Value: 布林值 Chainstate 格式
// chainstate 的鍵值格式
// UTXO 條目
// Key: 'C' + txid (33 bytes)
// Value: 壓縮的 UTXO 數據
interface UTXOEntry {
// Varint 編碼的高度和 coinbase 標誌
// 最低位 = coinbase,其餘位 = height
heightAndCoinbase: number;
// 每個未花費輸出
outputs: Array<{
// Varint: 與上一個輸出的索引差
// 0 = 輸出 0,1 = 輸出 1,...
// 如果輸出已花費則跳過
index: number;
// 壓縮的金額(特殊編碼節省空間)
amount: CompressedAmount;
// 壓縮的腳本
script: CompressedScript;
}>;
}
// 最佳區塊哈希
// Key: 'B' (1 byte)
// Value: 32 字節區塊哈希
// 數據庫版本
// Key: 'D' + 'b' (2 bytes)
// Value: 版本號
// Obfuscation key
// Key: 14 bytes (固定)
// Value: XOR 混淆密鑰 LSM-Tree 結構
LevelDB LSM-Tree 結構:
┌─────────────────────────────────────────────────────┐
│ MemTable │
│ (記憶體中的寫入緩衝) │
│ ↓ 滿了後刷新 │
├─────────────────────────────────────────────────────┤
│ Immutable MemTable │
│ (等待寫入磁碟) │
│ ↓ 寫入 │
├─────────────────────────────────────────────────────┤
│ Level 0: SSTable SSTable SSTable ... │
│ (剛從 MemTable 刷新,可能重疊) │
│ ↓ 合併 │
├─────────────────────────────────────────────────────┤
│ Level 1: SSTable SSTable SSTable ... │
│ (已排序,不重疊) │
│ ↓ 合併 │
├─────────────────────────────────────────────────────┤
│ Level 2: SSTable SSTable SSTable SSTable ... │
│ ↓ │
│ ...更多層級... │
└─────────────────────────────────────────────────────┘
SSTable = Sorted String Table(已排序的字符串表) 讀寫特性
| 操作 | 特性 |
|---|---|
| 寫入 | O(1) - 先寫入 MemTable |
| 讀取 | O(log N) - 可能需要查詢多個層級 |
| 範圍掃描 | 高效 - 數據已排序 |
| 刪除 | 寫入 tombstone 標記 |
數據混淆
Bitcoin Core 使用 XOR 混淆來防止殺毒軟體誤報(區塊鏈數據可能包含看起來像惡意內容的模式):
class ObfuscatedDB {
private obfuscateKey: Buffer;
constructor() {
// 首次創建時生成隨機密鑰
// 或從數據庫讀取現有密鑰
this.obfuscateKey = this.getOrCreateKey();
}
write(key: Buffer, value: Buffer): void {
const obfuscated = this.xor(value, this.obfuscateKey);
this.db.put(key, obfuscated);
}
read(key: Buffer): Buffer {
const obfuscated = this.db.get(key);
return this.xor(obfuscated, this.obfuscateKey);
}
private xor(data: Buffer, key: Buffer): Buffer {
const result = Buffer.alloc(data.length);
for (let i = 0; i < data.length; i++) {
result[i] = data[i] ^ key[i % key.length];
}
return result;
}
} 維護與診斷
# 數據庫位置
~/.bitcoin/blocks/index/ # 區塊索引
~/.bitcoin/chainstate/ # UTXO 集
# 檢查數據庫大小
du -sh ~/.bitcoin/blocks/index/
du -sh ~/.bitcoin/chainstate/
# 常見錯誤處理
# "Corruption: block checksum mismatch"
# "LevelDB read failure"
# → 通常需要 -reindex 或 -reindex-chainstate
# 重建區塊索引
bitcoind -reindex
# 僅重建 chainstate
bitcoind -reindex-chainstate
# 增加 dbcache 可以減少 LevelDB I/O
bitcoind -dbcache=4096 警告: 不要直接修改 LevelDB 文件。數據庫損壞可能導致節點無法啟動。 如果懷疑數據庫損壞,使用 -reindex 重建。
總結
- ✓ 用途:儲存區塊索引和 UTXO 集
- ✓ LSM-Tree:針對寫入密集型工作優化
- ✓ 混淆:XOR 加密防止殺毒軟體誤報
- ⚠ 維護:損壞時使用 -reindex 重建
已複製連結