跳至主要內容
進階

ScanTxOutSet

深入了解 Bitcoin Core 的 scantxoutset RPC,快速掃描 UTXO 集合查找特定輸出。

8 分鐘

什麼是 ScanTxOutSet?

scantxoutset 是一個強大的 RPC 命令,可以直接掃描 UTXO 集合 來查找屬於特定地址或描述符的未花費輸出,無需導入錢包或重新掃描區塊鏈。

使用場景

快速餘額查詢

  • • 無需導入地址
  • • 無需重新掃描區塊
  • • 即時獲取結果

錢包恢復驗證

  • • 驗證種子詞的餘額
  • • 查找丟失的資金
  • • 審計地址活動

基本用法

# 掃描單個地址
bitcoin-cli scantxoutset start '["addr(bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq)"]'

# 掃描多個地址
bitcoin-cli scantxoutset start '[
  "addr(bc1q...)",
  "addr(3J98...)",
  "addr(1A1z...)"
]'

# 使用描述符掃描(推薦)
bitcoin-cli scantxoutset start '[
  "wpkh([d34db33f/84h/0h/0h]xpub.../0/*)",
  "wpkh([d34db33f/84h/0h/0h]xpub.../1/*)"
]'

# 輸出示例
{
  "success": true,
  "txouts": 125000000,
  "height": 800000,
  "bestblock": "00000000000000000002...",
  "unspents": [
    {
      "txid": "abc123...",
      "vout": 0,
      "scriptPubKey": "0014...",
      "desc": "wpkh([d34db33f/84'/0'/0'/0/5]02...)#...",
      "amount": 0.5,
      "height": 750000
    }
  ],
  "total_amount": 1.23456789
}

支持的描述符

# 地址
addr(ADDRESS)

# 原始腳本(十六進制)
raw(HEX)

# 公鑰
pk(PUBKEY)

# P2PKH
pkh(PUBKEY)

# P2SH
sh(SCRIPT)

# P2WPKH (Native SegWit)
wpkh(PUBKEY)

# P2WSH
wsh(SCRIPT)

# P2TR (Taproot)
tr(PUBKEY)

# 多簽
multi(K, KEY1, KEY2, ...)
sortedmulti(K, KEY1, KEY2, ...)

# 組合
sh(wpkh(PUBKEY))
sh(wsh(multi(2, KEY1, KEY2, KEY3)))

# 派生路徑(用於 HD 錢包)
wpkh([fingerprint/path]xpub.../0/*)  # 外部地址
wpkh([fingerprint/path]xpub.../1/*)  # 找零地址

派生範圍

# 指定派生範圍
# 格式: "descriptor"#range(START, END)

# 掃描前 100 個地址
bitcoin-cli scantxoutset start '[
  {"desc": "wpkh([d34db33f/84h/0h/0h]xpub.../0/*)", "range": 100}
]'

# 掃描索引 50-150
bitcoin-cli scantxoutset start '[
  {"desc": "wpkh([d34db33f/84h/0h/0h]xpub.../0/*)", "range": [50, 150]}
]'

# 大範圍掃描(尋找丟失資金)
bitcoin-cli scantxoutset start '[
  {"desc": "wpkh([d34db33f/84h/0h/0h]xpub.../0/*)", "range": 10000}
]'

注意: 範圍越大,掃描時間越長。預設範圍是 1000。

掃描控制

# 開始掃描
bitcoin-cli scantxoutset start '[...]'

# 中止掃描
bitcoin-cli scantxoutset abort

# 查看掃描狀態
bitcoin-cli scantxoutset status

# 狀態輸出
{
  "progress": 0.456,   # 0-1 的進度
  "scantype": "start"
}

實用範例

驗證種子詞餘額

# 從種子詞派生 xpub(使用其他工具)
# 然後掃描所有標準派生路徑

# BIP-44 (Legacy)
bitcoin-cli scantxoutset start '[
  {"desc": "pkh([fp/44h/0h/0h]xpub.../0/*)", "range": 100},
  {"desc": "pkh([fp/44h/0h/0h]xpub.../1/*)", "range": 100}
]'

# BIP-49 (Nested SegWit)
bitcoin-cli scantxoutset start '[
  {"desc": "sh(wpkh([fp/49h/0h/0h]xpub.../0/*))", "range": 100},
  {"desc": "sh(wpkh([fp/49h/0h/0h]xpub.../1/*))", "range": 100}
]'

# BIP-84 (Native SegWit)
bitcoin-cli scantxoutset start '[
  {"desc": "wpkh([fp/84h/0h/0h]xpub.../0/*)", "range": 100},
  {"desc": "wpkh([fp/84h/0h/0h]xpub.../1/*)", "range": 100}
]'

# BIP-86 (Taproot)
bitcoin-cli scantxoutset start '[
  {"desc": "tr([fp/86h/0h/0h]xpub.../0/*)", "range": 100},
  {"desc": "tr([fp/86h/0h/0h]xpub.../1/*)", "range": 100}
]'

查找多簽餘額

# 2-of-3 多簽
bitcoin-cli scantxoutset start '[
  "wsh(sortedmulti(2,[fp1/48h/0h/0h/2h]xpub1.../*,[fp2/48h/0h/0h/2h]xpub2.../*,[fp3/48h/0h/0h/2h]xpub3.../*))#checksum"
]'

性能考慮

掃描性能因素:

1. UTXO 集大小
   - 當前約 8000 萬個 UTXO
   - 掃描需要遍歷整個集合

2. 描述符複雜度
   - 簡單地址:最快
   - 單個描述符:快
   - 帶範圍的描述符:需要更多計算

3. 範圍大小
   - 範圍 100:快(秒級)
   - 範圍 1000:中等
   - 範圍 10000+:慢(分鐘級)

4. 硬體
   - SSD vs HDD:顯著差異
   - RAM:更多緩存更快

典型掃描時間(SSD):
- 單個地址:1-5 秒
- 100 個派生地址:5-15 秒
- 1000 個派生地址:30-60 秒

腳本整合

import subprocess
import json

def scan_utxos(descriptors: list) -> dict:
    """掃描 UTXO 集合"""
    cmd = [
        'bitcoin-cli',
        'scantxoutset',
        'start',
        json.dumps(descriptors)
    ]

    result = subprocess.run(cmd, capture_output=True, text=True)
    return json.loads(result.stdout)

def check_balance(xpub: str, path: str = "84'/0'/0'") -> float:
    """檢查 xpub 餘額"""
    descriptors = [
        {"desc": f"wpkh([{path}]{xpub}/0/*)", "range": 100},
        {"desc": f"wpkh([{path}]{xpub}/1/*)", "range": 100},
    ]

    result = scan_utxos(descriptors)
    return result.get('total_amount', 0)

def find_utxos_for_address(address: str) -> list:
    """查找地址的 UTXO"""
    result = scan_utxos([f"addr({address})"])
    return result.get('unspents', [])

# 使用
balance = check_balance("xpub6...")
print(f"餘額: {balance} BTC")

utxos = find_utxos_for_address("bc1q...")
for utxo in utxos:
    print(f"UTXO: {utxo['txid']}:{utxo['vout']} = {utxo['amount']} BTC")

總結

  • 即時查詢:無需導入錢包或重新掃描
  • 描述符支持:支持所有標準描述符類型
  • 範圍掃描:可掃描 HD 錢包的派生地址
  • 注意:大範圍掃描耗時較長
已複製連結
已複製到剪貼簿