高級
AddrMan
深入了解 Bitcoin Core 的地址管理器,如何發現、儲存和選擇對等節點地址。
12 分鐘
什麼是 AddrMan?
AddrMan(Address Manager)是 Bitcoin Core 的地址管理系統,負責發現、儲存和選擇對等節點地址。 它使用精心設計的數據結構來抵抗 Eclipse 攻擊,確保節點能夠連接到真實的比特幣網路。
AddrMan 的職責
地址收集
- • 從 DNS seeds 獲取初始地址
- • 接收對等節點廣播的地址
- • 記錄成功連接的節點
連接選擇
- • 選擇要連接的節點
- • 平衡新舊地址
- • 防止連接偏向
雙表架構
AddrMan 結構:
┌──────────────────────────────────────────────────────┐
│ New Table (1024 buckets × 64 entries) │
│ ├── 儲存從未成功連接過的地址 │
│ ├── 按來源 IP 分組(防止單一來源控制) │
│ └── 最多 65,536 個地址 │
├──────────────────────────────────────────────────────┤
│ Tried Table (256 buckets × 64 entries) │
│ ├── 儲存成功連接過的地址 │
│ ├── 按目標 IP 分組 │
│ └── 最多 16,384 個地址 │
└──────────────────────────────────────────────────────┘ interface AddrInfo {
addr: NetAddress; // IP:Port
source: NetAddress; // 誰告訴我們這個地址
lastTry: number; // 最後嘗試連接時間
lastSuccess: number; // 最後成功連接時間
nAttempts: number; // 連接嘗試次數
}
class AddrMan {
private newTable: AddrInfo[/* 1024 */][/* 64 */];
private triedTable: AddrInfo[/* 256 */][/* 64 */];
private nKey: Buffer; // 隨機密鑰,防止預測
// New 表的 bucket 選擇(基於來源 IP)
getNewBucket(addr: NetAddress, source: NetAddress): number {
const sourceGroup = this.getGroup(source); // /16 網段
const hash = this.hash(this.nKey, sourceGroup, addr);
return hash % 1024;
}
// Tried 表的 bucket 選擇(基於目標 IP)
getTriedBucket(addr: NetAddress): number {
const addrGroup = this.getGroup(addr);
const hash = this.hash(this.nKey, addrGroup);
return hash % 256;
}
// 標記連接成功,移到 Tried 表
good(addr: NetAddress): void {
const info = this.findInNew(addr);
if (!info) return;
this.removeFromNew(addr);
const bucket = this.getTriedBucket(addr);
info.lastSuccess = Date.now();
this.triedTable[bucket][position] = info;
}
} Eclipse 攻擊防護
什麼是 Eclipse 攻擊?
攻擊者控制受害節點的所有連接,將其與真實網路隔離。
- • 雙花攻擊 - 讓商家看到假的確認
- • 自私挖礦 - 延遲受害者看到新區塊
- • N-confirmation 攻擊 - 製造假的確認深度
防禦機制
- 1 基於來源的 Bucket 分配
單一來源無法填滿所有 bucket
- 2 隨機密鑰 (nKey)
每個節點不同,攻擊者無法預測 bucket
- 3 網段多樣性
出站連接確保來自不同的 /16 網段
- 4 錨定連接
重啟時優先連接最後成功的節點
持久化
# 地址數據庫
~/.bitcoin/peers.dat
# 錨定檔案(重啟時優先連接)
~/.bitcoin/anchors.dat
# 查看已知地址
bitcoin-cli getnodeaddresses 10
# 手動添加節點
bitcoin-cli addnode "192.168.1.100:8333" "add"
# 查看連接的節點
bitcoin-cli getpeerinfo | jq '.[].addr' 配置選項
# bitcoin.conf
# 手動指定節點
addnode=192.168.1.100:8333
# 只連接到指定節點
connect=192.168.1.100:8333
# DNS seeds(預設開啟)
dnsseed=1
# 固定 seeds
fixedseeds=1
# 最大連接數
maxconnections=125 總結
- ✓ 雙表架構:New 表存新地址,Tried 表存驗證過的地址
- ✓ Eclipse 防護:基於來源分組、隨機密鑰、網段多樣性
- ✓ 錨定連接:重啟時優先連接已知可信節點
已複製連結