區塊鏈交易完整指南(繁體中文版)
從使用者發起到交易成功的完整流程解析
📑 目錄
核心觀念釐清
❌ 常見錯誤觀念
錯誤:一條鏈就是一個合約?
這是完全錯誤的觀念!讓我們釐清:
✅ 正確觀念
區塊鏈 (Blockchain)
├─ 是一個分散式帳本系統
├─ 包含成千上萬個合約
└─ 由一個個區塊串連而成
智能合約 (Smart Contract)
├─ 是部署在區塊鏈上的程式
├─ 一條鏈上可以有無數個合約
└─ 每個合約都有自己的地址
區塊 (Block)
├─ 是區塊鏈的基本單位
├─ 包含多筆交易
└─ 透過密碼學串連在一起
📊 三者關係圖
┌─────────────────────────────────────────────────────────────────┐
│ 區塊鏈 (Ethereum Mainnet) │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Block #1 │──▶│ Block #2 │──▶│ Block #3 │──▶ ... │
│ │ │ │ │ │ │ │
│ │ TX1, TX2 │ │ TX3, TX4 │ │ TX5, TX6 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 部署在鏈上的智能合約 │ │
│ ├─────────────────────────────────────────────────────┤ │
│ │ • USDT 合約 @ 0xdac17f95... │ │
│ │ • Uniswap V3 @ 0x68b3465... │ │
│ │ • AAVE Protocol @ 0x7d2768... │ │
│ │ • 您的合約 @ 0x1234abcd... │ │
│ │ ... (數百萬個合約) │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
關鍵理解:
✅ 一條鏈 = 一個完整的區塊鏈網路(如 Ethereum、BSC、Polygon)
✅ 一個區塊 = 鏈上的一個數據單位(包含多筆交易)
✅ 一個合約 = 部署在鏈上的一段程式碼(有自己的地址和狀態)
完整交易流程圖
🎯 從使用者發起到交易成功的 10 個步驟
┌─────────────────────────────────────────────────────────────────┐
│ 步驟 0: 使用者準備 │
│ │
│ 使用者 (Alice) │
│ ├─ 錢包地址: 0xAlice... │
│ ├─ 私鑰: 存儲在本地錢包(MetaMask、硬體錢包等) │
│ └─ 餘額: 10 ETH │
│ │
│ 想要執行: 轉 1 ETH 給 Bob (0xBob...) │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 步驟 1: 構造交易 │
│ │
│ 錢包軟體幫使用者建立交易物件: │
│ { │
│ from: "0xAlice...", ← 發送者地址 │
│ to: "0xBob...", ← 接收者地址 │
│ value: 1000000000000000000, ← 1 ETH (以 wei 為單位) │
│ gas: 21000, ← Gas 限制 │
│ gasPrice: 50000000000, ← 50 gwei │
│ nonce: 5, ← 交易序號(防重放攻擊) │
│ chainId: 1 ← 主網 ID │
│ } │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 步驟 2: 私鑰簽章 🔐 (最關鍵的步驟!) │
│ │
│ 為什麼需要簽章? │
│ ✅ 證明交易確實由 Alice 發起(身份驗證) │
│ ✅ 防止他人偽造交易 │
│ ✅ 確保交易內容不被篡改 │
│ │
│ 簽章過程: │
│ 1. 對交易數據計算 Keccak-256 哈希 │
│ txHash = Keccak256(nonce + gasPrice + gas + to + value + data)│
│ │
│ 2. 使用私鑰對哈希簽名(ECDSA 簽名算法) │
│ signature = sign(txHash, privateKey) │
│ ↓ │
│ 得到 (v, r, s) 三個參數 │
│ │
│ 3. 簽章後的交易: │
│ rawTransaction = RLP.encode([ │
│ nonce, gasPrice, gas, to, value, data, v, r, s │
│ ]) │
│ │
│ ⚠️ 私鑰永不離開錢包!只有簽名結果被廣播 │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 步驟 3: 廣播到網路 │
│ │
│ 錢包透過 RPC 節點廣播簽章後的交易: │
│ │
│ Alice 的錢包 │
│ ↓ (HTTPS/WebSocket) │
│ 以太坊節點 (Infura/Alchemy/自建節點) │
│ ↓ │
│ P2P 網路 (以太坊的 DevP2P 協議) │
│ ↓ │
│ 全球數千個節點接收到這筆交易 │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 步驟 4: 進入 Mempool (交易池) │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ Mempool (記憶池) │ │
│ ├─────────────────────────────────────┤ │
│ │ TX1: Gas Price = 100 gwei (最高) │ ← 優先 │
│ │ TX2: Gas Price = 75 gwei │ │
│ │ TX3: Gas Price = 50 gwei ← Alice 的交易 │
│ │ TX4: Gas Price = 30 gwei │ │
│ │ TX5: Gas Price = 20 gwei (最低) │ ← 可能需要等很久 │
│ └─────────────────────────────────────┘ │
│ │
│ 狀態: Pending (等待被打包) │
│ Transfer Hash 已生成: 0x1234...abcd │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 步驟 5: 驗證者選擇交易 (PoS 機制) │
│ │
│ 以太坊 2.0 使用 PoS (Proof of Stake): │
│ │
│ 驗證者 (Validator) │
│ ├─ 已質押 32 ETH │
│ ├─ 被隨機選中提議下一個區塊 │
│ └─ 從 Mempool 選擇交易(優先選 Gas Price 高的) │
│ │
│ 驗證者檢查: │
│ ✅ 簽名是否有效 (verify(signature, publicKey)) │
│ ✅ Alice 餘額是否足夠 (balance >= 1 ETH + gas fee) │
│ ✅ Nonce 是否正確(必須是連續的) │
│ ✅ Gas Limit 是否合理 │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 步驟 6: 打包進區塊 │
│ │
│ 驗證者建立新區塊: │
│ ┌─────────────────────────────────────┐ │
│ │ Block #19,500,000 │ │
│ ├─────────────────────────────────────┤ │
│ │ Block Header: │ │
│ │ • Parent Hash: 0xaabb... │ ← 指向前一個區塊 │
│ │ • Timestamp: 1704067200 │ │
│ │ • Validator: 0xValidator... │ │
│ │ • State Root: 0xccdd... │ ← 世界狀態的 Merkle Root │
│ │ • Transactions Root: 0xeeff... │ ← 交易的 Merkle Root │
│ ├─────────────────────────────────────┤ │
│ │ Transactions: │ │
│ │ • TX1: 0x1111... (Gas: 100 gwei) │ │
│ │ • TX2: 0x2222... (Gas: 75 gwei) │ │
│ │ • TX3: 0x1234...abcd ← Alice 的交易 │ │
│ │ • ... (總共 ~150 筆交易) │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 步驟 7: 執行交易 (EVM 執行) │
│ │
│ EVM (Ethereum Virtual Machine) 執行: │
│ │
│ 1. 從 Alice 扣除 1 ETH │
│ State[0xAlice].balance -= 1 ETH │
│ ↓ │
│ 10 ETH → 9 ETH │
│ │
│ 2. 給 Bob 增加 1 ETH │
│ State[0xBob].balance += 1 ETH │
│ ↓ │
│ 5 ETH → 6 ETH │
│ │
│ 3. 扣除 Gas 費用 │
│ gasFee = 21000 * 50 gwei = 0.00105 ETH │
│ State[0xAlice].balance -= 0.00105 ETH │
│ State[Validator].balance += 0.00105 ETH (給驗證者) │
│ │
│ 4. 更新 Nonce │
│ State[0xAlice].nonce = 6 (從 5 變成 6) │
│ │
│ 執行結果:Success ✓ │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 步驟 8: 區塊共識與傳播 │
│ │
│ 1. 驗證者提議區塊 │
│ Proposer → 廣播區塊給其他驗證者 │
│ │
│ 2. 其他驗證者投票 │
│ ✅ Validator 1: 贊成 │
│ ✅ Validator 2: 贊成 │
│ ✅ Validator 3: 贊成 │
│ ... (需要 2/3 多數同意) │
│ │
│ 3. 達成共識 │
│ 區塊被最終確定 (Finalized) │
│ │
│ 4. 傳播到全網路 │
│ 全球所有節點更新區塊鏈狀態 │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 步驟 9: 確認與最終性 │
│ │
│ 確認過程: │
│ │
│ Block #19,500,000 ← Alice 的交易在這裡 │
│ Block #19,500,001 ← 第 1 次確認 │
│ Block #19,500,002 ← 第 2 次確認 │
│ Block #19,500,003 ← 第 3 次確認 │
│ ... │
│ Block #19,500,006 ← 第 6 次確認 (一般認為足夠安全) │
│ │
│ 確認越多 → 交易被回滾的可能性越低 │
│ │
│ 建議確認數: │
│ • 小額交易: 1-3 確認 │
│ • 一般交易: 6 確認 │
│ • 大額交易: 12+ 確認 │
│ • 交易所充值: 12-64 確認 │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 步驟 10: 完成 ✓ │
│ │
│ 交易狀態: Success │
│ Transfer Hash: 0x1234567890abcdef... │
│ Block Number: 19,500,000 │
│ Gas Used: 21,000 │
│ Gas Price: 50 gwei │
│ Transaction Fee: 0.00105 ETH │
│ Confirmations: 6 │
│ │
│ 最終結果: │
│ • Alice: 10 ETH → 8.99895 ETH (轉出 1 + 手續費 0.00105) │
│ • Bob: 5 ETH → 6 ETH │
│ • 驗證者: 獲得 0.00105 ETH 手續費 │
│ │
│ 🎉 交易成功完成! │
└─────────────────────────────────────────────────────────────────┘
鏈、合約、區塊的關係
🔗 完整架構圖
┌─────────────────────────────────────────────────────────────────────────┐
│ │
│ 區塊鏈層級結構 │
│ │
│ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │
│ ┃ Layer 1: 區塊鏈網路 (Blockchain Network) ┃ │
│ ┃ • Ethereum Mainnet (主網) ┃ │
│ ┃ • BSC (幣安智能鏈) ┃ │
│ ┃ • Polygon ┃ │
│ ┃ • Arbitrum (Layer 2) ┃ │
│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │
│ ↓ (一條鏈由無數個區塊組成) │
│ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │
│ ┃ Layer 2: 區塊層 (Block Layer) ┃ │
│ ┃ ┃ │
│ ┃ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┃ │
│ ┃ │ Block #1 │──▶│ Block #2 │──▶│ Block #3 │──▶ ... ┃ │
│ ┃ │ │ │ │ │ │ ┃ │
│ ┃ │ Header │ │ Header │ │ Header │ ┃ │
│ ┃ │ • Parent H │ │ • Parent H │ │ • Parent H │ ┃ │
│ ┃ │ • StateRoot│ │ • StateRoot│ │ • StateRoot│ ┃ │
│ ┃ │ • TxRoot │ │ • TxRoot │ │ • TxRoot │ ┃ │
│ ┃ │ │ │ │ │ │ ┃ │
│ ┃ │ Body │ │ Body │ │ Body │ ┃ │
│ ┃ │ • TX1 │ │ • TX3 │ │ • TX5 │ ┃ │
│ ┃ │ • TX2 │ │ • TX4 │ │ • TX6 │ ┃ │
│ ┃ └────────────┘ └────────────┘ └────────────┘ ┃ │
│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │
│ ↓ (每個區塊包含多筆交易) │
│ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │
│ ┃ Layer 3: 交易層 (Transaction Layer) ┃ │
│ ┃ ┃ │
│ ┃ Transaction #1: ┃ │
│ ┃ ┌─────────────────────────────────────────┐ ┃ │
│ ┃ │ From: 0xAlice │ ┃ │
│ ┃ │ To: 0xBob │ ┃ │
│ ┃ │ Value: 1 ETH │ ┃ │
│ ┃ │ Gas: 21000 │ ┃ │
│ ┃ │ Signature: (v, r, s) │ ┃ │
│ ┃ └─────────────────────────────────────────┘ ┃ │
│ ┃ ┃ │
│ ┃ Transaction #2: ┃ │
│ ┃ ┌─────────────────────────────────────────┐ ┃ │
│ ┃ │ From: 0xCharlie │ ┃ │
│ ┃ │ To: 0xUSDT_Contract ← 調用智能合約 │ ┃ │
│ ┃ │ Value: 0 ETH │ ┃ │
│ ┃ │ Data: transfer(Bob, 100 USDT) │ ┃ │
│ ┃ │ Gas: 65000 │ ┃ │
│ ┃ └─────────────────────────────────────────┘ ┃ │
│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │
│ ↓ (交易可能調用智能合約) │
│ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │
│ ┃ Layer 4: 智能合約層 (Smart Contract Layer) ┃ │
│ ┃ ┃ │
│ ┃ 部署在鏈上的合約(數百萬個): ┃ │
│ ┃ ┃ │
│ ┃ ┌──────────────────────────────────┐ ┃ │
│ ┃ │ USDT 合約 @ 0xdac17f95... │ ┃ │
│ ┃ │ • Code: ERC20 Token │ ┃ │
│ ┃ │ • Storage: balances mapping │ ┃ │
│ ┃ │ • Functions: transfer(), approve() ┃ │
│ ┃ └──────────────────────────────────┘ ┃ │
│ ┃ ┃ │
│ ┃ ┌──────────────────────────────────┐ ┃ │
│ ┃ │ Uniswap V3 @ 0x68b3465... │ ┃ │
│ ┃ │ • Code: DEX Protocol │ ┃ │
│ ┃ │ • Storage: liquidity pools │ ┃ │
│ ┃ │ • Functions: swap(), addLiquidity() ┃ │
│ ┃ └──────────────────────────────────┘ ┃ │
│ ┃ ┃ │
│ ┃ ┌──────────────────────────────────┐ ┃ │
│ ┃ │ 您的合約 @ 0x1234abcd... │ ┃ │
│ ┃ │ • Code: 自定義邏輯 │ ┃ │
│ ┃ │ • Storage: 自定義狀態變數 │ ┃ │
│ ┃ │ • Functions: 自定義函數 │ ┃ │
│ ┃ └──────────────────────────────────┘ ┃ │
│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │
│ ↓ (合約執行產生狀態變更) │
│ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │
│ ┃ Layer 5: 世界狀態層 (World State Layer) ┃ │
│ ┃ ┃ │
│ ┃ 所有帳戶的狀態(使用 Merkle Patricia Trie 存儲): ┃ │
│ ┃ ┃ │
│ ┃ 0xAlice: ┃ │
│ ┃ • balance: 9.99895 ETH ┃ │
│ ┃ • nonce: 6 ┃ │
│ ┃ • code: null (EOA 外部帳戶) ┃ │
│ ┃ ┃ │
│ ┃ 0xBob: ┃ │
│ ┃ • balance: 6 ETH ┃ │
│ ┃ • nonce: 0 ┃ │
│ ┃ • code: null ┃ │
│ ┃ ┃ │
│ ┃ 0xUSDT_Contract: ┃ │
│ ┃ • balance: 0 ETH ┃ │
│ ┃ • nonce: 1 ┃ │
│ ┃ • code: 0x6060604052... (EVM 字節碼) ┃ │
│ ┃ • storage: ┃ │
│ ┃ balances[0xAlice] = 1000000000 (10 億 USDT) ┃ │
│ ┃ balances[0xBob] = 500000000 (5 億 USDT) ┃ │
│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │
└─────────────────────────────────────────────────────────────────────────┘
📝 關係總結
| 層級 | 名稱 | 數量關係 | 作用 |
|---|---|---|---|
| L1 | 區塊鏈 | 1 條鏈 | 整個網路(如 Ethereum) |
| L2 | 區塊 | 無數個 | 鏈的組成單位,每 12 秒產生 1 個 |
| L3 | 交易 | 無數筆 | 每個區塊包含約 150-300 筆交易 |
| L4 | 智能合約 | 數百萬個 | 部署在鏈上的程式 |
| L5 | 世界狀態 | 全局唯一 | 所有帳戶和合約的當前狀態 |
為什麼需要私鑰簽章
🔐 核心問題
問題:為什麼不能直接廣播交易,而必須先簽章?
答案:沒有簽章 = 任何人都能偽造您的交易!
💡 場景對比
❌ 如果沒有私鑰簽章(災難性後果)
┌─────────────────────────────────────┐
│ 惡意攻擊者 (Hacker) │
│ │
│ 構造一筆假交易: │
│ { │
│ from: "0xAlice", ← 假冒 Alice │
│ to: "0xHacker", │
│ value: 100 ETH ← 偷走 Alice 的錢
│ } │
│ │
│ 直接廣播 → 成功!Alice 的錢被偷了 │
└─────────────────────────────────────┘
問題:
❌ 任何人都能假冒 Alice 發起交易
❌ 無法證明交易確實由 Alice 授權
❌ Alice 的資產完全不安全
✅ 有私鑰簽章(安全機制)
┌─────────────────────────────────────────────────────────────┐
│ 惡意攻擊者嘗試假冒 Alice │
│ │
│ Step 1: 構造假交易 │
│ { │
│ from: "0xAlice", │
│ to: "0xHacker", │
│ value: 100 ETH │
│ } │
│ │
│ Step 2: 嘗試簽章 │
│ ❌ 沒有 Alice 的私鑰! │
│ ❌ 無法產生有效簽名 │
│ │
│ Step 3: 廣播到網路 │
│ 節點驗證: │
│ if (!verify(signature, publicKey)): │
│ reject("Invalid signature") ← 交易被拒絕 │
│ │
│ 結果:❌ 攻擊失敗!Alice 的資產安全 │
└─────────────────────────────────────────────────────────────┘
🔑 私鑰簽章的三大作用
┌────────────────────────────────────────────────────────────────┐
│ 作用 1: 身份驗證 (Authentication) │
├────────────────────────────────────────────────────────────────┤
│ • 證明交易確實由私鑰持有者發起 │
│ • 公鑰可以從簽名中恢復出來 │
│ • 恢復出的公鑰必須與 from 地址匹配 │
│ │
│ 驗證過程: │
│ recoveredAddress = ecrecover(txHash, v, r, s) │
│ if (recoveredAddress == from): │
│ ✅ 交易有效 │
│ else: │
│ ❌ 交易無效(偽造的) │
└────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────┐
│ 作用 2: 防篡改 (Integrity) │
├────────────────────────────────────────────────────────────────┤
│ • 簽名是對整個交易數據的簽名 │
│ • 任何字段被修改,簽名就會失效 │
│ │
│ 例如: │
│ 原始交易: {from: Alice, to: Bob, value: 1 ETH} │
│ 簽名: signature_original │
│ │
│ 攻擊者嘗試修改: │
│ {from: Alice, to: Hacker, value: 100 ETH} ← 修改收款人和金額 │
│ │
│ 驗證: │
│ verify(signature_original, modified_tx) │
│ ❌ 簽名不匹配!交易被拒絕 │
└────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────┐
│ 作用 3: 不可否認 (Non-repudiation) │
├────────────────────────────────────────────────────────────────┤
│ • 簽章後,Alice 無法否認曾發起過這筆交易 │
│ • 只有持有私鑰的人才能產生有效簽名 │
│ • 簽名被永久記錄在區塊鏈上 │
│ │
│ Alice: "我沒有發起這筆交易!" │
│ 區塊鏈: "這是您的簽名,經過密碼學驗證確實是您簽的" │
│ Alice: "..." (無法否認) │
└────────────────────────────────────────────────────────────────┘
🔬 簽章技術詳解
ECDSA 簽名算法(以太坊使用的算法)
# ============================================
# 完整的簽章與驗證流程
# ============================================
# Step 1: 準備交易數據
transaction = {
'nonce': 5,
'gasPrice': 50000000000, # 50 gwei
'gas': 21000,
'to': '0xBob...',
'value': 1000000000000000000, # 1 ETH
'data': '0x',
'chainId': 1
}
# Step 2: 計算交易哈希
from web3 import Web3
import rlp
# RLP 編碼
encoded = rlp.encode([
transaction['nonce'],
transaction['gasPrice'],
transaction['gas'],
Web3.to_bytes(hexstr=transaction['to']),
transaction['value'],
Web3.to_bytes(hexstr=transaction['data']),
transaction['chainId'], 0, 0 # EIP-155
])
# Keccak-256 哈希
tx_hash = Web3.keccak(encoded)
print(f"Transaction Hash: {tx_hash.hex()}")
# Step 3: 使用私鑰簽名
from eth_account import Account
private_key = "0x你的私鑰..."
account = Account.from_key(private_key)
# ECDSA 簽名(產生 v, r, s)
signature = account.signHash(tx_hash)
v = signature.v
r = signature.r
s = signature.s
print(f"Signature (v): {v}")
print(f"Signature (r): {r}")
print(f"Signature (s): {s}")
# Step 4: 組合完整的簽章交易
signed_transaction = rlp.encode([
transaction['nonce'],
transaction['gasPrice'],
transaction['gas'],
Web3.to_bytes(hexstr=transaction['to']),
transaction['value'],
Web3.to_bytes(hexstr=transaction['data']),
v, r, s
])
raw_tx = '0x' + signed_transaction.hex()
print(f"Raw Transaction: {raw_tx}")
# Step 5: 廣播交易
tx_hash = web3.eth.send_raw_transaction(signed_transaction)
print(f"Broadcasted! TX Hash: {tx_hash.hex()}")
# ============================================
# 節點如何驗證簽名
# ============================================
# Step 1: 從簽名恢復公鑰
from eth_utils import keccak
from eth_keys import keys
# 使用 ecrecover 恢復地址
recovered_address = Account.recover_message(
tx_hash,
signature=signature
)
print(f"Recovered Address: {recovered_address}")
# Step 2: 檢查地址是否匹配
if recovered_address.lower() == account.address.lower():
print("✅ 簽名有效!交易確實由 Alice 發起")
else:
print("❌ 簽名無效!這是偽造的交易")
簽章的數學原理
ECDSA (Elliptic Curve Digital Signature Algorithm)
使用的橢圓曲線: secp256k1 (與 Bitcoin 相同)
方程式: y² = x³ + 7
私鑰 (Private Key):
• 一個 256 位的隨機數
• 範圍: 1 到 2^256 - 1
• 必須保密!洩漏 = 資產被盜
公鑰 (Public Key):
• 從私鑰推導: Public Key = Private Key × G
• G 是橢圓曲線的生成點
• 無法從公鑰反推私鑰(單向函數)
地址 (Address):
• Address = Keccak256(Public Key)[12:]
• 取公鑰哈希的後 20 位元組
• 格式: 0x + 40 個十六進位字符
簽名過程:
1. 選擇隨機數 k
2. 計算 R = k × G
3. r = R 的 x 座標
4. s = k^(-1) × (hash + r × privateKey) mod n
5. 輸出: (r, s, v)
驗證過程:
1. 計算 u1 = hash × s^(-1) mod n
2. 計算 u2 = r × s^(-1) mod n
3. 計算 R' = u1 × G + u2 × PublicKey
4. 如果 R' 的 x 座標 == r,則簽名有效
區塊結構詳解
📦 完整的區塊結構
┌─────────────────────────────────────────────────────────────────┐
│ Block #19,500,000 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │
│ ┃ Block Header (區塊頭) ┃ │
│ ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ │
│ ┃ parentHash: 0xaabbccdd... ┃ │
│ ┃ ↑ 指向前一個區塊的哈希(形成鏈) ┃ │
│ ┃ ┃ │
│ ┃ stateRoot: 0x1122eeff... ┃ │
│ ┃ ↑ 世界狀態的 Merkle Root(所有帳戶狀態的摘要) ┃ │
│ ┃ ┃ │
│ ┃ transactionsRoot: 0x3344aabb... ┃ │
│ ┃ ↑ 交易 Merkle Tree 的根(所有交易的摘要) ┃ │
│ ┃ ┃ │
│ ┃ receiptsRoot: 0x5566ccdd... ┃ │
│ ┃ ↑ 交易收據 Merkle Tree 的根 ┃ │
│ ┃ ┃ │
│ ┃ logsBloom: 0x00000000... ┃ │
│ ┃ ↑ Bloom Filter(快速檢索事件日誌) ┃ │
│ ┃ ┃ │
│ ┃ number: 19500000 ┃ │
│ ┃ ↑ 區塊編號 ┃ │
│ ┃ ┃ │
│ ┃ gasLimit: 30000000 ┃ │
│ ┃ ↑ 該區塊的最大 Gas 限制 ┃ │
│ ┃ ┃ │
│ ┃ gasUsed: 29856742 ┃ │
│ ┃ ↑ 實際使用的 Gas ┃ │
│ ┃ ┃ │
│ ┃ timestamp: 1704067200 ┃ │
│ ┃ ↑ Unix 時間戳(2024-01-01 00:00:00 UTC) ┃ │
│ ┃ ┃ │
│ ┃ baseFeePerGas: 15000000000 ┃ │
│ ┃ ↑ 基礎 Gas 費用(15 gwei)- EIP-1559 ┃ │
│ ┃ ┃ │
│ ┃ feeRecipient: 0xValidator... ┃ │
│ ┃ ↑ 驗證者地址(PoS 機制) ┃ │
│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │
│ │
│ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │
│ ┃ Block Body (區塊體) ┃ │
│ ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ │
│ ┃ ┃ │
│ ┃ Transactions (交易列表): ┃ │
│ ┃ ┃ │
│ ┃ ┌─────────────────────────────────────┐ ┃ │
│ ┃ │ TX #1: 0x1111... │ ┃ │
│ ┃ │ • from: 0xAlice │ ┃ │
│ ┃ │ • to: 0xBob │ ┃ │
│ ┃ │ • value: 1 ETH │ ┃ │
│ ┃ │ • gas: 21000 │ ┃ │
│ ┃ │ • gasPrice: 50 gwei │ ┃ │
│ ┃ │ • signature: (v, r, s) │ ┃ │
│ ┃ └─────────────────────────────────────┘ ┃ │
│ ┃ ┃ │
│ ┃ ┌─────────────────────────────────────┐ ┃ │
│ ┃ │ TX #2: 0x2222... │ ┃ │
│ ┃ │ • from: 0xCharlie │ ┃ │
│ ┃ │ • to: 0xUSDT_Contract │ ┃ │
│ ┃ │ • value: 0 ETH │ ┃ │
│ ┃ │ • data: transfer(Bob, 100 USDT) │ ┃ │
│ ┃ │ • gas: 65000 │ ┃ │
│ ┃ └─────────────────────────────────────┘ ┃ │
│ ┃ ┃ │
│ ┃ ... (總共約 150-250 筆交易) ┃ │
│ ┃ ┃ │
│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │
│ │
│ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │
│ ┃ Transaction Receipts (交易收據) ┃ │
│ ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ │
│ ┃ ┃ │
│ ┃ ┌─────────────────────────────────────┐ ┃ │
│ ┃ │ Receipt for TX #1: │ ┃ │
│ ┃ │ • status: 1 (success) │ ┃ │
│ ┃ │ • gasUsed: 21000 │ ┃ │
│ ┃ │ • logs: [] │ ┃ │
│ ┃ └─────────────────────────────────────┘ ┃ │
│ ┃ ┃ │
│ ┃ ┌─────────────────────────────────────┐ ┃ │
│ ┃ │ Receipt for TX #2: │ ┃ │
│ ┃ │ • status: 1 (success) │ ┃ │
│ ┃ │ • gasUsed: 65000 │ ┃ │
│ ┃ │ • logs: [ │ ┃ │
│ ┃ │ { │ ┃ │
│ ┃ │ address: 0xUSDT_Contract, │ ┃ │
│ ┃ │ topics: [Transfer, Charlie, Bob], ┃ │
│ ┃ │ data: 100 USDT │ ┃ │
│ ┃ │ } │ ┃ │
│ ┃ │ ] │ ┃ │
│ ┃ └─────────────────────────────────────┘ ┃ │
│ ┃ ┃ │
│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │
└─────────────────────────────────────────────────────────────────┘
Block Hash = Keccak256(Block Header)
= 0xf1e2d3c4b5a6978...
🔗 區塊如何串連成鏈
Genesis Block Block #1 Block #2 Block #3
(創世區塊)
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ │ │ │ │ │ │ │
│ Hash: │ │ Hash: │ │ Hash: │ │ Hash: │
│ 0xaaaa... │◀────│ 0xbbbb... │◀────│ 0xcccc... │◀────│ 0xdddd... │
│ │ │ │ │ │ │ │
│ Parent: │ │ Parent: │ │ Parent: │ │ Parent: │
│ 0x0000... │ │ 0xaaaa... │ │ 0xbbbb... │ │ 0xcccc... │
│ │ │ ↑ │ │ ↑ │ │ ↑ │
│ Number: 0 │ │ └──────────┘ │ └──────────┘ │ └──────────┘
│ │ │ Number: 1 │ │ Number: 2 │ │ Number: 3 │
│ Timestamp: │ │ │ │ │ │ │
│ 1438269988 │ │ Timestamp: │ │ Timestamp: │ │ Timestamp: │
│ │ │ 1438270001 │ │ 1438270013 │ │ 1438270025 │
│ TX: [] │ │ │ │ │ │ │
│ │ │ TX: [...] │ │ TX: [...] │ │ TX: [...] │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
關鍵特性:
✅ 每個區塊都包含前一個區塊的哈希 (parentHash)
✅ 形成一條不可篡改的鏈
✅ 任何區塊被修改,後續所有區塊的哈希都會改變
✅ 需要重新計算所有後續區塊(幾乎不可能,因為需要巨大算力)
錢包與監聽器架構
💼 區塊鏈錢包完整架構(基於白板內容)
┌─────────────────────────────────────────────────────────────────────┐
│ 區塊鏈錢包系統架構 │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ Layer 1: 前端使用者介面 (Frontend UI) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ • Web App (React/Vue) │
│ • Mobile App (React Native/Flutter) │
│ • Browser Extension (MetaMask 架構) │
│ │
│ 功能: │
│ - 顯示錢包餘額 │
│ - 發起轉帳 │
│ - 查看交易歷史 │
│ - 合約互動介面 │
└─────────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────────┐
│ Layer 2: 錢包核心邏輯 (Wallet Core) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ 密鑰管理模組 (Key Management) │ │
│ ├──────────────────────────────────────────────┤ │
│ │ • 助記詞生成 (BIP39) │ │
│ │ - 12/24 個單詞 │ │
│ │ - 例: "army van defense..." │ │
│ │ │ │
│ │ • 私鑰推導 (BIP32/BIP44) │ │
│ │ - HD Wallet (分層確定性錢包) │ │
│ │ - Path: m/44'/60'/0'/0/0 │ │
│ │ │ │
│ │ • 私鑰存儲 │ │
│ │ - 加密存儲 (AES-256) │ │
│ │ - Keystore 文件 │ │
│ │ - 硬體錢包整合 (Ledger/Trezor) │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ 交易構造模組 (Transaction Builder) │ │
│ ├──────────────────────────────────────────────┤ │
│ │ • 構造交易物件 │ │
│ │ • 估算 Gas │ │
│ │ • 設定 Nonce │ │
│ │ • EIP-1559 費用計算 │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ 簽名模組 (Signing Module) │ │
│ ├──────────────────────────────────────────────┤ │
│ │ • ECDSA 簽名 │ │
│ │ • EIP-712 簽名 (結構化數據) │ │
│ │ • 簽名驗證 │ │
│ └──────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────────┐
│ Layer 3: 區塊鏈連接層 (Blockchain Connection) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ RPC 客戶端 (Web3.js / Ethers.js) │ │
│ ├──────────────────────────────────────────────┤ │
│ │ • HTTP Provider │ │
│ │ • WebSocket Provider │ │
│ │ • IPC Provider (本地節點) │ │
│ │ │ │
│ │ 支持的 RPC 方法: │ │
│ │ - eth_sendRawTransaction │ │
│ │ - eth_getBalance │ │
│ │ - eth_getTransactionReceipt │ │
│ │ - eth_call (讀取合約) │ │
│ │ - eth_estimateGas │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ 節點提供商 (Node Providers) │ │
│ ├──────────────────────────────────────────────┤ │
│ │ • Infura │ │
│ │ • Alchemy │ │
│ │ • QuickNode │ │
│ │ • 自建節點 (Geth/Erigon) │ │
│ └──────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
📡 區塊鏈監聽器架構(基於白板:Log/Event Listener)
┌─────────────────────────────────────────────────────────────────────┐
│ 區塊鏈事件監聽器完整架構 │
│ (Blockchain Event Listener Architecture) │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 監聽器核心組件 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────┐ │
│ │ 1. Block Number Tracker │ │
│ │ (區塊編號追蹤器) │ │
│ ├───────────────────────────────────────┤ │
│ │ • 持續輪詢最新區塊號 │ │
│ │ • 方法: eth_blockNumber │ │
│ │ • 頻率: 每 2-5 秒 │ │
│ │ │ │
│ │ 當前區塊: #19,500,123 │ │
│ │ 上次處理: #19,500,120 │ │
│ │ 待處理: [#19,500,121, #19,500,122] │ │
│ └───────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────┐ │
│ │ 2. Transaction List Fetcher │ │
│ │ (交易列表獲取器) │ │
│ ├───────────────────────────────────────┤ │
│ │ • 獲取區塊中的所有交易 │ │
│ │ • 方法: eth_getBlockByNumber │ │
│ │ │ │
│ │ Block #19,500,121: │ │
│ │ ├─ TX1: 0x1111... │ │
│ │ ├─ TX2: 0x2222... │ │
│ │ ├─ TX3: 0x3333... │ │
│ │ └─ ... (150 筆交易) │ │
│ └───────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────┐ │
│ │ 3. Transaction Hash Processor │ │
│ │ (交易哈希處理器) │ │
│ ├───────────────────────────────────────┤ │
│ │ • 獲取交易收據 │ │
│ │ • 方法: eth_getTransactionReceipt │ │
│ │ │ │
│ │ for each TX in block: │ │
│ │ receipt = getReceipt(tx_hash) │ │
│ │ if receipt.logs: │ │
│ │ process_events(receipt.logs) │ │
│ └───────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────┐ │
│ │ 4. Event Log Decoder │ │
│ │ (事件日誌解碼器) │ │
│ ├───────────────────────────────────────┤ │
│ │ 解碼事件日誌: │ │
│ │ │ │
│ │ Log: │ │
│ │ address: 0xUSDT_Contract │ │
│ │ topics: [ │ │
│ │ 0xddf252ad... (Transfer 簽名) │ │
│ │ 0x000...Alice (from) │ │
│ │ 0x000...Bob (to) │ │
│ │ ] │ │
│ │ data: 0x0000...0064 (100) │ │
│ │ │ │
│ │ 解碼後: │ │
│ │ Event: Transfer │ │
│ │ From: 0xAlice │ │
│ │ To: 0xBob │ │
│ │ Amount: 100 USDT │ │
│ └───────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────┐ │
│ │ 5. Event Filter & Router │ │
│ │ (事件過濾與路由器) │ │
│ ├───────────────────────────────────────┤ │
│ │ 過濾規則: │ │
│ │ │ │
│ │ if (event.name == "Transfer" && │ │
│ │ event.to == myAddress): │ │
│ │ notify_user("收到轉帳") │ │
│ │ │ │
│ │ if (event.contract == "0xUSDT" && │ │
│ │ event.amount > 1000000): │ │
│ │ alert_large_transfer() │ │
│ └───────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────┐ │
│ │ 6. Data Storage & Indexing │ │
│ │ (數據存儲與索引) │ │
│ ├───────────────────────────────────────┤ │
│ │ 存儲到數據庫: │ │
│ │ │ │
│ │ Database: PostgreSQL / MongoDB │ │
│ │ Table: transactions │ │
│ │ - tx_hash │ │
│ │ - block_number │ │
│ │ - from_address │ │
│ │ - to_address │ │
│ │ - value │ │
│ │ - timestamp │ │
│ │ │ │
│ │ Table: events │ │
│ │ - event_name │ │
│ │ - contract_address │ │
│ │ - block_number │ │
│ │ - tx_hash │ │
│ │ - decoded_params │ │
│ └───────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
🔧 關鍵技術詳解
1. Event Log 結構
// 原始 Log 格式
{
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", // USDT 合約地址
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", // Transfer(address,address,uint256) 簽名
"0x000000000000000000000000742d35cc6634c0532925a3b844bc454e4438f44e", // from (indexed)
"0x000000000000000000000000c5102fe9359fd9a28f877a67e36b0f050d81a3cc" // to (indexed)
],
"data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", // amount (100000000 = 100 USDT)
"blockNumber": "0x1234567",
"transactionHash": "0xaabbccdd...",
"logIndex": "0x0"
}
// Event 簽名計算
eventSignature = Keccak256("Transfer(address,address,uint256)")
= 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
2. 監聽器代碼實作(Python)
from web3 import Web3
import time
import json
# 連接節點
web3 = Web3(Web3.WebsocketProvider("wss://eth-mainnet.ws.infura.io/ws/v3/YOUR-KEY"))
# USDT 合約地址
USDT_CONTRACT = "0xdAC17F958D2ee523a2206206994597C13D831ec7"
# Transfer 事件簽名
TRANSFER_EVENT = web3.keccak(text="Transfer(address,address,uint256)").hex()
class BlockchainListener:
def __init__(self, web3_instance, monitored_address):
self.web3 = web3_instance
self.monitored_address = monitored_address.lower()
self.last_processed_block = self.web3.eth.block_number
def get_new_blocks(self):
"""獲取新區塊"""
current_block = self.web3.eth.block_number
if current_block > self.last_processed_block:
new_blocks = range(self.last_processed_block + 1, current_block + 1)
self.last_processed_block = current_block
return new_blocks
return []
def process_block(self, block_number):
"""處理單個區塊"""
print(f"Processing Block #{block_number}")
# 獲取區塊
block = self.web3.eth.get_block(block_number, full_transactions=True)
# 遍歷所有交易
for tx in block['transactions']:
self.process_transaction(tx)
def process_transaction(self, tx):
"""處理單筆交易"""
# 獲取交易收據
receipt = self.web3.eth.get_transaction_receipt(tx['hash'])
# 檢查交易是否成功
if receipt['status'] != 1:
return
# 處理事件日誌
for log in receipt['logs']:
self.process_event(log, tx)
def process_event(self, log, tx):
"""處理事件日誌"""
# 只處理 USDT 合約的 Transfer 事件
if log['address'].lower() != USDT_CONTRACT.lower():
return
if len(log['topics']) == 0 or log['topics'][0].hex() != TRANSFER_EVENT:
return
# 解碼事件
from_address = '0x' + log['topics'][1].hex()[-40:]
to_address = '0x' + log['topics'][2].hex()[-40:]
amount = int(log['data'].hex(), 16)
# 檢查是否與監控地址相關
if from_address.lower() == self.monitored_address or \
to_address.lower() == self.monitored_address:
print(f"\n🔔 USDT Transfer Detected!")
print(f" TX Hash: {tx['hash'].hex()}")
print(f" From: {from_address}")
print(f" To: {to_address}")
print(f" Amount: {amount / 1e6} USDT") # USDT 有 6 位小數
print(f" Block: {tx['blockNumber']}")
# 這裡可以:
# - 發送通知給使用者
# - 存儲到數據庫
# - 觸發其他業務邏輯
self.notify_user(from_address, to_address, amount, tx['hash'].hex())
def notify_user(self, from_addr, to_addr, amount, tx_hash):
"""通知使用者"""
if to_addr.lower() == self.monitored_address:
print(f"✅ 您收到了 {amount / 1e6} USDT")
else:
print(f"📤 您發送了 {amount / 1e6} USDT")
# 可以整合:
# - Email 通知
# - Push 通知
# - Webhook
# - WebSocket 推送到前端
def start(self):
"""啟動監聽器"""
print(f"🚀 Blockchain Listener Started")
print(f"📍 Monitoring Address: {self.monitored_address}")
print(f"📦 Starting from Block: {self.last_processed_block}")
while True:
try:
# 獲取新區塊
new_blocks = self.get_new_blocks()
# 處理每個新區塊
for block_num in new_blocks:
self.process_block(block_num)
# 等待 2 秒(以太坊平均出塊時間約 12 秒)
time.sleep(2)
except KeyboardInterrupt:
print("\n⛔ Listener Stopped")
break
except Exception as e:
print(f"❌ Error: {e}")
time.sleep(5)
# 使用範例
if __name__ == "__main__":
# 您要監控的錢包地址
MY_ADDRESS = "0x742d35Cc6634C0532925a3b844Bc454e4438f44e"
listener = BlockchainListener(web3, MY_ADDRESS)
listener.start()
3. 使用 WebSocket 的高效監聽(更推薦)
from web3 import Web3
import asyncio
# WebSocket 連接
web3 = Web3(Web3.WebsocketProvider("wss://eth-mainnet.ws.infura.io/ws/v3/YOUR-KEY"))
async def listen_pending_transactions():
"""監聽待處理交易(Mempool)"""
# 訂閱 pending transactions
pending_filter = web3.eth.filter('pending')
while True:
try:
# 獲取新的待處理交易
for tx_hash in pending_filter.get_new_entries():
tx = web3.eth.get_transaction(tx_hash)
# 檢查是否是發送給我們監控的地址
if tx['to'] and tx['to'].lower() == MY_ADDRESS.lower():
print(f"⚡ Incoming Pending TX: {tx_hash.hex()}")
print(f" From: {tx['from']}")
print(f" Value: {web3.from_wei(tx['value'], 'ether')} ETH")
await asyncio.sleep(1)
except Exception as e:
print(f"Error: {e}")
await asyncio.sleep(5)
async def listen_new_blocks():
"""監聽新區塊"""
block_filter = web3.eth.filter('latest')
while True:
try:
for block_hash in block_filter.get_new_entries():
block = web3.eth.get_block(block_hash, full_transactions=True)
print(f"\n📦 New Block: #{block['number']}")
print(f" Transactions: {len(block['transactions'])}")
print(f" Gas Used: {block['gasUsed']}")
await asyncio.sleep(1)
except Exception as e:
print(f"Error: {e}")
await asyncio.sleep(5)
async def listen_logs():
"""監聽特定合約的事件日誌"""
# 創建日誌過濾器
log_filter = web3.eth.filter({
'address': USDT_CONTRACT,
'topics': [TRANSFER_EVENT]
})
while True:
try:
for log in log_filter.get_new_entries():
# 解碼
from_addr = '0x' + log['topics'][1].hex()[-40:]
to_addr = '0x' + log['topics'][2].hex()[-40:]
amount = int(log['data'].hex(), 16)
print(f"\n💸 USDT Transfer:")
print(f" From: {from_addr}")
print(f" To: {to_addr}")
print(f" Amount: {amount / 1e6} USDT")
await asyncio.sleep(1)
except Exception as e:
print(f"Error: {e}")
await asyncio.sleep(5)
# 同時運行多個監聽器
async def main():
await asyncio.gather(
listen_pending_transactions(),
listen_new_blocks(),
listen_logs()
)
if __name__ == "__main__":
asyncio.run(main())
核心概念層級
📊 層級對應表
| 層級 | 概念 | 定義 | 位置 | 例子 |
|---|---|---|---|---|
| L1: 交易輸入 | From/To/Gas | 交易發起的基本參數 | 交易字段 | from: 0xAliceto: 0xUSDTgas: 100000 |
| L2: 交易識別 | Transfer Hash | 交易的唯一哈希 | 交易層 | 0x1234...5678(TXID) |
| L2b: 位置標記 | Block Number | 交易所在區塊 | 區塊層 | #19000000 |
| L3: 代碼執行 | Smart Contract | 區塊鏈上的程式 | 合約層 | USDT 合約@ 0xdac17f95... |
| L4: 執行追蹤 | Debug Trace | 執行的完整步驟 | 追蹤層 | CALL, SSTOREREVERT, emit |
| L5: 執行細節 | Opcode Level | 最細粒度的操作 | EVM 層 | PUSH1, ADDSSTORE, REVERT |
🏗️ 架構視圖
┌─────────────────────────────────────────────────┐
│ 使用者層 (L0) │
│ Alice 發起轉帳操作 │
└─────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────┐
│ 交易參數層 (L1) │
│ From: 0xAlice | To: 0xUSDT | Gas: 100000 │
└─────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────┐
│ 交易標識層 (L2) │
│ Transfer Hash: 0x1234...5678 │
│ Block Number: #19000000 │
└─────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────┐
│ 合約執行層 (L3) │
│ USDT Contract @ 0xdac17f95... │
│ Function: transfer(Bob, 100) │
└─────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────┐
│ 執行追蹤層 (L4) │
│ Debug Trace: CALL → SSTORE → EMIT → RETURN │
└─────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────┐
│ EVM 操作層 (L5) │
│ Opcodes: PUSH1 → ADD → SSTORE │
└─────────────────────────────────────────────────┘
交易生命週期詳解
(詳細內容請參考上方「完整交易流程圖」章節,已包含 10 個步驟的完整說明)
實戰代碼範例
🛠️ 完整錢包實作(從零開始)
from web3 import Web3
from eth_account import Account
from mnemonic import Mnemonic
import json
class EthereumWallet:
"""完整的以太坊錢包實作"""
def __init__(self, rpc_url="https://eth-mainnet.infura.io/v3/YOUR-KEY"):
self.web3 = Web3(Web3.HTTPProvider(rpc_url))
self.account = None
# ============================================
# 1. 創建新錢包
# ============================================
def create_wallet(self):
"""創建新錢包(生成助記詞)"""
# 生成助記詞
mnemo = Mnemonic("english")
mnemonic = mnemo.generate(strength=128) # 12 個單詞
print("🔑 新錢包已創建!")
print(f"助記詞: {mnemonic}")
print("⚠️ 請妥善保管助記詞,這是恢復錢包的唯一方式!\n")
# 從助記詞推導私鑰
Account.enable_unaudited_hdwallet_features()
self.account = Account.from_mnemonic(mnemonic)
self._print_wallet_info()
return {
'mnemonic': mnemonic,
'address': self.account.address,
'private_key': self.account.key.hex()
}
# ============================================
# 2. 導入錢包
# ============================================
def import_from_mnemonic(self, mnemonic):
"""從助記詞導入錢包"""
Account.enable_unaudited_hdwallet_features()
self.account = Account.from_mnemonic(mnemonic)
print("✅ 錢包已導入")
self._print_wallet_info()
def import_from_private_key(self, private_key):
"""從私鑰導入錢包"""
self.account = Account.from_key(private_key)
print("✅ 錢包已導入")
self._print_wallet_info()
def _print_wallet_info(self):
"""打印錢包資訊"""
print(f"地址: {self.account.address}")
print(f"私鑰: {self.account.key.hex()}\n")
# ============================================
# 3. 查詢餘額
# ============================================
def get_balance(self, address=None):
"""查詢 ETH 餘額"""
if address is None:
address = self.account.address
balance_wei = self.web3.eth.get_balance(address)
balance_eth = self.web3.from_wei(balance_wei, 'ether')
print(f"💰 地址: {address}")
print(f" 餘額: {balance_eth} ETH\n")
return float(balance_eth)
def get_token_balance(self, token_contract_address, decimals=18):
"""查詢 ERC20 代幣餘額"""
# ERC20 balanceOf ABI
abi = [{
"constant": True,
"inputs": [{"name": "_owner", "type": "address"}],
"name": "balanceOf",
"outputs": [{"name": "balance", "type": "uint256"}],
"type": "function"
}]
contract = self.web3.eth.contract(address=token_contract_address, abi=abi)
balance = contract.functions.balanceOf(self.account.address).call()
balance_formatted = balance / (10 ** decimals)
print(f"🪙 代幣餘額: {balance_formatted}")
return balance_formatted
# ============================================
# 4. 發送 ETH
# ============================================
def send_eth(self, to_address, amount_eth, gas_price_gwei=None):
"""發送 ETH"""
if self.account is None:
raise Exception("請先導入錢包")
# 獲取 nonce
nonce = self.web3.eth.get_transaction_count(self.account.address)
# 設定 Gas Price
if gas_price_gwei is None:
gas_price = self.web3.eth.gas_price
else:
gas_price = self.web3.to_wei(gas_price_gwei, 'gwei')
# 構建交易
transaction = {
'nonce': nonce,
'to': to_address,
'value': self.web3.to_wei(amount_eth, 'ether'),
'gas': 21000,
'gasPrice': gas_price,
'chainId': 1 # 主網
}
# 簽名交易
signed_tx = self.web3.eth.account.sign_transaction(transaction, self.account.key)
# 發送交易
tx_hash = self.web3.eth.send_raw_transaction(signed_tx.rawTransaction)
print(f"📤 交易已發送!")
print(f" TX Hash: {tx_hash.hex()}")
print(f" From: {self.account.address}")
print(f" To: {to_address}")
print(f" Amount: {amount_eth} ETH")
print(f" Gas Price: {self.web3.from_wei(gas_price, 'gwei')} gwei\n")
# 等待確認
print("⏳ 等待交易確認...")
receipt = self.web3.eth.wait_for_transaction_receipt(tx_hash)
if receipt['status'] == 1:
print("✅ 交易成功!")
print(f" Block: {receipt['blockNumber']}")
print(f" Gas Used: {receipt['gasUsed']}")
else:
print("❌ 交易失敗")
return tx_hash.hex()
# ============================================
# 5. 發送 ERC20 代幣
# ============================================
def send_token(self, token_contract_address, to_address, amount, decimals=18):
"""發送 ERC20 代幣"""
# ERC20 transfer ABI
abi = [{
"constant": False,
"inputs": [
{"name": "_to", "type": "address"},
{"name": "_value", "type": "uint256"}
],
"name": "transfer",
"outputs": [{"name": "", "type": "bool"}],
"type": "function"
}]
contract = self.web3.eth.contract(address=token_contract_address, abi=abi)
# 轉換金額
amount_wei = int(amount * (10 ** decimals))
# 獲取 nonce
nonce = self.web3.eth.get_transaction_count(self.account.address)
# 構建交易
transaction = contract.functions.transfer(
to_address,
amount_wei
).build_transaction({
'nonce': nonce,
'gas': 100000,
'gasPrice': self.web3.eth.gas_price,
'chainId': 1
})
# 簽名並發送
signed_tx = self.web3.eth.account.sign_transaction(transaction, self.account.key)
tx_hash = self.web3.eth.send_raw_transaction(signed_tx.rawTransaction)
print(f"📤 代幣轉帳已發送!")
print(f" TX Hash: {tx_hash.hex()}")
receipt = self.web3.eth.wait_for_transaction_receipt(tx_hash)
if receipt['status'] == 1:
print("✅ 轉帳成功!")
else:
print("❌ 轉帳失敗")
return tx_hash.hex()
# ============================================
# 6. 查詢交易詳情
# ============================================
def get_transaction(self, tx_hash):
"""查詢交易詳情"""
tx = self.web3.eth.get_transaction(tx_hash)
receipt = self.web3.eth.get_transaction_receipt(tx_hash)
print(f"📋 交易詳情:")
print(f" Hash: {tx_hash}")
print(f" From: {tx['from']}")
print(f" To: {tx['to']}")
print(f" Value: {self.web3.from_wei(tx['value'], 'ether')} ETH")
print(f" Block: {receipt['blockNumber']}")
print(f" Gas Used: {receipt['gasUsed']}")
print(f" Status: {'Success' if receipt['status'] == 1 else 'Failed'}")
return {'transaction': tx, 'receipt': receipt}
# ============================================
# 使用示例
# ============================================
if __name__ == "__main__":
# 創建錢包實例
wallet = EthereumWallet()
# 方法 1: 創建新錢包
# wallet_info = wallet.create_wallet()
# 方法 2: 導入現有錢包
wallet.import_from_private_key("YOUR_PRIVATE_KEY")
# 查詢餘額
wallet.get_balance()
# 查詢 USDT 餘額
USDT_CONTRACT = "0xdAC17F958D2ee523a2206206994597C13D831ec7"
wallet.get_token_balance(USDT_CONTRACT, decimals=6)
# 發送 ETH
# wallet.send_eth("0xRecipient...", 0.01)
# 發送 USDT
# wallet.send_token(USDT_CONTRACT, "0xRecipient...", 100, decimals=6)
常見問題 FAQ
Q1: Transfer Hash 和 Block Hash 有什麼區別?
答:
-
Transfer Hash (交易哈希):
- 標識單筆交易
- 由交易數據計算得出
- 格式:
0x1234...(64 字符)
-
Block Hash (區塊哈希):
- 標識整個區塊
- 由區塊頭數據計算得出
- 包含區塊內所有交易的 Merkle Root
Block Hash: 0xaabbccdd... (區塊唯一標識)
├─ Transaction 1: 0x1111...
├─ Transaction 2: 0x2222... ← Transfer Hash
└─ Transaction 3: 0x3333...
Q2: 為什麼我的交易一直 Pending?
可能原因:
-
Gas Price 太低
- 解決:提高 Gas Price 或使用 EIP-1559
-
Nonce 錯誤
- 解決:檢查 nonce 是否連續
-
網路擁堵
- 解決:等待或使用加速工具
-
Gas Limit 不足
- 解決:增加 Gas Limit
Q3: 私鑰洩漏會怎樣?
答:
- ❌ 任何人都能用您的私鑰簽名交易
- ❌ 您的所有資產都會被盜
- ❌ 無法追回(區塊鏈交易不可逆)
防護措施:
- ✅ 永不在網路上傳輸私鑰
- ✅ 使用硬體錢包(Ledger/Trezor)
- ✅ 備份助記詞到物理介質(紙張、金屬板)
- ✅ 使用多簽錢包(大額資產)
Q4: 一條鏈可以部署多少個合約?
答:理論上無限個!
- 每個合約都有唯一的地址
- 目前以太坊主網上已有數百萬個合約
- 合約地址由部署者地址和 nonce 計算得出
# 合約地址計算公式
contract_address = Keccak256(
RLP([deployer_address, nonce])
)[12:] # 取後 20 位元組
Q5: Gas Used 和 Gas Limit 的區別?
| 概念 | 定義 | 何時確定 | 能否退回 |
|---|---|---|---|
| Gas Limit | 願意支付的最大 Gas | 發送交易前 | ✅ 未用完會退回 |
| Gas Used | 實際消耗的 Gas | 交易執行後 | ❌ 已消耗不退回 |
例子:
Gas Limit: 100,000 (你願意最多花這麼多)
Gas Used: 52,345 (實際只用了這麼多)
Gas Refund: 47,655 (退回給你)
最終費用 = 52,345 × Gas Price
總結
🎯 核心要點回顧
1️⃣ 鏈、合約、區塊的關係:
- 一條鏈 = 一個完整的區塊鏈網路
- 一個區塊 = 鏈上的一個數據單位
- 一個合約 = 部署在鏈上的一段程式碼
- ❌ 一條鏈 ≠ 一個合約(這是錯誤觀念)
2️⃣ 為什麼需要私鑰簽章:
- ✅ 證明交易確實由您發起(身份驗證)
- ✅ 防止交易被篡改(完整性)
- ✅ 無法否認交易(不可否認性)
- ❌ 沒有簽章 = 任何人都能偽造您的交易!
3️⃣ 完整交易流程:
- 步驟 0-1:構造交易
- 步驟 2:私鑰簽章(最關鍵!)
- 步驟 3-4:廣播到網路,進入 Mempool
- 步驟 5-6:驗證者打包進區塊
- 步驟 7:EVM 執行交易
- 步驟 8-9:區塊共識與確認
- 步驟 10:交易完成
4️⃣ 錢包與監聽器:
- 錢包負責:密鑰管理、交易簽名、餘額查詢
- 監聽器負責:追蹤區塊、解析事件、通知使用者
更新日誌
- 2025-01-13: 繁體中文完整版創建
- 詳細解釋鏈、合約、區塊的關係
- 完整交易流程(10 個步驟)
- 私鑰簽章的必要性與原理
- 區塊結構詳解
- 錢包與監聽器架構(基於白板內容)
- 完整代碼實作範例
本文檔持續更新中...
如有問題或建議,歡迎提交 Issue!