🎯 什麼情境該想到我

當你要搞懂「以太坊上一筆交易到底送出了哪些欄位、為什麼會卡住、合約呼叫是怎麼被編碼進去的」時。

⚙️ 怎麼用(理解模型)

1. 只有兩種帳戶,而且只有一種能發起交易

以太坊沒有 UTXO,只有帳戶,且分兩類:

“Externally owned accounts are those that have a private key; having the private key means control over access to funds or contracts. Now, you’re probably guessing there is another type of account. That other type of account is a contract account. A contract account has smart contract code, which a simple EOA can’t have. Furthermore, a contract account does not have a private key. Instead, it is owned (and controlled) by the logic of its smart contract code: the software program recorded on the Ethereum blockchain at the contract account’s creation and executed by the EVM.”
(譯文:外部擁有帳戶就是那些擁有私鑰的帳戶;持有私鑰即代表能控制對資金或合約的存取。你大概已經猜到還有另一種帳戶,那就是合約帳戶。合約帳戶擁有智能合約程式碼,這是單純的 EOA 不會有的。此外,合約帳戶沒有私鑰,而是由它自己的智能合約程式碼邏輯所擁有與控制——那份程式在合約帳戶建立時就記錄在以太坊區塊鏈上,並由 EVM 執行。)
—— Ch.2 “Externally Owned Accounts (EOAs) and Contracts”(PDF p.90)

關鍵不對稱:

“Note that because a contract account does not have a private key, it cannot initiate a transaction. Only EOAs can initiate transactions, but contracts can react to transactions by calling other contracts, building complex execution paths.”
(譯文:注意,因為合約帳戶沒有私鑰,它無法發起交易。只有 EOA 能發起交易,但合約可以對交易做出反應、去呼叫其他合約,組成複雜的執行路徑。)
—— Ch.2 “Externally Owned Accounts (EOAs) and Contracts”(PDF p.90)

所以「一切都從一筆 EOA 簽的交易開始」——書在 Ch.6 開頭就把話講死:

“Transactions are signed messages originated by an externally owned account, transmitted by the Ethereum network, and recorded on the Ethereum blockchain. … Contracts don’t run on their own. Ethereum doesn’t run autonomously. Everything starts with a transaction.”
(譯文:交易是由外部擁有帳戶發起、經以太坊網路傳播、並記錄在以太坊區塊鏈上的已簽章訊息。……合約不會自己跑。以太坊不會自動運轉。一切都從一筆交易開始。)
—— Ch.6 開篇(PDF p.207)

2. 一筆交易到底送出了什麼(序列化欄位)

網路上實際傳的是 RLP 編碼的二進位訊息,只含這些欄位(書中逐欄定義,此處為譯文整理):

欄位書中定義(譯文)
nonce由發起的 EOA 給出的序號,用來防止訊息重放
gas price發起人願意支付的 gas 價格(以 wei 計)
gas limit發起人願意為這筆交易購買的 gas 上限
recipient目的地以太坊地址
value要送到目的地的 ether 數量
data變動長度的二進位資料負載
v, r, s發起 EOA 的 ECDSA 數位簽章的三個組成

“Note that the field labels (to, gas limit, etc.) are shown here for clarity, but are not part of the transaction serialized data, which contains the field values RLP-encoded.”
(譯文:請注意,這裡列出的欄位名稱(to、gas limit 等)只是為了說明清楚,它們並不是交易序列化資料的一部分;序列化資料裡只有 RLP 編碼後的欄位值。)
—— Ch.6 “The Structure of a Transaction”(PDF p.209)

沒有 from 欄位——這是最反直覺的一點:

“For example, you may notice there is no “from” data in the address identifying the originator EOA. That is because the EOA’s public key can be derived from the v,r,s components of the ECDSA signature. The address can, in turn, be derived from the public key.”
(譯文:舉例來說,你可能會注意到裡面沒有標示發起者 EOA 的「from」資料。那是因為 EOA 的公鑰可以從 ECDSA 簽章的 v、r、s 三個組成推導出來,而地址又可以進一步從公鑰推導出來。)
—— Ch.6 “The Structure of a Transaction”(PDF p.209)

你在區塊瀏覽器看到的 from、區塊高度、交易 ID,都是軟體事後從交易「推導」出來加上去的,不在訊息本體裡。

3. nonce:既排順序,也防重放

書給的兩個場景(Ch.6 “The Transaction Nonce”, PDF p.210–211):

  • 排序:你先送 6 ether、再送 8 ether,但帳上只有 10 ether。去中心化網路裡節點收到的先後是隨機的;有了 nonce(例如 3 和 4),nonce 4 那筆會被擱著,直到 0–3 都處理完為止。
  • 防重放:沒有 nonce 的話,兩筆「同金額同收款人」的交易長得一模一樣,任何看到你交易的人都能複製貼上重送到你的 ether 被榨乾。有 nonce,每一筆都獨一無二。

書明講這正是帳戶模型必須付出的代價:

“In summary, it is important to note that the use of the nonce is actually vital for an account-based protocol, in contrast to the “Unspent Transaction Output” (UTXO) mechanism of the Bitcoin protocol.”
(譯文:總結來說,必須注意的是:對一個以帳戶為基礎的協定而言,nonce 的使用是至關重要的;這與比特幣協定的「未花費交易輸出」(UTXO)機制形成對比。)
—— Ch.6 “The Transaction Nonce”(PDF p.211)

實務上 nonce 從 0 開始計數,且不是明著存在帳戶狀態裡,而是「數這個地址已確認的交易筆數」動態算出來的。查法:web3.eth.getTransactionCount(address)

4. 交易卡住=nonce 有缺口

“The Ethereum network processes transactions sequentially, based on the nonce. That means that if you transmit a transaction with nonce 0 and then transmit a transaction with nonce 2, the second transaction will not be included in any blocks. It will be stored in the mempool, while the Ethereum network waits for the missing nonce to appear.”
(譯文:以太坊網路依照 nonce 依序處理交易。這表示如果你送出一筆 nonce 為 0 的交易,接著送出一筆 nonce 為 2 的交易,第二筆不會被納入任何區塊。它會被存在 mempool 裡,網路則等著缺掉的那個 nonce 出現。)
—— Ch.6 “Gaps in Nonces, Duplicate Nonces, and Confirmation”(PDF p.215)

推論出三條處置原則(全部照書):

  1. 補洞就通:把缺的那個 nonce 用一筆有效交易送出去,後面卡住的會一起被打包。
  2. 補洞不可逆:一旦缺號那筆被驗證,所有後續已廣播的交易會陸續變有效——it is not possible to “recall” a transaction!(譯文:你沒辦法「收回」一筆交易!)
  3. 重複 nonce 是賭運氣:同 nonce 送兩筆不同內容,一筆確認一筆被拒,哪筆贏取決於誰先到達第一個驗證節點,基本上是隨機的。

5. value 與 data 的四種組合

“A transaction with only value is a payment. A transaction with only data is an invocation. A transaction with both value and data is both a payment and an invocation. A transaction with neither value nor data — well that’s probably just a waste of gas! But it is still possible.”
(譯文:只有 value 的交易是一筆付款。只有 data 的交易是一次呼叫。同時有 value 和 data 的交易既是付款也是呼叫。兩者都沒有的交易——嗯,那大概只是在浪費 gas!但它仍然是可能的。)
—— Ch.6 “Transaction Value and Data”(PDF p.223)

收款方是 EOA 還是合約,行為不同:送到 EOA 只是加餘額,data 會被協定忽略(怎麼解讀由錢包自己決定,且不受共識規則約束);送到合約則會讓 EVM 執行合約,並嘗試呼叫 data 裡指名的 function。沒有 data 時會呼叫 fallback function,若該 function 是 payable 就執行它;連 fallback 都沒有,效果就只是增加合約餘額。

6. 合約呼叫怎麼被編碼成 data

“The data payload sent to an ABI-compatible contract (which you can assume all contracts are) is a hex-serialized encoding of: A function selector — The first 4 bytes of the Keccak-256 hash of the function’s prototype. This allows the contract to unambiguously identify which function you wish to invoke. The function arguments — The function’s arguments, encoded according to the rules for the various elementary types defined in the ABI specification.”
(譯文:送往 ABI 相容合約(你可以假設所有合約都是)的資料負載,是以下兩者的十六進位序列化編碼:函式選擇器——函式原型的 Keccak-256 雜湊值的前 4 個位元組,讓合約能毫不含糊地辨識出你想呼叫哪個函式。函式引數——依照 ABI 規格中各種基本型別的規則編碼的函式引數。)
—— Ch.6 “Transmitting a Data Payload to an EOA or Contract”(PDF p.227)

書上的完整範例(Ch.6, PDF p.227–228):

  1. 函式原型 = 函式名 + 括號內以逗號分隔的各引數型別 → withdraw(uint256)uintuint256 的別名)。
  2. web3.sha3("withdraw(uint256)")0x2e1a7d4d1332…,取前 4 bytes → 0x2e1a7d4d 就是 selector。
  3. 引數 0.01 ether = 10000000000000000 wei = 0x2386f26fc10000,補齊到 32 bytes。
  4. 串起來就是 data:
    2e1a7d4d000000000000000000000000000000000000000000000000002386f26fc10000

7. 簽章:簽的是雜湊,不是交易本身

“When we say “sign the transaction” we actually mean “sign the Keccak-256 hash of the RLP-serialized transaction data.” The signature is applied to the hash of the transaction data, not the transaction itself.”
(譯文:當我們說「簽署交易」時,實際的意思是「簽署 RLP 序列化交易資料的 Keccak-256 雜湊值」。簽章是施加在交易資料的雜湊上,而不是交易本身。)
—— Ch.6 “Transaction Signing in Practice”(PDF p.240)

五個步驟(照書):

  1. 建立含九個欄位的交易資料結構:nonce、gasPrice、gasLimit、to、value、data、chainID、0、0。
  2. 對這個結構做 RLP 序列化。
  3. 算它的 Keccak-256 雜湊。
  4. 用發起 EOA 的私鑰對雜湊算 ECDSA 簽章。
  5. 把算出的 v、r、s 附加回交易。

多出來的 chainID、0、0 來自 EIP-155「Simple Replay Attack Protection」(Spurious Dragon 硬分叉,區塊 #2,675,000 導入):把鏈識別碼放進被簽的資料裡,一改鏈 ID 簽章就失效,因此為 A 鏈造的交易無法在 B 鏈重放。主網 chain ID = 1、Ropsten = 3、Rinkeby = 4、Kovan = 42、Ethereum Classic 主網 = 61。

v 同時編碼兩件事:chain ID,以及復原識別碼(27/28 是舊式簽章,35/36 是完整 Spurious Dragon 式),後者用來標示公鑰 y 座標的奇偶。

8. 公鑰復原(recovery):from 是算出來的

從 r、s 可以算出兩個可能的公鑰(因為橢圓曲線對 x 軸對稱,同一個 x 有兩個點 R 與 R’):K₁ = r⁻¹(sR − zG)、K₂ = r⁻¹(sR’ − zG),其中 z 是訊息雜湊的最低 n 位元、G 是曲線生成點。

“To make things more efficient, the transaction signature includes a prefix value v, which tells us which of the two possible R values is the ephemeral public key. If v is even, then R is the correct value. If v is odd, then it is R’. That way, we need to calculate only one value for R and only one value for K.”
(譯文:為了讓過程更有效率,交易簽章包含一個前綴值 v,告訴我們兩個可能的 R 值中哪一個才是臨時公鑰。如果 v 是偶數,R 就是正確的值;如果 v 是奇數,那就是 R’。這樣一來我們只需要計算一個 R 值和一個 K 值。)
—— Ch.6 “The Signature Prefix Value (v) and Public Key Recovery”(PDF p.246)

9. 建立合約=送到零地址

合約建立交易的 to 欄位填 0x0,data 放編譯好的 bytecode。零地址既不是 EOA 也不是合約,永遠不能花錢也不能發起交易,只作為目的地、代表「建立這份合約」。想燒幣請用專用的 burn address 0x000000000000000000000000000000000000dEaD,別用 0x0。交易收據(receipt)裡的 contractAddress 就是新合約地址。

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 本卡的 gas 機制是本書(2018)當時的單一 gasPrice 模型gasPrice 是發起人自己設定的、以 wei/gas 計價的單一價格,出價越高越快確認,最低可以設 0(協定不禁止免費交易,只是可能永遠不被確認)。書用 MetaMask 的例子是 3 gwei × 21,000 gas = 0.000063 ETH。書裡就是這樣寫的,本卡不做任何現代化改寫(見下方「刻意不寫」)。
  • gasLimit 是「願意買的上限」,不是預付:驗證時只檢查餘額夠不夠付 gasPrice * gas,實際只按用掉的量計費;但送出前餘額必須足以支付你願付的最大值。收款方若是合約,gas 用量只能估、無法精確預測(不同執行路徑成本不同)。
  • 協定不驗證收款地址:任何 20 bytes 值都算合法。送到沒有對應私鑰也沒有合約的地址=把 ether 燒掉、永遠拿不回來。驗證只能在 UI 層做。
  • 併發送交易很危險:多台機器用同一個地址簽交易時 nonce 極難協調;指派 nonce 的那台機器變成單點故障,而任何一個被指派卻沒用掉的 nonce 都會讓後續交易全部卡住。書的結論是:多數實作乾脆放棄併發,改用單一流程處理提領,或設多個各自獨立的熱錢包。
  • 別用 getTransactionCount 數 pending:短時間連送多筆時它數不準。只有在 pending 與 confirmed 數量相等時才可信;之後要靠應用自己追。Parity 的 parity_nextNonce 則能正確計數。
  • 以太坊沒有原生多簽:EOA 的基本轉帳「沒有任何多重簽章的機制」,多簽得靠錢包合約自己實作——彈性換來的是雙面刃,安全性完全取決於那份多簽合約的程式碼品質。
  • 這張卡只講到「交易被記錄上鏈」為止:EVM 內部怎麼執行、gas 每個 opcode 怎麼收,看 工具-Gas與EVM

🔗 相關工具

  • 工具-UTXO交易模型 —— 對照組:兩種記帳哲學。比特幣的帳本不存餘額、只存「還沒被花掉的輸出」,交易是「消耗舊 UTXO、產生新 UTXO」,防雙花靠「一個 UTXO 只能花一次」這件事本身;以太坊反過來,帳本直接存帳戶餘額與狀態,同一個帳戶會被反覆改寫,所以必須額外發明 nonce 來排序與防重放(本書 Ch.6 就是這樣點名對比的)。副作用也隨之而來:UTXO 天然可平行驗證、天然無序無關,帳戶模型則是嚴格序列、一個缺口就整串卡住。
  • 工具-Gas與EVM —— 同書:本卡的 gasPricegasLimit 兩個欄位只是入口,收費規則與 EVM 執行細節在那張。
  • 工具-金鑰地址與錢包 —— 金鑰那一層兩鏈共通:本卡的 v/r/s 簽章、以及「地址由公鑰推導」都建立在同一套橢圓曲線私鑰/公鑰上。
  • 精通以太坊 —— 來源書卡