高級
CoinStatsIndex
深入了解 Bitcoin Core 的 coinstatsindex,提供 UTXO 集統計和 muhash 驗證功能。
12 分鐘
什麼是 CoinStatsIndex?
CoinStatsIndex 是 Bitcoin Core 22.0 引入的可選索引,用於追蹤每個區塊高度的 UTXO 集統計資訊。 它提供快速的 UTXO 集查詢功能,支援 MuHash 驗證,是 AssumeUTXO 功能的重要基礎。
主要功能
UTXO 統計
- • 每個高度的 UTXO 數量
- • 總供應量追蹤
- • OP_RETURN 燒毀統計
MuHash
- • UTXO 集的密碼學承諾
- • 支援增量更新
- • AssumeUTXO 驗證
配置方式
啟用索引
# 命令行啟用
bitcoind -coinstatsindex
# 配置文件
echo "coinstatsindex=1" >> ~/.bitcoin/bitcoin.conf
# 首次啟用需要建立索引
# 會掃描整個區塊鏈,可能需要數小時 注意: 建立索引需要掃描整個區塊鏈。在 SSD 上約需 2-4 小時, HDD 可能需要更長時間。索引大小約 2-3 GB。
儲存位置
# 索引儲存在
~/.bitcoin/indexes/coinstats/
# 檔案結構
indexes/coinstats/
├── db/ # LevelDB 資料庫
└── ...
# 查看索引大小
du -sh ~/.bitcoin/indexes/coinstats/ RPC 命令
gettxoutsetinfo
# 基本用法(沒有 coinstatsindex 也可用,但較慢)
bitcoin-cli gettxoutsetinfo
# 使用 coinstatsindex(快速)
bitcoin-cli gettxoutsetinfo muhash
# 查詢特定高度(需要 coinstatsindex)
bitcoin-cli gettxoutsetinfo muhash '"800000"'
# 輸出示例
{
"height": 800000,
"bestblock": "00000000000000000002a7c4c1e48d76c5a37902165a270156b7a8d72728a054",
"txouts": 95234567,
"bogosize": 7123456789,
"muhash": "abcdef1234567890...",
"total_amount": 19468750.00000000,
"total_unspendable_amount": 219.12345678,
"block_info": {
"prevout_spent": 12345.67890000,
"coinbase": 6.25000000,
"new_outputs_ex_coinbase": 12340.42890000,
"unspendable": 0.00000000,
"unspendables": {
"genesis_block": 50.00000000,
"bip30": 0.00000000,
"scripts": 169.12345678,
"unclaimed_rewards": 0.00000000
}
}
} 輸出欄位說明
| 欄位 | 說明 |
|---|---|
| txouts | UTXO 數量 |
| bogosize | 序列化大小估算(字節) |
| muhash | UTXO 集的 MuHash |
| total_amount | 可花費的總金額 |
| total_unspendable_amount | 不可花費的總金額 |
MuHash 原理
什麼是 MuHash?
MuHash(Multiplicative Hash)是一種可增量更新的集合哈希函數。 它允許高效地計算 UTXO 集的密碼學承諾,而不需要遍歷整個集合。
// MuHash 的數學原理
// 基於有限域上的乘法
class MuHash {
private numerator: bigint; // 分子
private denominator: bigint; // 分母
private readonly prime: bigint; // 3072-bit 素數
constructor() {
this.numerator = 1n;
this.denominator = 1n;
this.prime = /* 大素數 */;
}
// 添加元素:乘以元素的哈希
add(element: Buffer): void {
const hash = this.hashToFieldElement(element);
this.numerator = (this.numerator * hash) % this.prime;
}
// 移除元素:除以元素的哈希(乘以分母)
remove(element: Buffer): void {
const hash = this.hashToFieldElement(element);
this.denominator = (this.denominator * hash) % this.prime;
}
// 合併兩個 MuHash
combine(other: MuHash): void {
this.numerator = (this.numerator * other.numerator) % this.prime;
this.denominator = (this.denominator * other.denominator) % this.prime;
}
// 獲取最終哈希
finalize(): Buffer {
// 計算 numerator / denominator (mod prime)
const denominatorInv = this.modInverse(this.denominator, this.prime);
const result = (this.numerator * denominatorInv) % this.prime;
return this.toSHA256(result);
}
private hashToFieldElement(data: Buffer): bigint {
// 使用 SHA256 將數據映射到有限域
const hash = sha256(data);
return BigInt('0x' + hash.toString('hex')) % this.prime;
}
} MuHash 特性
- 1 可交換性
元素的添加順序不影響結果
- 2 可增量更新
添加或刪除元素的複雜度為 O(1)
- 3 可合併性
兩個 MuHash 可以高效合併
- 4 抗碰撞
基於離散對數假設的安全性
實現細節
索引結構
interface CoinStatsEntry {
height: number;
blockHash: string;
// UTXO 統計
txoutCount: bigint;
bogoSize: bigint;
totalAmount: bigint;
// MuHash
muhash: Buffer; // 32 bytes
// 供應量追蹤
totalUnspendable: bigint;
genesisBlockUnspendable: bigint;
bip30Unspendable: bigint;
scriptsUnspendable: bigint;
unclaimedRewards: bigint;
}
class CoinStatsIndex {
private db: LevelDB;
private currentStats: CoinStatsEntry;
private muhash: MuHash;
async init(): Promise {
// 從 chainstate 初始化 MuHash
this.muhash = new MuHash();
// 遍歷所有現有 UTXO 建立初始 MuHash
for await (const utxo of this.iterateUTXOs()) {
const serialized = this.serializeUTXO(utxo);
this.muhash.add(serialized);
}
}
// 處理新區塊
async connectBlock(block: Block, undoData: UndoData): Promise {
// 移除被花費的 UTXO
for (const spent of undoData.spentOutputs) {
const serialized = this.serializeUTXO(spent);
this.muhash.remove(serialized);
this.currentStats.txoutCount--;
this.currentStats.totalAmount -= spent.value;
}
// 添加新的 UTXO
for (const tx of block.transactions) {
for (const output of tx.outputs) {
if (!this.isUnspendable(output)) {
const utxo = this.createUTXO(tx.txid, output);
const serialized = this.serializeUTXO(utxo);
this.muhash.add(serialized);
this.currentStats.txoutCount++;
this.currentStats.totalAmount += output.value;
} else {
// 追蹤不可花費的輸出
this.currentStats.totalUnspendable += output.value;
this.currentStats.scriptsUnspendable += output.value;
}
}
}
// 更新區塊資訊
this.currentStats.height = block.height;
this.currentStats.blockHash = block.hash;
this.currentStats.muhash = this.muhash.finalize();
// 寫入資料庫
await this.db.put(block.height, this.serialize(this.currentStats));
}
// 序列化 UTXO 用於 MuHash
private serializeUTXO(utxo: UTXO): Buffer {
// 格式: txid + vout + script + value + height + coinbase
return Buffer.concat([
Buffer.from(utxo.txid, 'hex'),
this.encodeVarInt(utxo.vout),
utxo.scriptPubKey,
this.encodeAmount(utxo.value),
this.encodeVarInt(utxo.height),
Buffer.from([utxo.coinbase ? 1 : 0]),
]);
}
} 與 AssumeUTXO 的關係
AssumeUTXO 驗證
CoinStatsIndex 的 MuHash 是 AssumeUTXO 功能的核心。 它允許快速驗證預設的 UTXO 集快照是否正確。
// AssumeUTXO 驗證流程
class AssumeUTXOVerifier {
async verifySnapshot(
snapshot: UTXOSnapshot,
expectedMuHash: string
): Promise {
// 使用 coinstatsindex 計算 MuHash
const muhash = new MuHash();
for (const utxo of snapshot.utxos) {
const serialized = this.serializeUTXO(utxo);
muhash.add(serialized);
}
const calculatedHash = muhash.finalize().toString('hex');
// 比對預期的 MuHash
return calculatedHash === expectedMuHash;
}
}
// chainparams.cpp 中的 AssumeUTXO 配置
const ASSUME_UTXO_DATA = {
// 高度 840000 的快照
840000: {
hashSerialized: '...', // UTXO 集的 SHA256
muhash: '...', // MuHash(用於驗證)
txoutCount: 150000000,
totalAmount: 19700000_00000000n,
},
}; 使用場景
✓ 適合啟用
- • 需要查詢歷史 UTXO 統計
- • 進行區塊鏈分析
- • 驗證 AssumeUTXO 快照
- • 研究供應量分佈
✗ 可能不需要
- • 磁碟空間有限
- • 只需要基本節點功能
- • 使用 pruned 模式
- • 效能敏感的環境
供應量審計
# 驗證比特幣總供應量
bitcoin-cli gettxoutsetinfo muhash | jq '{
total_amount,
total_unspendable_amount,
theoretical_supply: (19 * 10000000 + (.height - 840000) * 3.125)
}'
# 分析不可花費的比特幣
bitcoin-cli gettxoutsetinfo muhash | jq '.block_info.unspendables' 效能考量
資源需求
| 項目 | 數值 |
|---|---|
| 磁碟空間 | 約 2-3 GB |
| 初始建立時間(SSD) | 2-4 小時 |
| 每區塊更新時間 | < 1 秒 |
| 歷史查詢時間 | < 100 ms |
總結
- ✓ UTXO 統計:每個高度的 UTXO 集統計資訊
- ✓ MuHash:可增量更新的 UTXO 集密碼學承諾
- ✓ AssumeUTXO:驗證 UTXO 快照的重要基礎
- ⚠ 資源:需要額外 2-3 GB 磁碟空間和初始建立時間
已複製連結