Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

區塊鏈錢包技術實現理論 - 企業級系統架構解析

📚 從實際生產環境專案學習區塊鏈錢包技術與理論

來源專案:blockchain-listener-modify 整理日期:2025-11-13

本文檔解析企業級區塊鏈錢包系統的技術架構與設計理念


📑 目錄


1. 系統概述

1.1 系統定位

Blockchain Listener 是一個企業級的區塊鏈監聽與錢包管理系統,專注於:

  • 大規模錢包管理:同時管理數萬個錢包地址
  • 即時交易監聽:毫秒級響應區塊鏈上的轉帳事件
  • 多鏈資產追蹤:統一管理不同區塊鏈的資產
  • 資金自動化整合:智能歸集錢包資金
  • 審計與對帳:提供完整的歷史追蹤

1.2 核心功能模組

┌────────────────────────────────────────────────────────────┐
│              Blockchain Listener 核心架構                   │
├────────────────────────────────────────────────────────────┤
│                                                            │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐       │
│  │  錢包管理    │  │  交易監聽    │  │  餘額追蹤    │       │
│  │  模組        │  │  模組        │  │  模組        │       │
│  └─────────────┘  └─────────────┘  └─────────────┘       │
│                                                            │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐       │
│  │  資金整合    │  │  多鏈支援    │  │  審計對帳    │       │
│  │  模組        │  │  模組        │  │  模組        │       │
│  └─────────────┘  └─────────────┘  └─────────────┘       │
│                                                            │
└────────────────────────────────────────────────────────────┘

1.3 支援的區塊鏈網路

網路名稱符號Chain ID用途
EthereumETH1主網,支援多種 ERC20 代幣
PolygonPOL137Layer 2,低手續費
BNB Smart ChainBSC56幣安生態,交易快速

1.4 支援的代幣類型

Ethereum 網路

  • 原生代幣:ETH
  • ERC20 代幣:USDT、USDC、APE、SHIB、BITO、TON

Polygon 網路

  • 原生代幣:POL (原 MATIC)
  • ERC20 代幣:USDT、USDC、MV

BSC 網路

  • 原生代幣:BNB
  • BEP20 代幣:USDT、USDC

1.5 技術架構總覽

┌──────────────────────────────────────────────────────────────┐
│                    技術架構分層圖                              │
└──────────────────────────────────────────────────────────────┘

    應用層 (Application Layer)
    ┌────────────────────────────────────┐
    │  REST API │ Schedulers │ Consumers │
    └────────────────────────────────────┘
                    ↓
    業務邏輯層 (Service Layer)
    ┌────────────────────────────────────┐
    │  錢包服務 │ 監聽服務 │ 整合服務   │
    └────────────────────────────────────┘
                    ↓
    資料訪問層 (Data Access Layer)
    ┌────────────────────────────────────┐
    │  DAO 模式 │ 資料庫連線池          │
    └────────────────────────────────────┘
                    ↓
    儲存層 (Storage Layer)
    ┌────────────────────────────────────┐
    │  MySQL │ Kafka │ Cache             │
    └────────────────────────────────────┘
                    ↓
    區塊鏈層 (Blockchain Layer)
    ┌────────────────────────────────────┐
    │  Ethereum │ Polygon │ BSC          │
    └────────────────────────────────────┘

2. 錢包管理架構理論

2.1 單例模式 (Singleton Pattern)

設計理念

在整個系統生命週期中,錢包管理器只存在一個實例,提供:

  • 全局統一訪問點:所有模組使用同一份錢包數據
  • 記憶體效率:避免重複載入相同數據
  • 狀態一致性:確保所有查詢使用最新的錢包列表

架構圖

┌─────────────────────────────────────────────────────────┐
│              錢包單例模式架構                             │
└─────────────────────────────────────────────────────────┘

    系統啟動
        ↓
    ┌─────────────────┐
    │ 載入所有錢包地址  │
    │ (一次性從資料庫)  │
    └────────┬────────┘
             ↓
    ┌─────────────────┐
    │  存入記憶體結構   │
    │  • Set (快速查找)│
    │  • Map (屬性映射)│
    └────────┬────────┘
             ↓
    ┌─────────────────────────────────┐
    │      錢包單例 (全局唯一)          │
    │                                 │
    │  worldpayWalletSet              │
    │  ├─ 0x123...                    │
    │  ├─ 0x456...                    │
    │  └─ 0x789...                    │
    │                                 │
    │  bitoproWalletSet               │
    │  ├─ 0xabc...                    │
    │  ├─ 0xdef...                    │
    │  └─ 0xghi...                    │
    │                                 │
    │  worldpayGatewayMap             │
    │  ├─ 0x123... → gatewayId: 5     │
    │  ├─ 0x456... → gatewayId: 3     │
    │  └─ 0x789... → gatewayId: 7     │
    └─────────────────────────────────┘
             ↓
    ┌─────────────────┐
    │  應用各模組使用   │
    │  • 交易監聽      │
    │  • 餘額查詢      │
    │  • 資金整合      │
    └─────────────────┘

2.2 資料結構選擇理論

為什麼使用 Set 和 Map?

Set(集合)特性

集合 (Set) 的特點:
┌─────────────────────────────────────┐
│  特性          │  說明              │
├─────────────────────────────────────┤
│  唯一性        │  自動去重           │
│  查找速度      │  O(1) 時間複雜度    │
│  記憶體效率    │  僅存儲值,無鍵值對  │
│  適用場景      │  快速判斷存在性      │
└─────────────────────────────────────┘

Map(映射)特性

映射 (Map) 的特點:
┌─────────────────────────────────────┐
│  特性          │  說明              │
├─────────────────────────────────────┤
│  鍵值對存儲    │  關聯額外屬性        │
│  查找速度      │  O(1) 時間複雜度    │
│  動態更新      │  易於修改屬性值      │
│  適用場景      │  需要關聯數據的查找  │
└─────────────────────────────────────┘

效能對比分析

假設系統有 10,000 個錢包地址

操作陣列 (Array)SetMap
查找地址是否存在O(n) ≈ 10,000 次比對O(1) ≈ 1 次哈希查找O(1) ≈ 1 次哈希查找
記憶體佔用~420 KB~420 KB~460 KB
新增地址O(1)O(1)O(1)
刪除地址O(n)O(1)O(1)

結論:Set/Map 在大規模錢包管理中效能優勢明顯

2.3 記憶體管理策略

載入策略:分批載入 (Pagination)

分批載入流程:
┌─────────────────────────────────────┐
│  資料庫總數:50,000 個錢包地址       │
└─────────────────────────────────────┘
             ↓
    ┌─────────────────┐
    │  批次 1: 載入     │
    │  Offset: 0       │
    │  Limit: 10,000   │
    └────────┬────────┘
             ↓
    ┌─────────────────┐
    │  批次 2: 載入     │
    │  Offset: 10,000  │
    │  Limit: 10,000   │
    └────────┬────────┘
             ↓
    ┌─────────────────┐
    │  批次 3: 載入     │
    │  Offset: 20,000  │
    │  Limit: 10,000   │
    └────────┬────────┘
             ↓
           ......
             ↓
    ┌─────────────────┐
    │  全部載入完成     │
    │  總數:50,000    │
    └─────────────────┘

優點

  • ✅ 避免單次查詢過大導致資料庫壓力
  • ✅ 防止記憶體瞬間暴增
  • ✅ 可顯示載入進度

2.4 錢包分類管理

雙錢包系統設計

系統將錢包分為兩類,分別管理:

錢包分類架構:
┌─────────────────────────────────────────────┐
│           Worldpay 錢包 (業務錢包)            │
│  • 用途:處理客戶入金                         │
│  • 特性:需要 gatewayId 映射                 │
│  • 數量:~30,000 個                          │
│  • 管理:worldpayWalletSet                  │
│           worldpayGatewayMap                │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│           Bitopro 錢包 (交易所錢包)           │
│  • 用途:交易所充提幣                         │
│  • 特性:無需額外屬性                         │
│  • 數量:~20,000 個                          │
│  • 管理:bitoproWalletSet                   │
└─────────────────────────────────────────────┘

查詢邏輯

地址查詢流程:
輸入:某個地址 (例如 0x123...)
    ↓
┌──────────────────┐
│  檢查是否在       │     是 → 返回 true (Bitopro 錢包)
│  bitoproWalletSet│
└────────┬─────────┘
         ↓ 否
┌──────────────────┐
│  檢查是否在       │     是 → 返回 true (Worldpay 錢包)
│ worldpayWalletSet│          + 取得 gatewayId
└────────┬─────────┘
         ↓ 否
    返回 false (非系統錢包)

3. 錢包地址存儲與查詢設計

3.1 資料庫設計理論

錢包資料表結構

┌──────────────────────────────────────────────┐
│              wallets 資料表                   │
├──────────────────────────────────────────────┤
│  欄位名          │  類型         │  說明      │
├──────────────────────────────────────────────┤
│  id             │  INT          │  主鍵      │
│  address        │  VARCHAR(42)  │  錢包地址   │
│  gateway_id     │  INT          │  閘道 ID   │
│  created_at     │  INT          │  建立時間   │
│  deleted_at     │  INT          │  刪除時間   │
└──────────────────────────────────────────────┘

索引設計:
• PRIMARY KEY (id)
• UNIQUE KEY (address)        ← 確保地址唯一
• INDEX (deleted_at)          ← 軟刪除查詢優化

3.2 軟刪除機制

為什麼使用軟刪除?

硬刪除 vs 軟刪除對比:

硬刪除 (DELETE)
┌─────────────────────────────────┐
│  ✗ 資料永久丟失                  │
│  ✗ 無法恢復誤刪                  │
│  ✗ 失去歷史審計記錄               │
│  ✓ 節省儲存空間                  │
└─────────────────────────────────┘

軟刪除 (UPDATE deleted_at)
┌─────────────────────────────────┐
│  ✓ 資料可恢復                    │
│  ✓ 保留完整歷史                  │
│  ✓ 支援審計追蹤                  │
│  ✓ 符合金融業規範                │
│  ✗ 需要額外儲存空間               │
└─────────────────────────────────┘

軟刪除實現邏輯

正常查詢:
SELECT * FROM wallets WHERE deleted_at IS NULL

軟刪除操作:
UPDATE wallets SET deleted_at = UNIX_TIMESTAMP() WHERE address = ?

查詢已刪除:
SELECT * FROM wallets WHERE deleted_at IS NOT NULL

恢復錢包:
UPDATE wallets SET deleted_at = NULL WHERE address = ?

3.3 地址格式標準化

以太坊地址特性

地址格式:
┌─────────────────────────────────────────┐
│  標準格式:0x + 40 個十六進制字元         │
│  範例:0x742d35Cc6634C0532925a3b844Bc... │
│                                         │
│  關鍵特性:                              │
│  • 不區分大小寫                          │
│  • Checksum 大小寫混合 (EIP-55)         │
│  • 總長度固定 42 字元                    │
└─────────────────────────────────────────┘

地址統一化處理

由於地址不區分大小寫,系統需要統一處理:

統一化流程:
輸入地址: 0xAbC123...DEF789
    ↓
┌──────────────────┐
│  轉換為小寫       │
└────────┬─────────┘
         ↓
輸出地址: 0xabc123...def789
    ↓
存入資料庫 / Set / Map

為什麼選擇小寫?

  • ✅ 簡化查詢邏輯
  • ✅ 避免重複存儲(0xABC... 和 0xabc... 被視為同一地址)
  • ✅ 減少比對錯誤

3.4 批次操作設計

批次新增錢包

批次新增流程:
┌──────────────────────────────────┐
│  輸入:1,000 個錢包地址列表        │
└───────────┬──────────────────────┘
            ↓
    ┌───────────────┐
    │  地址驗證      │
    │  • 格式檢查    │
    │  • 重複檢查    │
    └───────┬───────┘
            ↓
    ┌───────────────┐
    │  統一化處理    │
    │  • 轉小寫      │
    └───────┬───────┘
            ↓
    ┌───────────────┐
    │  批次 INSERT   │
    │  (單次 SQL)    │
    └───────┬───────┘
            ↓
    ┌───────────────┐
    │  更新記憶體     │
    │  (加入 Set)    │
    └───────────────┘

效能優勢

操作方式1,000 個地址耗時資料庫連線數
逐筆 INSERT~5,000 ms1,000 次
批次 INSERT~200 ms1 次

效能提升:~25 倍


4. ERC20 代幣互動原理

4.1 ERC20 標準介面

什麼是 ERC20?

ERC20 (Ethereum Request for Comment 20) 是以太坊上的代幣標準,定義了一組統一的智能合約介面。

核心功能

┌────────────────────────────────────────────┐
│             ERC20 標準介面                  │
├────────────────────────────────────────────┤
│  功能              │  說明                  │
├────────────────────────────────────────────┤
│  balanceOf        │  查詢錢包代幣餘額       │
│  transfer         │  轉帳代幣給他人         │
│  approve          │  授權他人使用代幣       │
│  transferFrom     │  從授權帳戶轉帳         │
│  allowance        │  查詢授權額度           │
│                   │                        │
│  事件              │  說明                  │
├────────────────────────────────────────────┤
│  Transfer         │  轉帳事件(from, to, value)│
│  Approval         │  授權事件               │
└────────────────────────────────────────────┘

4.2 智能合約 ABI (Application Binary Interface)

ABI 的作用

ABI 是什麼?
┌─────────────────────────────────────────┐
│  智能合約的「使用說明書」                 │
│                                         │
│  定義了:                                │
│  • 函數名稱                              │
│  • 參數類型                              │
│  • 返回值類型                            │
│  • 事件結構                              │
└─────────────────────────────────────────┘

Transfer 事件結構

Transfer 事件定義:
┌──────────────────────────────────────┐
│  event Transfer(                     │
│    address indexed from,    ← 轉出方  │
│    address indexed to,      ← 接收方  │
│    uint256 value            ← 金額   │
│  )                                   │
└──────────────────────────────────────┘

為什麼 from 和 to 是 indexed?
• indexed 參數可作為過濾條件
• 快速查詢特定地址的轉帳記錄
• 最多 3 個 indexed 參數

4.3 代幣餘額查詢機制

查詢流程

查詢 USDT 餘額流程:
┌──────────────────────────────────────┐
│  1. 準備查詢參數                      │
│     • 合約地址:USDT 合約             │
│     • 錢包地址:要查詢的地址           │
└───────────┬──────────────────────────┘
            ↓
┌──────────────────────────────────────┐
│  2. 呼叫 balanceOf(address)          │
│     • 這是一個 view 函數              │
│     • 不消耗 Gas                     │
│     • 直接從區塊鏈狀態讀取            │
└───────────┬──────────────────────────┘
            ↓
┌──────────────────────────────────────┐
│  3. 取得原始餘額 (uint256)            │
│     範例:1000000 (6 個零)            │
└───────────┬──────────────────────────┘
            ↓
┌──────────────────────────────────────┐
│  4. 根據 decimals 格式化              │
│     • USDT decimals = 6              │
│     • 1000000 / 10^6 = 1.0 USDT     │
└──────────────────────────────────────┘

Decimals 概念

不同代幣的 Decimals:
┌──────────────────────────────────────┐
│  代幣    │  Decimals  │  範例         │
├──────────────────────────────────────┤
│  ETH    │  18        │  1 ETH = 10^18 Wei        │
│  USDT   │  6         │  1 USDT = 10^6 單位       │
│  USDC   │  6         │  1 USDC = 10^6 單位       │
│  WBTC   │  8         │  1 WBTC = 10^8 Satoshi    │
└──────────────────────────────────────┘

為什麼需要 Decimals?
• 區塊鏈只能處理整數
• Decimals 定義「小數點位置」
• 1.5 USDT 實際存為 1500000

4.4 Transfer 事件監聽

事件監聽原理

事件監聽流程:
┌──────────────────────────────────────┐
│  1. 定義監聽範圍                      │
│     • 合約地址:USDT                 │
│     • 起始區塊:100000               │
│     • 結束區塊:100100               │
└───────────┬──────────────────────────┘
            ↓
┌──────────────────────────────────────┐
│  2. 查詢 Transfer 事件                │
│     • 使用 getPastEvents             │
│     • 或直接查詢 Logs                │
└───────────┬──────────────────────────┘
            ↓
┌──────────────────────────────────────┐
│  3. 解析事件參數                      │
│     Event {                          │
│       from: 0x123...                 │
│       to: 0x456...                   │
│       value: 1000000                 │
│       transactionHash: 0xabc...      │
│       blockNumber: 100050            │
│     }                                │
└───────────┬──────────────────────────┘
            ↓
┌──────────────────────────────────────┐
│  4. 過濾系統關心的事件                 │
│     • 檢查 to 是否為系統錢包          │
│     • 是 → 記錄並處理                │
│     • 否 → 忽略                      │
└──────────────────────────────────────┘

分批查詢策略

由於 RPC 節點對單次查詢的區塊範圍有限制(通常 1000-5000 個區塊),需要分批查詢:

分批查詢示意:
目標:查詢區塊 10000 到 15000 的 Transfer 事件
分批大小:100 區塊

    查詢 1: 10000 → 10099
    查詢 2: 10100 → 10199
    查詢 3: 10200 → 10299
    ...
    查詢 50: 14900 → 14999
    查詢 51: 15000 → 15000

    合併所有結果 → 完整事件列表

5. 區塊鏈 RPC 互動機制

5.1 RPC (Remote Procedure Call) 原理

什麼是 RPC?

RPC 通信模型:
┌────────────────┐        ┌────────────────┐
│  客戶端         │        │  區塊鏈節點     │
│  (你的應用)     │        │  (Ethereum)    │
│                │        │                │
│  1. 發送請求    │───────>│  3. 執行操作    │
│     (JSON-RPC) │        │                │
│                │        │  4. 準備回應    │
│  2. 等待回應    │<───────│                │
│                │        │                │
│  5. 處理結果    │        │                │
└────────────────┘        └────────────────┘

JSON-RPC 格式

請求範例:查詢區塊高度
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}

回應範例:
{
  "jsonrpc": "2.0",
  "result": "0x10d4f",  // 十六進制區塊號
  "id": 1
}

5.2 常用 RPC 方法

┌──────────────────────────────────────────────┐
│           常用 RPC 方法分類                    │
├──────────────────────────────────────────────┤
│  區塊相關                                     │
│  • eth_blockNumber        取得最新區塊號      │
│  • eth_getBlockByNumber   取得區塊詳情        │
│                                              │
│  交易相關                                     │
│  • eth_getTransactionByHash    查詢交易       │
│  • eth_getTransactionReceipt   查詢交易收據   │
│  • eth_sendRawTransaction      廣播交易       │
│                                              │
│  帳戶相關                                     │
│  • eth_getBalance             查詢餘額        │
│  • eth_getTransactionCount    查詢 nonce     │
│                                              │
│  合約相關                                     │
│  • eth_call                   呼叫合約函數    │
│  • eth_getLogs                查詢事件日誌    │
│                                              │
│  進階功能                                     │
│  • debug_traceTransaction     追蹤內部調用    │
└──────────────────────────────────────────────┘

5.3 多 RPC 節點備援機制

為什麼需要多節點?

單節點風險:
┌─────────────────────────────────┐
│  ✗ 節點故障 → 系統停擺           │
│  ✗ 速率限制 → 請求失敗           │
│  ✗ 網路延遲 → 響應緩慢           │
│  ✗ 節點維護 → 服務中斷           │
└─────────────────────────────────┘

多節點優勢:
┌─────────────────────────────────┐
│  ✓ 故障轉移                      │
│  ✓ 負載均衡                      │
│  ✓ 速率限制分散                  │
│  ✓ 高可用性                      │
└─────────────────────────────────┘

多節點架構

多 RPC 節點配置:
┌──────────────────────────────────────┐
│  Ethereum 網路 (networkId: 1)         │
├──────────────────────────────────────┤
│  節點 1 (Priority: 1)                │
│  • Alchemy                           │
│  • 速度快、穩定性高                   │
│  • 有速率限制                         │
├──────────────────────────────────────┤
│  節點 2 (Priority: 2)                │
│  • LlamaRPC                          │
│  • 免費、無速率限制                   │
│  • 可能較慢                           │
├──────────────────────────────────────┤
│  節點 3 (Priority: 3)                │
│  • Ankr                              │
│  • 備用節點                           │
│  • 故障時使用                         │
└──────────────────────────────────────┘

節點切換邏輯

節點切換流程:
┌─────────────────┐
│  使用節點 1      │
│  (最高優先級)    │
└────────┬────────┘
         ↓
    ┌────────┐
    │ 請求成功│ ─ 是 → 返回結果
    └───┬────┘
        ↓ 否
┌───────────────┐
│  錯誤類型?     │
└───┬───────────┘
    ↓
┌─────────────────┐    是   ┌─────────────┐
│  速率限制?      │ ────→  │  切換節點 2  │
└─────────────────┘        └─────────────┘
    ↓ 否
┌─────────────────┐    是   ┌─────────────┐
│  連線超時?      │ ────→  │  切換節點 2  │
└─────────────────┘        └─────────────┘
    ↓ 否
┌─────────────────┐    是   ┌─────────────┐
│  節點維護?      │ ────→  │  切換節點 2  │
└─────────────────┘        └─────────────┘
    ↓ 否
    拋出錯誤

5.4 Web3.js vs Ethers.js 選擇

兩個函式庫的定位

┌─────────────────────────────────────────────┐
│              Web3.js                        │
├─────────────────────────────────────────────┤
│  優勢:                                      │
│  • 更早期,生態成熟                          │
│  • 事件監聽功能完善                          │
│  • getPastEvents 方法方便                   │
│                                             │
│  適用場景:                                  │
│  • 合約事件監聽                              │
│  • 需要向下相容舊專案                        │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│              Ethers.js                      │
├─────────────────────────────────────────────┤
│  優勢:                                      │
│  • 更輕量 (~88 KB vs ~200 KB)               │
│  • 錯誤處理更友善                            │
│  • TypeScript 原生支援                      │
│  • 交易簽名更安全                            │
│                                             │
│  適用場景:                                  │
│  • 交易廣播與簽名                            │
│  • 新專案開發                                │
│  • TypeScript 專案                          │
└─────────────────────────────────────────────┘

專案中的使用策略

功能分工:
┌────────────────────────────────────┐
│  監聽 ERC20 Transfer 事件           │
│  → 使用 Web3.js                    │
│     理由:getPastEvents 更直觀      │
└────────────────────────────────────┘

┌────────────────────────────────────┐
│  廣播簽名交易                       │
│  → 使用 Ethers.js                  │
│     理由:錯誤處理更完善             │
└────────────────────────────────────┘

┌────────────────────────────────────┐
│  查詢區塊、交易資訊                 │
│  → 兩者皆可                         │
│     根據專案習慣選擇                │
└────────────────────────────────────┘

6. 交易監聽與處理流程

6.1 交易監聽架構設計

雙軌監聽系統

系統使用兩種方式監聽交易:

┌──────────────────────────────────────────┐
│         ERC20 代幣轉帳監聽                │
│         (Token Transfer Listener)        │
├──────────────────────────────────────────┤
│  監聽方式:查詢 Transfer 事件             │
│  監聽對象:USDT、USDC、APE 等             │
│  監聽頻率:每 30 秒                       │
│  資料來源:eth_getLogs                   │
└──────────────────────────────────────────┘

┌──────────────────────────────────────────┐
│         原生代幣轉帳監聽                   │
│         (Native Transfer Listener)       │
├──────────────────────────────────────────┤
│  監聽方式:逐區塊掃描交易                 │
│  監聽對象:ETH、POL、BNB                 │
│  監聽頻率:每 15 秒                       │
│  資料來源:eth_getBlockByNumber          │
│          + debug_traceTransaction        │
└──────────────────────────────────────────┘

6.2 ERC20 監聽流程詳解

完整監聽流程

ERC20 Transfer 監聽週期:
┌─────────────────────────────────────┐
│  1. 讀取上次掃描位置                 │
│     • 從 last_block_numbers 表      │
│     • 取得 networkId + tokenId      │
│     • 範例:上次掃描到區塊 10000     │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  2. 查詢當前區塊高度                 │
│     • 呼叫 eth_blockNumber          │
│     • 範例:當前區塊 10100          │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  3. 計算掃描範圍                     │
│     • fromBlock: 10001              │
│     • toBlock: 10100                │
│     • 共 100 個區塊                 │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  4. 查詢 Transfer 事件               │
│     • 使用 getPastEvents('Transfer')│
│     • 過濾合約地址                   │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  5. 逐個事件處理                     │
│     For each event:                 │
│       • 解析 from、to、value        │
│       • 檢查 to 是否為系統錢包       │
│       • 是 → 發送到 Kafka           │
│       • 否 → 忽略                   │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  6. 更新掃描位置                     │
│     • 更新 last_block_numbers       │
│     • 設為 10100                    │
└───────────┬─────────────────────────┘
            ↓
    等待 30 秒,重複流程

6.3 原生代幣監聽流程

為什麼更複雜?

原生代幣(ETH/POL/BNB)的轉帳不會產生事件,需要:

  1. 掃描每個區塊的所有交易
  2. 使用 debug_traceTransaction 追蹤內部轉帳

內部轉帳 (Internal Transaction) 概念

什麼是內部轉帳?
┌──────────────────────────────────────┐
│  外部交易 (External Transaction)     │
│  • 用戶直接發起的轉帳                 │
│  • 在交易列表中可見                   │
│  • 範例:Alice 轉 1 ETH 給 Bob       │
└──────────────────────────────────────┘

┌──────────────────────────────────────┐
│  內部交易 (Internal Transaction)     │
│  • 智能合約執行過程中的轉帳           │
│  • 不在交易列表中顯示                 │
│  • 需要 trace 才能發現                │
│  • 範例:DeFi 合約分配收益給用戶      │
└──────────────────────────────────────┘

內部轉帳追蹤流程

debug_traceTransaction 流程:
┌─────────────────────────────────────┐
│  1. 發現一筆交易                     │
│     txHash: 0xabc123...             │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  2. 呼叫 debug_traceTransaction     │
│     • 重新執行交易                   │
│     • 記錄每一步操作                 │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  3. 分析 trace 結果                  │
│     Trace {                         │
│       type: "CALL",                 │
│       from: "0x123...",             │
│       to: "0x456...",               │
│       value: "1000000000000000000", │
│       gas: 21000,                   │
│       gasUsed: 21000                │
│     }                               │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  4. 提取所有轉帳操作                 │
│     • 可能有多層調用                 │
│     • 合約 A → 合約 B → 用戶         │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  5. 檢查是否涉及系統錢包             │
│     • 檢查每個 to 地址               │
│     • 匹配 → 記錄                   │
└─────────────────────────────────────┘

6.4 Kafka 異步處理架構

為什麼使用 Kafka?

同步處理 vs 異步處理:

同步處理 (不推薦)
┌─────────────────────────────────┐
│  監聽 → 處理 → 儲存 → 更新餘額   │
│  ✗ 阻塞監聽流程                  │
│  ✗ 處理慢導致漏掉區塊             │
│  ✗ 無法擴展                      │
└─────────────────────────────────┘

異步處理 (Kafka)
┌─────────────────────────────────┐
│  監聽 → 發送到 Kafka             │
│         ↓                       │
│  Consumer 處理 (獨立進程)        │
│  ✓ 監聽不阻塞                    │
│  ✓ 可以延遲處理                  │
│  ✓ 可以水平擴展 Consumer         │
│  ✓ 訊息不會丟失                  │
└─────────────────────────────────┘

Kafka 訊息流

Kafka 訊息處理流程:
┌─────────────────────────────────────────┐
│  Scheduler (生產者)                      │
│  • ERC20 Transfer Scheduler             │
│  • Native Transfer Scheduler            │
└───────────┬─────────────────────────────┘
            ↓ 發送訊息
┌─────────────────────────────────────────┐
│  Kafka Topic: blockchain-listener-rescan│
│                                         │
│  訊息格式:                              │
│  {                                      │
│    networkId: 1,                        │
│    tokenId: 2,                          │
│    transactionHash: "0xabc...",         │
│    to: "0x123...",                      │
│    value: "1000000"                     │
│  }                                      │
└───────────┬─────────────────────────────┘
            ↓ 消費訊息
┌─────────────────────────────────────────┐
│  Rescan Consumer (消費者)                │
│  • 查詢完整交易資料                      │
│  • 儲存到 received_transactions         │
│  • 發送餘額更新訊息                      │
└───────────┬─────────────────────────────┘
            ↓
┌─────────────────────────────────────────┐
│  Kafka Topic: blockchain-listener-balance│
└───────────┬─────────────────────────────┘
            ↓
┌─────────────────────────────────────────┐
│  Balance Consumer (消費者)               │
│  • 查詢鏈上餘額                          │
│  • 更新 wallet_balances                 │
└─────────────────────────────────────────┘

6.5 區塊掃描狀態管理

last_block_numbers 資料表

掃描狀態記錄:
┌──────────────────────────────────────┐
│  network_id │ token_id │ block_number│
├──────────────────────────────────────┤
│      1      │    2     │   10000     │  ← ETH USDT
│      1      │    3     │   10050     │  ← ETH USDC
│      1      │    0     │   9950      │  ← ETH 原生
│      2      │    0     │   5000      │  ← Polygon 原生
│      2      │    5     │   5100      │  ← Polygon USDT
└──────────────────────────────────────┘

作用:
• 系統重啟後從上次位置繼續
• 避免重複掃描
• 支援多 Scheduler 並行

7. 錢包餘額管理機制

7.1 餘額資料模型

雙層儲存架構

┌─────────────────────────────────────────┐
│      即時餘額表 (wallet_balances)        │
├─────────────────────────────────────────┤
│  用途:儲存最新的錢包餘額                 │
│  更新:每次收到轉帳後更新                 │
│  查詢:提供給前端 API 快速查詢            │
│                                         │
│  結構:                                  │
│  • wallet_id (錢包 ID)                  │
│  • network_id (網路 ID)                 │
│  • token_id (代幣 ID)                   │
│  • balance (餘額,Wei 格式)              │
│  • updated_at (更新時間)                │
│                                         │
│  唯一約束:(wallet_id, network_id, token_id)│
└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐
│   歷史快照表 (wallet_balance_snapshots)  │
├─────────────────────────────────────────┤
│  用途:審計與對帳                         │
│  更新:定時(每日)建立快照               │
│  查詢:用於歷史資料分析                   │
│                                         │
│  結構:                                  │
│  • wallet_id                            │
│  • network_id                           │
│  • token_id                             │
│  • balance                              │
│  • snapshot_at (快照時間戳)              │
│  • created_at (記錄建立時間)             │
└─────────────────────────────────────────┘

7.2 餘額更新流程

觸發時機

什麼時候更新餘額?
┌─────────────────────────────────────┐
│  1. 接收到轉帳                       │
│     • Rescan Consumer 處理完交易     │
│     • 發送餘額更新訊息到 Kafka       │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  2. 手動觸發查詢                     │
│     • 管理員透過 API 請求            │
│     • 對帳時批次更新                 │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  3. 定時全量更新                     │
│     • 每日凌晨 3:00                  │
│     • 確保數據準確性                 │
└─────────────────────────────────────┘

更新流程詳解

餘額更新完整流程:
┌─────────────────────────────────────┐
│  1. 接收更新請求                     │
│     From: Kafka balance topic       │
│     Data: {                         │
│       walletAddress: "0x123...",    │
│       networkId: 1,                 │
│       tokenId: 2                    │
│     }                               │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  2. 查詢鏈上餘額                     │
│     IF tokenId == 0:                │
│       → 呼叫 eth_getBalance         │
│     ELSE:                           │
│       → 呼叫 ERC20 balanceOf        │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  3. 取得原始餘額                     │
│     範例:                           │
│     • USDT: "1500000" (6 decimals)  │
│     • 代表 1.5 USDT                 │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  4. 更新資料庫                       │
│     • 查找現有記錄                   │
│     • 存在 → UPDATE                 │
│     • 不存在 → INSERT               │
│     • 更新 updated_at               │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  5. 記錄變更日誌                     │
│     • 舊餘額 vs 新餘額               │
│     • 變化量                         │
│     • 變化原因(txHash)             │
└─────────────────────────────────────┘

7.3 餘額格式化處理

Wei / 原始單位 概念

為什麼鏈上存儲的是「大整數」?
┌─────────────────────────────────────┐
│  區塊鏈特性:                         │
│  • 只能處理整數運算                   │
│  • 浮點數會有精度問題                 │
│  • 使用「最小單位」存儲               │
└─────────────────────────────────────┘

單位轉換範例:
┌─────────────────────────────────────┐
│  ETH (18 decimals)                  │
│  • 鏈上:1000000000000000000 Wei    │
│  • 顯示:1.0 ETH                    │
│  • 計算:value / 10^18              │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  USDT (6 decimals)                  │
│  • 鏈上:1500000                    │
│  • 顯示:1.5 USDT                   │
│  • 計算:value / 10^6               │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  WBTC (8 decimals)                  │
│  • 鏈上:150000000                  │
│  • 顯示:1.5 WBTC                   │
│  • 計算:value / 10^8               │
└─────────────────────────────────────┘

數值精度處理

大數值問題:
┌─────────────────────────────────────┐
│  JavaScript Number 類型限制:         │
│  • 最大安全整數:2^53 - 1            │
│  • ETH 最小單位:10^18               │
│  • 會發生精度丟失!                   │
└─────────────────────────────────────┘

解決方案:使用 BigInt 或字串
┌─────────────────────────────────────┐
│  資料庫存儲:VARCHAR(78)             │
│  • 足夠存儲 uint256 最大值           │
│  • 避免數值溢出                      │
│                                     │
│  計算時:使用 BigInt 或 BigNumber    │
│  • Ethers.js: BigNumber             │
│  • JavaScript: BigInt               │
│                                     │
│  顯示時:格式化為 decimal string     │
│  • 使用 formatUnits(value, decimals)│
└─────────────────────────────────────┘

7.4 餘額快照機制

為什麼需要快照?

快照的用途:
┌─────────────────────────────────────┐
│  1. 審計追蹤                         │
│     • 每日記錄所有錢包餘額            │
│     • 可追溯任意時間點的資產狀況      │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  2. 對帳驗證                         │
│     • 鏈上餘額 vs 資料庫餘額         │
│     • 發現數據不一致                 │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  3. 財務報表                         │
│     • 每日資產總量統計                │
│     • 資產變動趨勢分析                │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  4. 合規要求                         │
│     • 金融業務需要完整記錄            │
│     • 監管機構可能要求提供            │
└─────────────────────────────────────┘

快照生成流程

每日快照生成流程:
┌─────────────────────────────────────┐
│  時間:每日 03:00 (UTC)              │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  1. 查詢所有活躍錢包                 │
│     • 從 wallets 表                 │
│     • WHERE deleted_at IS NULL      │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  2. 批次查詢鏈上餘額                 │
│     For each wallet:                │
│       • 查詢所有支援的 token         │
│       • ETH, USDT, USDC...          │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  3. 記錄快照                         │
│     INSERT INTO                     │
│     wallet_balance_snapshots        │
│     • snapshot_at = UNIX_TIMESTAMP()│
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  4. 生成對帳報告                     │
│     • 總資產統計                     │
│     • 與昨日比較                     │
│     • 異常告警                       │
└─────────────────────────────────────┘

8. 加密與安全理論

8.1 AES 加密原理

AES (Advanced Encryption Standard)

AES-128-ECB 模式:
┌─────────────────────────────────────┐
│  演算法:AES                         │
│  金鑰長度:128 bits (16 bytes)       │
│  加密模式:ECB (Electronic Codebook) │
│  區塊大小:128 bits                  │
└─────────────────────────────────────┘

加密流程

加密過程:
明文 (Plaintext)
    ↓
┌─────────────────┐
│  轉換為 bytes    │
└────────┬────────┘
         ↓
┌─────────────────┐
│  金鑰擴展        │
│  • 128 bit key  │
│  • 生成輪密鑰    │
└────────┬────────┘
         ↓
┌─────────────────┐
│  AES 加密        │
│  • 10 輪運算     │
│  • SubBytes     │
│  • ShiftRows    │
│  • MixColumns   │
│  • AddRoundKey  │
└────────┬────────┘
         ↓
密文 (Ciphertext)
    ↓
轉為十六進制字串

金鑰轉換機制

專案使用自定義的金鑰轉換演算法:

金鑰轉換流程:
輸入金鑰:"MySecretPassword"
    ↓
┌─────────────────────────────────────┐
│  1. 初始化 16 bytes 緩衝區           │
│     [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]│
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  2. 將輸入金鑰轉為 bytes             │
│     "MySecretPassword" → bytes[]    │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  3. XOR 運算                         │
│     For i in keyBytes:              │
│       buffer[i % 16] ^= keyBytes[i] │
│                                     │
│     效果:任意長度密碼 → 16 bytes    │
└───────────┬─────────────────────────┘
            ↓
    最終 16 bytes 金鑰

為什麼使用 XOR?

XOR 特性:
┌─────────────────────────────────────┐
│  可逆性:                            │
│  • A XOR B = C                      │
│  • C XOR B = A                      │
│  • 加密和解密使用相同運算            │
│                                     │
│  混淆性:                            │
│  • 密碼每個字元影響多個位置          │
│  • 增加破解難度                      │
└─────────────────────────────────────┘

8.2 敏感資料保護策略

分層保護架構

┌─────────────────────────────────────┐
│  第一層:環境變數隔離                 │
│  • 私鑰、API Key 不寫入程式碼        │
│  • 使用 .env 檔案                   │
│  • .env 加入 .gitignore             │
└─────────────────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  第二層:資料庫加密存儲               │
│  • 私鑰使用 AES 加密後存儲            │
│  • 加密金鑰存在環境變數               │
│  • 資料庫洩露也無法直接使用           │
└─────────────────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  第三層:記憶體內使用                 │
│  • 需要時才解密到記憶體               │
│  • 使用後立即清除                    │
│  • 避免記憶體 dump 洩露              │
└─────────────────────────────────────┘

私鑰管理最佳實踐

私鑰生命週期管理:
┌─────────────────────────────────────┐
│  1. 生成階段                         │
│     • 使用硬體隨機數生成器            │
│     • 立即加密                       │
│     • 安全傳輸給管理員                │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  2. 存儲階段                         │
│     • 加密後存入資料庫                │
│     • 或使用 HSM (硬體安全模組)       │
│     • 設定存取權限                    │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  3. 使用階段                         │
│     • 臨時解密到記憶體                │
│     • 簽名交易                       │
│     • 立即從記憶體清除                │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  4. 輪換階段                         │
│     • 定期生成新錢包                 │
│     • 遷移資金                       │
│     • 銷毀舊私鑰                     │
└─────────────────────────────────────┘

8.3 交易簽名安全

本地簽名 vs 遠程簽名

本地簽名 (推薦)
┌─────────────────────────────────────┐
│  流程:                              │
│  1. 建構交易參數                     │
│  2. 本地使用私鑰簽名                 │
│  3. 廣播已簽名交易                   │
│                                     │
│  優點:                              │
│  ✓ 私鑰不離開服務器                  │
│  ✓ 完全控制簽名過程                  │
│  ✓ 可離線簽名                        │
└─────────────────────────────────────┘

遠程簽名 (不推薦)
┌─────────────────────────────────────┐
│  流程:                              │
│  1. 發送未簽名交易到節點             │
│  2. 節點使用私鑰簽名                 │
│  3. 節點廣播交易                     │
│                                     │
│  風險:                              │
│  ✗ 私鑰存在遠程節點                  │
│  ✗ 依賴第三方安全性                  │
│  ✗ 網路攔截風險                      │
└─────────────────────────────────────┘

簽名流程詳解

交易簽名完整流程:
┌─────────────────────────────────────┐
│  1. 準備交易參數                     │
│     {                               │
│       to: "0x456...",               │
│       value: "1000000000000000000", │
│       gasLimit: 21000,              │
│       gasPrice: "20000000000",      │
│       nonce: 5,                     │
│       chainId: 1                    │
│     }                               │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  2. RLP 編碼                         │
│     • Recursive Length Prefix       │
│     • 以太坊標準序列化格式            │
│     • 將交易轉為 bytes               │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  3. Keccak-256 哈希                 │
│     • 計算交易哈希                   │
│     • txHash = keccak256(rlpEncode) │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  4. ECDSA 簽名                       │
│     • 使用私鑰簽名 txHash            │
│     • 產生 (r, s, v) 簽名            │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  5. 組合簽名交易                     │
│     • RLP(tx + signature)           │
│     • 產生 rawTransaction           │
└───────────┬─────────────────────────┘
            ↓
┌─────────────────────────────────────┐
│  6. 廣播交易                         │
│     • eth_sendRawTransaction        │
│     • 無需私鑰                       │
└─────────────────────────────────────┘

8.4 API 安全防護

認證與授權

多層認證機制:
┌─────────────────────────────────────┐
│  第一層:Session 認證                │
│  • 用戶登入後建立 session            │
│  • 每次請求檢查 session 有效性        │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  第二層:OTP (一次性密碼)             │
│  • 敏感操作需要 OTP 驗證             │
│  • 例如:刪除錢包、轉帳              │
│  • 使用 TOTP (Time-based OTP)       │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  第三層:IP 白名單                    │
│  • 限制允許訪問的 IP                 │
│  • 防止未授權訪問                    │
└─────────────────────────────────────┘

輸入驗證

完整的輸入驗證流程:
┌─────────────────────────────────────┐
│  1. 格式驗證                         │
│     • 地址必須是有效的 Ethereum 地址  │
│     • 金額必須是正數                 │
│     • 欄位長度限制                   │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  2. 類型驗證                         │
│     • 字串 vs 數字                   │
│     • 防止類型混淆攻擊                │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  3. 範圍驗證                         │
│     • 金額不能超過餘額                │
│     • nonce 合理性檢查               │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  4. 業務邏輯驗證                     │
│     • 錢包是否存在                   │
│     • 是否有操作權限                 │
└─────────────────────────────────────┘

9. 多鏈支援架構設計

9.1 統一抽象層設計

為什麼需要統一介面?

多鏈差異:
┌─────────────────────────────────────┐
│  Ethereum                           │
│  • Chain ID: 1                      │
│  • 區塊時間:~12 秒                  │
│  • Gas 單位:Gwei                   │
│  • 原生代幣:ETH (18 decimals)       │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  Polygon                            │
│  • Chain ID: 137                    │
│  • 區塊時間:~2 秒                   │
│  • Gas 單位:Gwei                   │
│  • 原生代幣:POL (18 decimals)       │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  BSC                                │
│  • Chain ID: 56                     │
│  • 區塊時間:~3 秒                   │
│  • Gas 單位:Gwei                   │
│  • 原生代幣:BNB (18 decimals)       │
└─────────────────────────────────────┘

統一抽象後:
所有鏈使用相同的介面,差異由配置決定

統一介面設計

統一的區塊鏈操作介面:
┌─────────────────────────────────────┐
│  getBalance(network, wallet, token) │
│  • network 參數決定使用哪個 RPC      │
│  • token 參數決定查詢原生或 ERC20    │
│  • 返回格式統一                      │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  monitorTransfers(network, token)   │
│  • 根據 network 選擇 RPC             │
│  • 根據 token 決定監聽方式           │
│  • 統一的事件處理邏輯                │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  sendTransaction(network, tx)       │
│  • 自動選擇對應的 RPC                │
│  • 統一的簽名流程                    │
│  • 統一的錯誤處理                    │
└─────────────────────────────────────┘

9.2 配置驅動架構

網路配置表

網路配置資料模型:
┌──────────────────────────────────────┐
│  networks 資料表                      │
├──────────────────────────────────────┤
│  id   │ name      │ symbol │ chain_id│
│  1    │ Ethereum  │ ETH    │ 1       │
│  2    │ Polygon   │ POL    │ 137     │
│  3    │ BSC       │ BSC    │ 56      │
└──────────────────────────────────────┘

新增網路步驟:
1. INSERT INTO networks
2. INSERT INTO network_rpcs (配置 RPC 節點)
3. 重啟 Scheduler
4. 無需修改程式碼!

代幣配置表

代幣配置資料模型:
┌───────────────────────────────────────────────┐
│  tokens 資料表                                 │
├───────────────────────────────────────────────┤
│  network_id │ symbol │ contract │ decimals   │
│  1          │ ETH    │ NULL     │ 18         │  ← 原生
│  1          │ USDT   │ 0xdac... │ 6          │  ← ERC20
│  1          │ USDC   │ 0xa0b... │ 6          │
│  2          │ POL    │ NULL     │ 18         │  ← 原生
│  2          │ USDT   │ 0xc21... │ 6          │  ← ERC20
└───────────────────────────────────────────────┘

判斷邏輯:
IF contract_address IS NULL:
  → 原生代幣,使用 eth_getBalance
ELSE:
  → ERC20 代幣,使用 balanceOf

9.3 多鏈並行處理

獨立 Scheduler 設計

多 Scheduler 並行架構:
┌─────────────────────────────────────┐
│  Scheduler 1: ETH USDT              │
│  • networkId: 1, tokenId: 2         │
│  • 獨立進程                          │
│  • 掃描進度獨立                      │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  Scheduler 2: ETH USDC              │
│  • networkId: 1, tokenId: 3         │
│  • 獨立進程                          │
│  • 與 Scheduler 1 不互相影響         │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  Scheduler 3: Polygon USDT          │
│  • networkId: 2, tokenId: 5         │
│  • 獨立進程                          │
│  • 可部署在不同服務器                │
└─────────────────────────────────────┘

優點:
✓ 一個鏈故障不影響其他鏈
✓ 可根據負載調整資源
✓ 易於水平擴展

進程管理策略

進程分配建議:
┌─────────────────────────────────────┐
│  高頻代幣 (ETH USDT, ETH USDC)       │
│  • 獨立服務器                        │
│  • 更多 CPU 和記憶體資源             │
│  • 低掃描延遲                        │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  中頻代幣 (Polygon USDT)             │
│  • 共享服務器                        │
│  • 適中資源配置                      │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  低頻代幣 (小眾 ERC20)               │
│  • 多個 Scheduler 共享一臺服務器     │
│  • 較長掃描間隔                      │
└─────────────────────────────────────┘

9.4 跨鏈統一查詢

統一餘額查詢 API

API 設計:
GET /api/wallet/balance?address=0x123...

回應格式:
{
  "success": true,
  "address": "0x123...",
  "balances": [
    {
      "network": "ETH",
      "token": "ETH",
      "balance": "1.5",
      "valueUSD": "3000"
    },
    {
      "network": "ETH",
      "token": "USDT",
      "balance": "500",
      "valueUSD": "500"
    },
    {
      "network": "Polygon",
      "token": "POL",
      "balance": "100",
      "valueUSD": "50"
    }
  ],
  "totalUSD": "3550"
}

特點:
• 一次請求查詢所有鏈
• 統一格式化
• 自動計算美元價值

10. 系統整合與協作

10.1 整體架構回顧

完整資料流

端到端資料流程:
┌──────────────────────────────────────────────┐
│  區塊鏈層 (Blockchain Layer)                  │
│  • Ethereum Mainnet                          │
│  • Polygon Mainnet                           │
│  • BSC Mainnet                               │
└────────────┬─────────────────────────────────┘
             ↓ RPC 查詢
┌──────────────────────────────────────────────┐
│  監聽層 (Listener Layer)                      │
│  • ERC20 Transfer Schedulers (11 個進程)      │
│  • Native Transfer Schedulers (3 個進程)      │
│  • Consolidate Scheduler (1 個進程)           │
└────────────┬─────────────────────────────────┘
             ↓ 發送到 Kafka
┌──────────────────────────────────────────────┐
│  消息隊列層 (Message Queue Layer)             │
│  • Kafka Topic: rescan                       │
│  • Kafka Topic: balance                      │
│  • Kafka Topic: priority-rescan              │
└────────────┬─────────────────────────────────┘
             ↓ Consumer 消費
┌──────────────────────────────────────────────┐
│  處理層 (Processing Layer)                    │
│  • Rescan Consumer (2-4 個進程)               │
│  • Balance Consumer (1-2 個進程)              │
│  • Priority Rescan Consumer (1 個進程)        │
└────────────┬─────────────────────────────────┘
             ↓ 寫入資料庫
┌──────────────────────────────────────────────┐
│  儲存層 (Storage Layer)                       │
│  • MySQL: wallets, balances, transactions    │
│  • Cache: 熱點數據快取                        │
└────────────┬─────────────────────────────────┘
             ↓ API 查詢
┌──────────────────────────────────────────────┐
│  服務層 (Service Layer)                       │
│  • REST API (Express.js)                     │
│  • Swagger 文件                               │
└────────────┬─────────────────────────────────┘
             ↓
        外部系統 / 前端

10.2 錯誤處理與容錯

分層錯誤處理

錯誤處理策略:
┌─────────────────────────────────────┐
│  RPC 層錯誤                          │
│  • 連線超時 → 切換備用節點            │
│  • 速率限制 → 延遲重試               │
│  • 節點同步中 → 等待或切換            │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  Kafka 層錯誤                        │
│  • 連線失敗 → 自動重連               │
│  • 消息處理失敗 → 重試 3 次          │
│  • 超過重試 → 記錄到死信隊列         │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  資料庫層錯誤                        │
│  • 連線池耗盡 → 等待可用連線         │
│  • 死鎖 → 自動重試                   │
│  • 主鍵衝突 → 忽略(冪等性設計)     │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  業務層錯誤                          │
│  • 餘額不足 → 返回明確錯誤           │
│  • 錢包不存在 → 404 錯誤             │
│  • 權限不足 → 403 錯誤               │
└─────────────────────────────────────┘

重試機制

指數退避重試:
嘗試 1: 立即重試
         ↓ 失敗
嘗試 2: 等待 1 秒
         ↓ 失敗
嘗試 3: 等待 2 秒
         ↓ 失敗
嘗試 4: 等待 4 秒
         ↓ 失敗
嘗試 5: 等待 8 秒
         ↓ 失敗
放棄,記錄錯誤

10.3 效能監控

關鍵指標

監控指標分類:
┌─────────────────────────────────────┐
│  Scheduler 指標                      │
│  • 掃描區塊速度 (blocks/min)         │
│  • 發現事件數量                      │
│  • RPC 請求延遲                      │
│  • 錯誤率                            │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  Consumer 指標                       │
│  • 消息處理速度 (msgs/sec)           │
│  • 消息積壓數量 (lag)                │
│  • 處理成功率                        │
│  • 平均處理時間                      │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  資料庫指標                          │
│  • 查詢響應時間                      │
│  • 連線池使用率                      │
│  • 慢查詢數量                        │
│  • 錯誤率                            │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  API 指標                            │
│  • 請求數 (QPS)                      │
│  • 響應時間 (P50, P95, P99)          │
│  • 錯誤率                            │
│  • 並發連線數                        │
└─────────────────────────────────────┘

10.4 擴展性設計

水平擴展策略

擴展點:
┌─────────────────────────────────────┐
│  1. Scheduler 擴展                   │
│     • 每個代幣獨立進程                │
│     • 可部署到不同服務器              │
│     • 互不影響                       │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  2. Consumer 擴展                    │
│     • Kafka Consumer Group          │
│     • 自動負載均衡                   │
│     • 增加進程即可提升吞吐量          │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  3. API 擴展                         │
│     • 無狀態設計                     │
│     • 使用負載均衡器                 │
│     • Session 存儲外部化 (Redis)     │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  4. 資料庫擴展                       │
│     • 讀寫分離                       │
│     • 分庫分表(按網路 ID)           │
│     • 冷熱數據分離                   │
└─────────────────────────────────────┘

效能瓶頸與優化

常見瓶頸與解決方案:
┌─────────────────────────────────────┐
│  瓶頸:RPC 請求慢                    │
│  解決:                              │
│  • 使用付費節點(Alchemy, Infura)   │
│  • 多節點負載均衡                    │
│  • 批次查詢優化                      │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  瓶頸:資料庫查詢慢                  │
│  解決:                              │
│  • 建立適當索引                      │
│  • 使用查詢快取                      │
│  • 讀寫分離                          │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  瓶頸:Kafka 消息積壓                │
│  解決:                              │
│  • 增加 Consumer 數量                │
│  • 增加 Partition 數量               │
│  • 優化處理邏輯                      │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│  瓶頸:記憶體佔用高                  │
│  解決:                              │
│  • 分批載入錢包地址                  │
│  • 定期清理快取                      │
│  • 使用流式處理                      │
└─────────────────────────────────────┘

總結

核心技術要點

本文從實際生產環境的企業級區塊鏈監聽系統中,提煉出以下核心技術理論:

1. 錢包管理

  • 單例模式確保全局唯一性
  • Set/Map 資料結構提供 O(1) 查詢效能
  • 軟刪除機制保留審計記錄
  • 分批載入策略避免記憶體暴增

2. ERC20 互動

  • ABI 定義智能合約介面
  • Transfer 事件監聽機制
  • Decimals 處理數值精度
  • 批次查詢優化 RPC 請求

3. 區塊鏈 RPC

  • JSON-RPC 通信協議
  • 多節點備援提升可用性
  • Web3.js vs Ethers.js 功能分工
  • debug_traceTransaction 追蹤內部轉帳

4. 交易監聽

  • 雙軌監聽系統(ERC20 + 原生)
  • Kafka 異步處理解耦流程
  • 區塊掃描狀態管理
  • 事件過濾與處理

5. 餘額管理

  • 即時餘額 + 歷史快照雙層架構
  • Wei/原始單位格式化
  • BigInt 處理大數值
  • 定時快照支援審計

6. 加密安全

  • AES-128-ECB 加密演算法
  • 環境變數隔離敏感資料
  • 本地簽名保護私鑰
  • 多層認證與授權

7. 多鏈支援

  • 統一抽象層設計
  • 配置驅動架構
  • 獨立 Scheduler 並行處理
  • 跨鏈統一查詢介面

8. 系統協作

  • 分層架構清晰職責
  • 錯誤處理與容錯機制
  • 效能監控與告警
  • 水平擴展策略

適用場景

本系統架構適合以下場景:

  • ✅ 加密貨幣交易所(充提幣管理)
  • ✅ 支付閘道(多鏈收款)
  • ✅ DeFi 平臺(資產追蹤)
  • ✅ NFT 市場(交易監聽)
  • ✅ 錢包服務(多鏈支援)
  • ✅ 審計系統(資產追蹤)

學習建議

理論 → 實踐路徑

階段 1:理解基礎概念
• 區塊鏈原理
• 以太坊架構
• 智能合約基礎

階段 2:學習開發工具
• Web3.js / Ethers.js 文檔
• RPC 方法實驗
• 測試網實作

階段 3:架構設計
• 單例模式應用
• 異步處理設計
• 資料庫設計

階段 4:安全實踐
• 私鑰管理
• 交易簽名
• API 防護

階段 5:生產部署
• 監控告警
• 擴展策略
• 災難恢復

參考專案: blockchain-listener-modify 文檔版本: 2.0.0 最後更新: 2025-11-13