高級
Fee Sniping
了解手續費狙擊攻擊的原理,以及 nLockTime 如何用於防護。
10 分鐘
手續費狙擊(Fee Sniping)是一種理論上的礦工攻擊,礦工試圖重新挖掘已確認的區塊 以獲取其中的高手續費交易。Bitcoin Core 使用 nLockTime 來防止這種攻擊。
攻擊原理
正常情況:
區塊 N: 包含高手續費交易 (總手續費: 5 BTC)
區塊 N+1: 礦工 A 正在挖掘
Fee Sniping 攻擊:
1. 礦工 B 看到區塊 N 有很高的手續費
2. 礦工 B 決定重新挖掘區塊 N
3. 礦工 B 在區塊 N-1 上挖礦
4. 如果成功,獲得區塊 N 的所有手續費
風險:
- 如果礦工 A 先完成區塊 N+1
- 礦工 B 需要挖 2 個區塊才能追上
- 通常不划算,但高手續費時可能有利可圖 為什麼是問題?
// 經濟激勵可能導致不穩定
假設:
- 區塊 N 手續費: 10 BTC
- 區塊 N+1 預期手續費: 0.5 BTC
- 礦工算力: 20%
期望收益比較:
誠實挖礦 (N+1):
0.2 × (6.25 + 0.5) = 1.35 BTC
狙擊 (重挖 N):
0.2 × (6.25 + 10) = 3.25 BTC (如果成功)
如果狙擊成功率 > 41%,則狙擊更有利
// 大礦工或礦池可能有足夠高的成功率 nLockTime 防護
Bitcoin Core 創建的交易默認設置 nLockTime 為當前區塊高度:
// nLockTime 設置策略
交易創建時:
if (current_height > 0) {
// 設置為當前高度
tx.nLockTime = current_height;
// 10% 的概率減 1(防止區塊高度洩露隱私)
if (GetRand(10) == 0 && tx.nLockTime > 0) {
tx.nLockTime--;
}
}
效果:
- 交易只能被包含在區塊 N 或之後
- 礦工無法將交易放入重新挖掘的區塊 N-1
- 降低了狙擊的吸引力 工作原理
場景:
當前區塊高度: 840000
交易 TX 創建,nLockTime = 840000
正常流程:
TX 被包含在區塊 840001 ✓
Fee Sniping 嘗試:
礦工想重新挖掘區塊 840000
但 TX 的 nLockTime = 840000
TX 不能被包含在區塊 839999
礦工無法獲得 TX 的手續費
狙擊失去吸引力 ✓
// 注意: TX 可以被包含在 840000 或之後的任何區塊
// 所以正常操作不受影響 nSequence 的作用
// nLockTime 只在 nSequence < 0xffffffff 時生效
Bitcoin Core 的設置:
- 如果啟用 RBF: nSequence = 0xfffffffd
(允許 RBF,同時啟用 nLockTime)
- 如果禁用 RBF: nSequence = 0xfffffffe
(禁用 RBF,但仍啟用 nLockTime)
// 只有 nSequence = 0xffffffff 時 nLockTime 被忽略
// 這在現代錢包中很少使用 為什麼只是部分解決?
// nLockTime 防護的局限性
1. 只保護新交易
- 舊交易(已在 mempool 中的)沒有這個保護
- 礦工可能從重新挖掘中獲得一些手續費
2. 礦工可以創建自己的交易
- 礦工可以用自己的交易替換
- 只是獲取手續費,不是竊取
3. 不能阻止區塊重組
- 51% 攻擊仍然可能
- nLockTime 只是降低激勵
4. 交易可能已在目標區塊中
- nLockTime = N 的交易可以在區塊 N 中
- 重新挖掘區塊 N 時仍可包含 未來考慮
// 隨著區塊獎勵減少,手續費比例增加
2024 年:
- 區塊獎勵: 3.125 BTC
- 平均手續費: 0.1-1 BTC
- 手續費佔比: 3-25%
未來:
- 區塊獎勵: 趨近 0
- 手續費將是主要收入
- Fee sniping 激勵可能增加
可能的改進:
- 更強的時間鎖機制
- 協議級別的狙擊懲罰
- 社會共識(礦池聲譽) 錢包實現
// 檢查錢包是否正確設置 nLockTime
# 創建交易
bitcoin-cli createrawtransaction '[...]' '{...}'
# 解碼並檢查
bitcoin-cli decoderawtransaction <hex>
{
...
"locktime": 840000, # 應該是當前高度附近
"vin": [
{
...
"sequence": 4294967293 # 0xfffffffd, 啟用 nLockTime
}
]
}
# 如果 locktime = 0 且 sequence = 0xffffffff
# 錢包可能沒有實現 fee sniping 保護 對用戶的影響
- 透明:用戶通常不需要關心這個機制
- 無額外成本:不增加交易大小或手續費
- 兼容性:與 RBF 和相對時間鎖兼容
- 隱私:隨機減 1 避免洩露錢包類型
程序示例
import random
def set_anti_fee_sniping(tx, current_height):
"""設置 nLockTime 以防止 fee sniping"""
# 基本設置為當前高度
tx.nLockTime = current_height
# 10% 概率減 1(隱私保護)
if random.randint(0, 9) == 0 and tx.nLockTime > 0:
tx.nLockTime -= 1
# 確保 nSequence 啟用 nLockTime
for inp in tx.vin:
if inp.nSequence == 0xffffffff:
inp.nSequence = 0xfffffffe # 啟用 nLockTime
return tx
# 使用
tx = create_transaction(inputs, outputs)
tx = set_anti_fee_sniping(tx, get_current_height()) 相關概念
- nLockTime:交易級別的絕對時間鎖
- nSequence:輸入級別的序列號,影響 nLockTime 行為
- BIP-68:相對時間鎖(使用 nSequence)
- 區塊重組:Fee sniping 是重組的經濟動機之一
已複製連結