跳至主要內容
高級

Mempool Eviction

了解 Bitcoin Core 如何在 mempool 滿載時驅逐低優先級交易。

10 分鐘

當 mempool 達到容量上限時,Bitcoin Core 需要驅逐低費率的交易以騰出空間。 驅逐策略確保 mempool 保留最有價值的交易,同時防止記憶體耗盡。

Mempool 容量限制

默認配置:
maxmempool = 300 MB  # 默認 mempool 大小
mempoolexpiry = 336  # 交易過期時間(小時,14天)

配置選項:
# bitcoin.conf
maxmempool=300      # 設置為 300 MB
maxmempool=1000     # 設置為 1 GB(需要更多記憶體)
mempoolexpiry=336   # 14 天後過期

查看當前狀態:
bitcoin-cli getmempoolinfo
{
  "loaded": true,
  "size": 45000,           # 交易數量
  "bytes": 28500000,       # 總大小(bytes)
  "usage": 95000000,       # 記憶體使用(含索引)
  "total_fee": 1.25,       # 總手續費
  "maxmempool": 300000000, # 容量上限
  "mempoolminfee": 0.00001000,  # 最低接受費率
  "minrelaytxfee": 0.00001000,  # 最低中繼費率
  "incrementalrelayfee": 0.00001000
}

驅逐策略

驅逐優先級(從低到高):

1. 祖先費率(Ancestor Fee Rate)
   - 考慮整個交易包的費率
   - 父交易 + 當前交易的總費率
   - 低祖先費率優先被驅逐

2. 後代費率(Descendant Fee Rate)
   - 考慮子交易的「拉動」效應
   - 但驅逐時整個後代鏈一起移除

驅逐流程:
1. 計算所有交易的祖先費率
2. 找到祖先費率最低的交易
3. 移除該交易及其所有後代
4. 重複直到 mempool 低於限制

// 注意: 驅逐是按「包」進行的
// 不能只驅逐父交易而保留子交易

動態最低費率

// mempool 滿時自動提高最低費率

當 mempool 接近滿載:
1. 計算「驅逐費率」
   eviction_rate = 最低被驅逐交易的費率
2. 設置 mempoolminfee
   mempoolminfee = eviction_rate + incrementalrelayfee

效果:
- 新交易必須付更高費率才能進入
- 自動形成費率市場
- 防止低價值交易佔用空間

查看當前最低費率:
bitcoin-cli getmempoolinfo | jq '.mempoolminfee'

// 當 mempool 清空時
// mempoolminfee 會回落到 minrelaytxfee

費率計算細節

祖先費率計算:

單交易費率:
fee_rate = fee / vsize

祖先費率:
ancestor_fee_rate = ancestor_fees / ancestor_vsize

其中:
- ancestor_fees = 自己的費用 + 所有未確認祖先的費用
- ancestor_vsize = 自己的大小 + 所有未確認祖先的大小

範例:
交易 A: 200 vB, 200 sat (1 sat/vB)
交易 B: 200 vB, 600 sat (3 sat/vB), 依賴 A

B 的祖先費率:
= (200 + 600) / (200 + 200)
= 800 / 400
= 2 sat/vB

// 儘管 B 自己是 3 sat/vB
// 但祖先費率只有 2 sat/vB

驅逐示例

場景: mempool 滿載,需要驅逐 1 MB

交易池中的交易:
TX_A: 500 vB, ancestor_fee_rate = 1 sat/vB
TX_B: 300 vB, ancestor_fee_rate = 2 sat/vB
TX_C: 800 vB, ancestor_fee_rate = 0.5 sat/vB  ← 最低
TX_D: 200 vB, ancestor_fee_rate = 5 sat/vB
TX_E: 400 vB, ancestor_fee_rate = 1.5 sat/vB

驅逐順序:
1. 首先驅逐 TX_C (0.5 sat/vB) → 釋放 800 vB
2. 然後驅逐 TX_A (1 sat/vB) → 釋放 500 vB

結果:
- 驅逐了 1300 vB
- 新的 mempoolminfee ≈ 1 sat/vB + increment
- 保留了較高費率的交易

後代限制

防止過長的交易鏈:

默認限制:
MAX_ANCESTORS = 25      # 最大祖先數量
MAX_DESCENDANTS = 25    # 最大後代數量
MAX_ANCESTOR_SIZE = 101 KB   # 祖先鏈最大大小
MAX_DESCENDANT_SIZE = 101 KB # 後代鏈最大大小

為什麼需要限制?
1. 驅逐一個交易可能連帶驅逐大量後代
2. 驗證長鏈需要更多計算
3. 防止 DoS 攻擊

超過限制的後果:
- 交易被拒絕進入 mempool
- 需要等待部分祖先確認
- 或使用 CPFP 打包確認

查看交易的祖先/後代:
bitcoin-cli getmempoolentry <txid> | jq '.fees'

RBF 與驅逐的互動

RBF 替換 vs 驅逐:

RBF 替換:
- 主動替換,由用戶發起
- 需要滿足 BIP-125 規則
- 新交易必須支付更高總費用

驅逐:
- 被動移除,由系統執行
- 基於相對費率
- 不產生新交易

互動情況:
1. 如果交易被驅逐,RBF 失去意義
   - 原交易不在 mempool
   - 新交易按普通交易處理

2. 如果 mempool 滿,RBF 更容易
   - 被替換交易可能已接近驅逐門檻
   - 新交易更容易滿足費率要求

3. 驅逐後重新廣播
   - 交易可以重新進入(如果費率夠高)
   - 但在擁擠時可能再次被驅逐

時間過期

除了費率驅逐,還有時間過期:

默認: mempoolexpiry = 336 小時 (14 天)

工作方式:
- 每個交易記錄進入時間
- 定期清理超過 expiry 的交易
- 與費率驅逐獨立

為什麼需要?
1. 防止交易永久佔用空間
2. 清理「死」交易(如過期的時間鎖)
3. 保持 mempool 新鮮

// 注意: 過期不意味著交易無效
// 交易可能仍在其他節點的 mempool
// 或者可以重新廣播

監控與調試

# 查看 mempool 統計
bitcoin-cli getmempoolinfo

# 查看費率分佈
bitcoin-cli getrawmempool true | jq '
  [.[]] |
  group_by(.fees.ancestor | . * 100000000 / .ancestorsize | floor) |
  map({rate: .[0].fees.ancestor * 100000000 / .[0].ancestorsize | floor, count: length})
'

# 查看即將被驅逐的交易
bitcoin-cli getrawmempool true | jq '
  to_entries |
  sort_by(.value.fees.ancestor / .value.ancestorsize) |
  .[0:10] |
  map({txid: .key, rate: .value.fees.ancestor * 100000000 / .value.ancestorsize})
'

# 監控 mempool 變化
watch -n 10 'bitcoin-cli getmempoolinfo | jq "{size, bytes, mempoolminfee}"'

對用戶的影響

  • 費率估算:在擁擠時期使用更高費率
  • RBF 準備:啟用 RBF 以便加速卡住的交易
  • 監控狀態:關注 mempoolminfee 變化
  • 避免長鏈:不要創建太長的未確認交易鏈
  • 及時確認:在費率低時盡快確認交易

相關概念

  • Mempool Policy:Mempool 接受策略
  • Fee Estimation:手續費估算
  • RBF:Replace-by-Fee
  • CPFP:Child Pays For Parent
  • Ancestor Limits:祖先後代限制
已複製連結
已複製到剪貼簿