“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)
“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)
“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)
推論出三條處置原則(全部照書):
補洞就通:把缺的那個 nonce 用一筆有效交易送出去,後面卡住的會一起被打包。
補洞不可逆:一旦缺號那筆被驗證,所有後續已廣播的交易會陸續變有效——it is not possible to “recall” a transaction!(譯文:你沒辦法「收回」一筆交易!)
“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)
“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)
多出來的 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)
“The EVM operates in a much more limited domain: it is just a computation engine, and as such provides an abstraction of just computation and storage, similar to the Java Virtual Machine (JVM) specification, for example.”
(譯文:EVM 運作的領域侷限得多:它就只是一個運算引擎,因此提供的抽象也只有運算與儲存,類似於 Java 虛擬機(JVM)規格那樣。)
—— Ch.13 “Comparison with Existing Technology”(PDF p.546)
“The EVM has a stack-based architecture, storing all in-memory values on a stack. It works with a word size of 256 bits (mainly to facilitate native hashing and elliptic curve operations) and has several addressable data components:”
(譯文:EVM 採用堆疊式(stack-based)架構,把所有記憶體內的值都存放在一個堆疊上。它的字組大小(word size)是 256 位元(主要是為了方便原生的雜湊與橢圓曲線運算),並且有數個可定址的資料元件:)
—— Ch.13 “What Is the EVM?”(PDF p.543)
“As you might expect, all operands are taken from the stack, and the result (where applicable) is often put back on the top of the stack.”
(譯文:如你所料,所有運算元都取自堆疊,而結果(若適用)通常會被放回堆疊頂端。)
—— Ch.13 “The EVM Instruction Set (Bytecode Operations)“(PDF p.547)
“As code execution progresses, the gas supply is reduced according to the gas cost of the operations executed. If at any point the gas supply is reduced to zero we get an “Out of Gas” (OOG) exception; execution immediately halts and the transaction is abandoned. No changes to the Ethereum state are applied, except for the sender’s nonce being incremented and their ether balance going down to pay the block’s beneficiary for the resources used to execute the code to the halting point.”
(譯文:隨著程式碼執行推進,gas 供給量會依照所執行操作的 gas 成本而減少。如果在任何時點 gas 供給量降到零,我們就會得到一個「Out of Gas」(OOG)例外;執行立即中止,該筆交易被放棄。以太坊狀態不會套用任何變更,唯一的例外是發送者的 nonce 會遞增、且其 ether 餘額會減少,用以支付區塊受益者為了執行程式碼到中止點所耗用的資源。)
—— Ch.13 “Ethereum State”(PDF p.551–552)
書給的心智模型是沙盒:EVM 跑在以太坊 world state 的一份沙盒副本上,只要執行因任何理由無法完成,這份沙盒版本就被整份丟棄;若順利完成,真實狀態才更新成沙盒版本(包含被呼叫合約的 storage 變更、新建立的合約、以及所有已發起的 ether 餘額轉移)。
執行是遞迴的:合約可以呼叫其他合約,每次呼叫都會在新目標上再實例化一個 EVM,其沙盒狀態由上一層的沙盒初始化,並被指定一份 gas supply(當然不能超過上一層剩下的量),因此子層自己也可能因為分到的 gas 太少而以例外中止;這種情況下沙盒狀態被丟棄,執行回到上一層的 EVM。
4. opcode 的完整分類
書先給了一個概觀:EVM 指令集提供「算術與位元邏輯運算、執行脈絡查詢、stack/memory/storage 存取、控制流程操作、記錄(logging)/呼叫與其他運算子」,另外還能取得帳戶資訊(地址、餘額)與區塊資訊(區塊編號、當前 gas price)。
接著是那句分類宣告——“The available opcodes can be divided into the following categories:“(譯文:可用的 opcode 可以分成下列幾類:),完整 7 類如下(“The EVM Instruction Set (Bytecode Operations)“,p.547–550):
DELEGATECALL:用「別的帳戶的程式碼」對本帳戶做訊息呼叫,但 sender 與 value 沿用當前值。
GAS:取得可用的 gas 量(已扣掉本指令的部分)。
BLOCKHASH:只拿得到最近 256 個已完成區塊的雜湊。
5. Turing completeness and gas:gas 就是停機問題的解
這一節是整章的中心論證。
“This capability, however, comes with an very important caveat: some programs take forever to run. An important aspect of this is that we can’t tell, just by looking at a program, whether it will take forever or not to execute. … This is called the halting problem and would be a huge problem for Ethereum if it were not addressed.”
(譯文:然而這個能力帶著一個非常重要的但書:有些程式會永遠跑不完。其中很關鍵的一點是,我們無法光看一支程式就判斷它會不會永遠執行下去。……這就是所謂的停機問題,若不加以處理,對以太坊會是個大麻煩。)
—— Ch.13 “Turing Completeness and Gas”(PDF p.566)
為什麼對以太坊特別致命:前面說過它像一台沒有排程器的單執行緒機器,一旦卡進無窮迴圈就整台不能用了。
解法:
“However, with gas, there is a solution: if after a prespecified maximum amount of computation has been performed, the execution hasn’t ended, the execution of the program is halted by the EVM. This makes the EVM a quasi–Turing-complete machine: it can run any program you feed into it, but only if the program terminates within a particular amount of computation.”
(譯文:然而有了 gas 就有解:如果在執行完預先指定的最大運算量之後程式還沒結束,EVM 就會中止這支程式的執行。這使得 EVM 成為一台準圖靈完備(quasi–Turing-complete)的機器:你餵給它的任何程式它都能跑,但前提是這支程式要在某個特定的運算量之內終止。)
—— Ch.13 “Turing Completeness and Gas”(PDF p.566)
同樣的話在章首出現過一次(“What Is the EVM?”,p.543):EVM 是準圖靈完備的狀態機,「quasi」是因為所有執行過程都被該次合約執行可用的 gas 量限制在有限步數內;因此停機問題「被解決了」(所有程式執行都會停),而執行可能(不論意外或惡意)永遠跑下去、進而讓整個以太坊平台停擺的情況也被避免了。
書特別註明那個上限不是固定的:你可以付錢把它提高,最高到「block gas limit」,而大家也可以隨時間一起同意調高那個上限;但在任一時刻上限都存在,執行時消耗太多 gas 的交易會被中止。
6. gas 的角色與計費
gas 是什麼(“Gas”,p.567):
“Gas is Ethereum’s unit for measuring the computational and storage resources required to perform actions on the Ethereum blockchain. In contrast to Bitcoin, whose transaction fees only take into account the size of a transaction in kilobytes, Ethereum must account for every computational step performed by transactions and smart contract code execution.”
(譯文:gas 是以太坊用來衡量「在以太坊區塊鏈上執行動作所需的運算與儲存資源」的單位。相對於比特幣——它的交易手續費只考慮交易以 KB 計的大小——以太坊必須為交易與智能合約程式碼執行所進行的每一個運算步驟記帳。)
—— Ch.13 “Gas”(PDF p.567)
書從 Yellow Paper 舉的三個例子:兩數相加 3 gas;算一次 Keccak-256 是 30 gas + 每 256 bits 被雜湊的資料再加 6 gas;送出一筆交易 21,000 gas。
執行期間怎麼記帳(“Gas Accounting During Execution”,p.568):
EVM 一開始拿到的 gas supply = 交易中指定的 gas limit。
每個被執行的 opcode 都有 gas 成本,EVM 一步步走、供給量一路減少。
每個操作之前,EVM 會先檢查 gas 夠不夠付這個操作;不夠就中止執行、交易回滾。
成功跑完(沒耗盡 gas):用掉的 gas 成本按交易指定的 gas price 換成 ether 付給礦工當手續費。
miner fee = gas cost * gas price
remaining gas = gas limit - gas cost
refunded ether = remaining gas * gas price
out of gas:操作立即終止,拋出 out of gas 例外,交易回滾、所有狀態變更被撤銷。
“Although the transaction was unsuccessful, the sender will be charged a transaction fee, as miners have already performed the computational work up to that point and must be compensated for doing so.”
(譯文:雖然這筆交易失敗了,發送者仍會被收取交易手續費,因為礦工已經執行了到那個時點為止的運算工作,必須獲得補償。)
—— Ch.13 “Gas Accounting During Execution”(PDF p.568)
gas cost 與 gas price 是兩回事(“Gas Cost Versus Gas Price”,p.570)——書自己做的 recap:
Gas cost:執行某個特定操作所需的 gas「單位數」。
Gas price:你送交易到以太坊網路時,願意為「每一單位 gas」支付的 ether 金額。
transaction fee = total gas used * gas price paid (in ether)
發送者指定自己願付的 gas price,讓市場去決定以太幣價格與運算成本(以 gas 計)之間的關係;礦工在組新區塊時可以從待處理交易中挑出價較高的,所以出高一點的 gas price 會誘使礦工把你的交易納入、更快確認。實務上發送者設的 gas limit 會大於或等於預期用量,設得比實際消耗高的話多的部分會退還,因為礦工只為實際做的工作獲得補償。
書還附了一個容易搞混的提醒:
“While gas has a price, it cannot be “owned” nor “spent.” Gas exists only inside the EVM, as a count of how much computational work is being performed.”
(譯文:gas 雖然有價格,但它無法被「擁有」也無法被「花用」。gas 只存在於 EVM 之內,作為「執行了多少運算工作」的計數。)
—— Ch.13 “Gas Cost Versus Gas Price”(PDF p.570)
發送者被收取的是 ether 手續費,這筆錢被換算成 gas 供 EVM 記帳,最後再換回 ether 付給礦工。
退款機制:負的 gas 成本(“Negative gas costs”,p.571)。以太坊用「退還部分執行期間用掉的 gas」來鼓勵刪除不再需要的 storage 變數與帳戶,EVM 中有兩個負 gas 成本的操作:
操作
退款
刪除一份合約(SELFDESTRUCT)
24,000 gas
把某個 storage 位址從非零值改成零(SSTORE[x] = 0)
15,000 gas
“To avoid exploitation of the refund mechanism, the maximum refund for a transaction is set to half the total amount of gas used (rounded down).”
(譯文:為避免退款機制被濫用,一筆交易的最高退款額被設定為「所使用 gas 總量的一半」(無條件捨去)。)
—— Ch.13 “Negative gas costs”(PDF p.571)
block gas limit(“Block Gas Limit”,p.572):一個區塊中所有交易可消耗的 gas 上限,限制了一個區塊能塞進多少交易。書的例子:五筆交易 gas limit 分別為 30,000/30,000/40,000/50,000/50,000,若 block gas limit 是 180,000,其中任四筆可進同一個區塊,第五筆要等下一個區塊。礦工若想塞進一筆需要 gas 超過當前 block gas limit 的交易,整個區塊會被網路拒絕;多數以太坊客戶端會先給你「transaction exceeds block gas limit」的警告擋下來。
上限由誰決定:礦工集體決定。協定內建投票機制,每個區塊的礦工可以把 block gas limit 往任一方向調整 1/1,024(0.0976%),形成隨網路需求浮動的區塊大小;預設挖礦策略是投給「至少 4.7 million gas,但以近期每區塊平均總用量的 150% 為目標(用 1,024 個區塊的指數移動平均)」。
7. 額外:dispatcher 為什麼要檢查 calldata 有沒有 4 bytes
Ch.13 的 “Disassembling the Bytecode”(p.560–565)把 Faucet.sol 的 runtime bytecode 拆開看,開頭那段就是 dispatcher:讀進交易的 data 欄位,把相關部分送到對應的 function。
“Each function is identified by the first 4 bytes of its Keccak-256 hash.”
(譯文:每個函式都由它的 Keccak-256 雜湊值的前 4 個位元組來識別。)
—— Ch.13 “Disassembling the Bytecode”(PDF p.560)
本卡的 gas 機制是本書(2018)當時的單一 gasPrice 市場模型:發送者自己指定一個 gas price,礦工挑高價的先打包,手續費全額付給礦工(transaction fee = total gas used * gas price paid)。書裡就是這樣寫的,本卡完全不做現代化改寫(見下方「刻意不寫的東西」)。
子呼叫的 gas 是被分配的:合約呼叫合約時,每一層拿到的 gas 不能超過上一層剩餘量,所以子層可能單獨 OOG 而中止,執行回到上一層——這正是很多安全反模式的溫床,見 工具-智能合約安全反模式(例如只給 2300 gas 的 transfer、未檢查回傳值的 send、以及靠迴圈撐爆 block gas limit 的 DoS)。
書中的 block gas limit 是「寫作當時」的 8 million gas(約可容納 380 筆 21,000 gas 的基本交易),這是 2018 年的快照,不是常數。
本卡只涵蓋 Ch.7 “Smart Contracts and Solidity”(PDF p.254–310)——合約的定義、生命週期、Solidity 的基本語言構件。安全反模式(重入、溢位、權限、搶跑…)全部在 工具-智能合約安全反模式(Ch.9),本卡不重複。
⚙️ 怎麼用(心法與注意)
1. 先把「smart contract」這個名字的誤導拆掉
Ch.7 “What Is a Smart Contract?”(PDF p.255)直接說這個詞在以太坊的脈絡下是個誤稱:
“In the 1990s, cryptographer Nick Szabo coined the term and defined it as ‘a set of promises, specified in digital form, including protocols within which the parties perform on the other promises.’ … In the context of Ethereum, the term is actually a bit of a misnomer, given that Ethereum smart contracts are neither smart nor legal contracts, but the term has stuck.”
—— 譯文:1990 年代,密碼學家 Nick Szabo 造出這個詞,把它定義為「一組以數位形式指定的承諾,包含各方履行其他承諾所依循的協定」。……在以太坊的脈絡下,這個詞其實有點名不副實,因為以太坊的智能合約既不聰明、也不是法律合約,但這個名字就這麼沿用下來了。
書自己採用的定義是:
“…immutable computer programs that run deterministically in the context of an Ethereum Virtual Machine as part of the Ethereum network protocol — i.e., on the decentralized Ethereum world computer.”
—— 譯文:……在以太坊虛擬機的脈絡中、作為以太坊網路協定的一部分而決定性地執行的不可變電腦程式——也就是跑在去中心化的以太坊世界電腦上。
書把這句定義拆成五個字(p.255–256),這五個字就是這張卡的骨架:
Computer programs(電腦程式)——“The word ‘contract’ has no legal meaning in this context.”(譯文:「合約」這個詞在這裡沒有任何法律意義。)
Decentralized world computer(去中心化世界電腦)——EVM 在每個節點各跑一份,但因為初始狀態相同、產出狀態也相同,整個系統對外表現得像一台電腦。
2. 合約帳戶沒有私鑰,它「自己擁有自己」
Ch.7 章首(PDF p.254)與 “Life Cycle of a Smart Contract”(p.257):合約帳戶同時擁有程式碼與資料儲存,而 EOA 兩者皆無;合約帳戶沒有私鑰,因此以其合約程式碼所預先規定的方式「控制自己」。
“As the contract creator, you don’t get any special privileges at the protocol level (although you can explicitly code them into the smart contract). You certainly don’t receive the private key for the contract account, which in fact does not exist — we can say that smart contract accounts own themselves.”
—— 譯文:身為合約的建立者,你在協定層面上不會拿到任何特權(不過你可以把特權明確寫進合約程式碼裡)。你當然也不會拿到合約帳戶的私鑰——那把私鑰根本不存在;我們可以說,智能合約帳戶擁有它自己。
實務含意:你想要的任何管理員權限,都得自己寫進程式碼(見下面的 onlyOwner)。
3. 合約不會自己跑——一定是交易觸發的
“Life Cycle of a Smart Contract”(PDF p.257):
“Importantly, contracts only run if they are called by a transaction. … Contracts never run ‘on their own’ or ‘in the background.’ Contracts effectively lie dormant until a transaction triggers execution, either directly or indirectly as part of a chain of contract calls.”
—— 譯文:重要的是,合約只有在被交易呼叫時才會執行。……合約絕不會「自己跑」或「在背景跑」。合約實際上是休眠的,直到某筆交易直接或間接(作為一連串合約呼叫的一環)觸發它為止。
同一段還給了三個常被忽略的性質:
任何執行鏈的第一個合約,一定是被某個 EOA 發起的交易呼叫的。
世界電腦可視為單執行緒機器,合約不會「平行」執行。
交易是原子的:不管它呼叫了幾個合約,全部成功才寫入狀態;中途出錯則所有狀態變更「回滾」(rolled back),彷彿沒發生過——但失敗仍被記錄,且 gas 照扣。
“Note that you must explicitly add this command to your contract if you want it to be deletable — this is the only way a contract can be deleted, and it is not present by default. In this way, users of a contract who might rely on a contract being there forever can be certain that a contract can’t be deleted if it doesn’t contain a SELFDESTRUCT opcode.”
—— 譯文:注意,如果你要讓合約可被刪除,必須明確把這道指令加進合約——這是刪除合約的唯一途徑,而且它預設不存在。如此一來,那些指望合約永遠存在的使用者,就能確定:只要合約裡沒有 SELFDESTRUCT opcode,它就刪不掉。
此後合約休眠,等交易呼叫;ABI + 部署位址就是外界互動所需的全部(p.269:“All that is needed for an application to interact with a contract is an ABI and the address where the contract has been deployed.”)。
“Keep in mind that the terms internal and private are somewhat misleading. Any function or data inside a contract is always visible on the public blockchain, meaning that anyone can see the code or data. The keywords described here only affect how and when a function can be called.”
—— 譯文:請記住,internal 與 private 這兩個詞有點誤導。合約內的任何函式或資料在公開區塊鏈上永遠是可見的,意思是任何人都能看到程式碼或資料。這裡描述的關鍵字只影響一個函式如何、以及何時可以被呼叫。
“Function modifiers are an extremely useful tool because they allow us to write preconditions for functions and apply them consistently, making the code easier to read and, as a result, easier to audit for security.”
—— 譯文:函式修飾詞是極其有用的工具,因為它讓我們能為函式寫下前置條件並一致地套用,使程式碼更易讀,因而也更容易做安全稽核。
“By convention, assert is used when the outcome is expected to be true, meaning that we use assert to test internal conditions. By comparison, require is used when testing inputs (such as function arguments or transaction fields), setting our expectations for those conditions.”
—— 譯文:依慣例,assert 用在「結果理應為真」的情況,也就是用它來檢驗內部條件;相對地,require 用來檢驗輸入(例如函式參數或交易欄位),為那些條件設定我們的預期。
“Events are especially useful for light clients and DApp services, which can ‘watch’ for specific events and report them to the user interface, or make a change in the state of the application to reflect an event in an underlying contract.”
—— 譯文:Events 對輕節點與 DApp 服務特別有用:它們可以「監看」特定事件,回報到使用者介面,或改變應用程式的狀態以反映底層合約中發生的事。
“Gas Considerations”(PDF p.304–307)。超過 gas limit 時的三件事:拋出 out of gas 例外 → 狀態回滾到執行前 → 付出去的 ether 當作交易手續費,不退。因為 gas 由發起交易的使用者付,高 gas 成本的函式會勸退使用者,所以壓低 gas 成本是寫合約的人的責任。書給兩條具體戒律:
Avoid Dynamically Sized Arrays(避免動態大小陣列)——任何走訪動態陣列的迴圈都有 gas 用爆的風險,可能在找到答案前就耗盡,白花時間與 ether 卻毫無結果。
Avoid Calls to Other Contracts(避免呼叫其他合約)——對方函式的 gas 成本未知就有 OOG 風險。並且:“Avoid using libraries that are not well tested and broadly used. The less scrutiny a library has received from other programmers, the greater the risk of using it.”(譯文:避免使用未經充分測試、未被廣泛使用的函式庫。一個函式庫受到其他程式設計者的檢視越少,用它的風險就越大。)
估算方式是 contract.myMethod.estimateGas(...)。書提醒這只是估計——EVM 是圖靈完備的,同一個函式不同呼叫路徑的 gas 可能天差地遠。書的建議是把評估函式 gas 成本納入開發流程,避免部署到主網時才驚訝。細節見 工具-Gas與EVM。
“When writing smart contracts, you must keep in mind that while you may mostly expect to be dealing with EOAs, there is nothing to stop arbitrarily complex and perhaps malign contracts from calling into and being called by your code.”
—— 譯文:寫智能合約時你必須謹記:雖然你多半預期打交道的對象是 EOA,但沒有任何機制能阻止任意複雜、可能懷有惡意的合約呼叫你的程式、或被你的程式呼叫。
“As with other programs, a smart contract will execute exactly what is written, which is not always what the programmer intended. Furthermore, all smart contracts are public, and any user can interact with them simply by creating a transaction. Any vulnerability can be exploited, and losses are almost always impossible to recover.”
—— 譯文:跟其他程式一樣,智能合約會完全照著寫的執行,而那不見得是寫的人想要的。此外,所有智能合約都是公開的,任何使用者只要發一筆交易就能與之互動。任何漏洞都會被利用,而損失幾乎總是無法追回。
第一層:防禦性設計五原則(Ch.9 “Security Best Practices”, PDF p.329–330)
書把 defensive programming 拆成五條,寫合約前先當檢查表:
Minimalism/simplicity(極簡)
“Complexity is the enemy of security. The simpler the code, and the less it does, the lower the chances are of a bug or unforeseen effect occurring.”
—— 譯文:複雜度是安全的敵人。程式越簡單、做的事越少,出現 bug 或非預期效果的機會就越低。
書講得很直白:如果有人跟你說他們的合約寫了「好幾千行程式碼」,你就該懷疑那個專案的安全性。Simpler is more secure.
“Writing DApps in Solidity is not like creating a web widget in JavaScript. Rather, you should apply rigorous engineering and software development methodologies, as you would in aerospace engineering or any similarly unforgiving discipline.”
—— 譯文:用 Solidity 寫 DApp 不像用 JavaScript 做一個網頁小工具。你應該套用嚴謹的工程與軟體開發方法論,就像做航太工程或任何同樣不容出錯的領域那樣。
“You should never assume that input, such as function arguments, is well formed, properly bounded, or has a benign purpose.”
—— 譯文:你絕不該假設輸入(例如函式參數)格式良好、範圍正確、或抱著善意。
第二層:七個著墨最深的反模式
1. Reentrancy 重入(Ch.9 “Reentrancy”, PDF p.332–339)
漏洞:合約把 ether 送到一個未知位址時,對方的 fallback function 會被觸發,而那段惡意程式碼可以再呼叫回原合約——路徑「reenter(重入)」了。
checks-effects-interactions pattern:所有改 state 的邏輯都放在送錢/外部呼叫之前;對未知位址的外部呼叫要是該段程式的最後一個動作。
加 mutex:用一個 state variable 在執行期間鎖住合約,擋掉重入呼叫。
真實案例:The DAO
“The DAO (Decentralized Autonomous Organization) attack was one of the major hacks that occurred in the early development of Ethereum. At the time, the contract held over $150 million. Reentrancy played a major role in the attack, which ultimately led to the hard fork that created Ethereum Classic (ETC).”
—— 譯文:DAO(去中心化自治組織)攻擊是以太坊早期發展中的重大駭客事件之一。當時該合約持有超過 1.5 億美元。重入在這次攻擊中扮演了主要角色,最終導致了那次催生出 Ethereum Classic(ETC)的硬分叉。
2. Arithmetic Over/Underflows 算術溢位(PDF p.340–346)
漏洞:EVM 用定長整數型別。
“The Ethereum Virtual Machine specifies fixed-size data types for integers. This means that an integer variable can represent only a certain range of numbers. A uint8, for example, can only store numbers in the range [0,255]. Trying to store 256 into a uint8 will result in 0.”
—— 譯文:EVM 為整數指定了固定大小的資料型別。這表示一個整數變數只能表示某個範圍的數字。例如 uint8 只能存 [0,255] 範圍內的數;試圖把 256 存進 uint8 會得到 0。
“It is also important to notice that when we say that delegatecall is state-preserving, we are not talking about the variable names of the contract, but rather the actual storage slots to which those names point.”
—— 譯文:還有一點很重要:當我們說 delegatecall 會保留狀態時,指的不是合約的變數名稱,而是那些名稱所指向的實際 storage slot。
“As a result, all ether in all Parity multisig wallets of this type instantly became lost or permanently unrecoverable.”
—— 譯文:結果,所有這類 Parity 多簽錢包裡的 ether 瞬間全部遺失、永久無法取回。
“Keep in mind that in this type of ‘front-running’ vulnerability, miners are uniquely incentivized to run the attacks themselves (or can be bribed to run these attacks with extravagant fees). The possibility of the attacker being a miner themselves should not be underestimated.”
—— 譯文:請記住,在這類「搶跑」漏洞中,礦工有獨特的誘因親自執行攻擊(或可用誇張的手續費賄賂他們去執行)。不要低估攻擊者本身就是礦工的可能性。
“Perhaps the most fundamental software security principle is to maximize reuse of trusted code. In cryptography, this is so important it has been condensed into an adage: ‘Don’t roll your own crypto.’”
—— 譯文:也許最根本的軟體安全原則就是最大化重用可信任的程式碼。在密碼學中這件事重要到被濃縮成一句諺語:「別自己造密碼學。」
“Nowadays, “tokens” administered on blockchains are redefining the word to mean blockchain-based abstractions that can be owned and that represent assets, currency, or access rights.”
(譯文:如今,在區塊鏈上管理的「代幣」正在重新定義這個詞,使它意指「可被擁有、且代表資產、貨幣或存取權的區塊鏈式抽象物」。)
—— Ch.10 章首(PDF p.424)
“Tokens are fungible when we can substitute any single unit of the token for another without any difference in its value or function.”
(譯文:當我們能用代幣的任一單位替換另一單位,而其價值或功能毫無差異時,這種代幣就是同質化的。)
—— Ch.10 “Tokens and Fungibility”(PDF p.427)
“One of the most important ramifications of blockchain-based tokens is the ability to convert extrinsic assets into intrinsic assets and thereby remove counterparty risk.”
(譯文:以區塊鏈為基礎的代幣,最重要的後果之一,就是能把外生資產轉換成內生資產,藉此消除交易對手風險。)
—— Ch.10 “Tokens and Intrinsicality”(PDF p.429)
書舉的例子:從「公司股權(外生)」搬到「DAO 或類似組織中的股權/投票代幣(內生)」。
4. utility token vs equity token:這個專案該不該發幣
書把當時所有專案的發幣動機收斂成兩類,並直說這兩種角色常常被混為一談(“Using Tokens: Utility or Equity”,p.430):
代表對某物(例如一家新創)的控制權或所有權的份額。可以窄到只是分配股利與利潤的無投票權股份,也可以寬到是 DAO 中的投票股份,由代幣持有者透過複雜治理系統管理平台
然後書開了一個以本章最直白的標題寫成的小節——“It’s a Duck!”(p.431):代幣是很棒的募資機制,但向公眾發行證券(股權)在多數司法管轄區是受監管的行為。許多新創把 equity token 偽裝成 utility token,希望繞過監管、把公開募資包裝成「服務存取憑證」的預售。書的判斷是:
“As the popular saying goes: “If it walks like a duck and quacks like a duck, it’s a duck.” Regulators are not likely to be distracted by these semantic contortions; quite the opposite, they are more likely to see such legal sophistry as an attempt to deceive the public.”
(譯文:如同那句俗諺:「如果牠走起來像鴨子、叫起來也像鴨子,那牠就是鴨子。」監管機關不太可能被這些語意上的扭曲所迷惑;恰恰相反,他們更可能把這種法律詭辯視為欺騙公眾的意圖。)
—— Ch.10 “It’s a Duck!”(PDF p.431)
接著是 “Utility Tokens: Who Needs Them?”(p.432–434),論證非常值得抄進產品決策清單:
“Adopt a token because your application cannot work without a token. Adopt it because the token lifts a fundamental market barrier or solves an access problem. Don’t introduce a utility token because it is the only way you can raise money fast and you need to pretend it’s not a public securities offering.”
(譯文:採用代幣,是因為你的應用少了代幣就無法運作;採用它,是因為代幣消除了某個根本性的市場障礙、或解決了某個存取問題。不要因為那是你唯一能快速募資的方式、而且你需要假裝那不是公開的證券發行,才去引進一個 utility token。)
—— Ch.10 “Utility Tokens: Who Needs Them?”(PDF p.433–434)
5. 代幣活在合約層,協定根本不知道它存在
這是理解後面所有 ERC20 怪癖的唯一前提:
“Tokens are different from ether because the Ethereum protocol does not know anything about them. Sending ether is an intrinsic action of the Ethereum platform, but sending or even owning tokens is not. The ether balance of Ethereum accounts is handled at the protocol level, whereas the token balance of Ethereum accounts is handled at the smart contract level.”
(譯文:代幣不同於 ether,因為以太坊協定對它們一無所知。發送 ether 是以太坊平台的內建行為,但發送、甚至擁有代幣則不是。以太坊帳戶的 ether 餘額在協定層被處理,而代幣餘額則是在智能合約層被處理。)
—— Ch.10 “Tokens on Ethereum”(PDF p.435)
“The ERC20 standard defines a common interface for contracts implementing a token, such that any compatible token can be accessed and used in the same way.”
(譯文:ERC20 標準為實作代幣的合約定義了一套共通介面,使得任何相容的代幣都能以相同方式被存取與使用。)
—— Ch.10 “The ERC20 Token Standard”(PDF p.436)
必要 function 與 event(“ERC20 required functions and events”,p.436–437)——「一份符合 ERC20 的代幣合約至少必須提供下列 function 與 event」:
(1) 把代幣送到不支援代幣的合約地址=永久卡死。 書故意示範了這個災難:把 1,000 MET 送進前面章節的 Faucet 合約,然後問「怎麼領回來?」答案是:
“If you’re wondering what to do next, don’t. There is no solution to this problem. The MET sent to Faucet is stuck, forever. Only the Faucet contract can transfer it, and the Faucet contract doesn’t have code to call the transfer function of an ERC20 token contract.”
(譯文:如果你正在想接下來該怎麼辦——別想了。這個問題沒有解。送進 Faucet 的那些 MET 永遠卡住了。只有 Faucet 合約能轉走它們,而 Faucet 合約裡並沒有呼叫 ERC20 代幣合約 transfer 函式的程式碼。)
—— Ch.10 “Sending ERC20 tokens to contract addresses”(PDF p.451)
“In a token transfer, no transaction is actually sent to the recipient of the token. Instead, the recipient’s address is added to a map within the token contract itself. A transaction sending ether to an address changes the state of an address. A transaction transferring a token to an address only changes the state of the token contract, not the state of the recipient address.”
(譯文:在一次代幣移轉中,實際上沒有任何交易被送到代幣的收款人。取而代之的是,收款人的地址被加進代幣合約內部的一張對映表裡。送 ether 到某個地址的交易會改變該地址的狀態;而把代幣轉到某個地址的交易,只會改變代幣合約的狀態,不會改變收款地址的狀態。)
—— Ch.10 “Issues with ERC20 Tokens”(PDF p.455)
“To send ether or use any Ethereum contract you need ether to pay for gas. To send tokens, you also need ether. You cannot pay for a transaction’s gas with a token and the token contract can’t pay for the gas for you.”
(譯文:要發送 ether 或使用任何以太坊合約,你都需要 ether 來支付 gas。要發送代幣,你同樣需要 ether。你無法用代幣支付一筆交易的 gas,代幣合約也不能替你支付 gas。)
—— Ch.10 “Issues with ERC20 Tokens”(PDF p.456)
// Mapping from deed ID to ownermapping (uint256 => address) private deedOwner;
“Whereas ERC20 tracks the balances that belong to each owner, with the owner being the primary key of the mapping, ERC721 tracks each deed ID and who owns it, with the deed ID being the primary key of the mapping. From this basic difference flow all the properties of a non-fungible token.”
(譯文:ERC20 追蹤的是屬於每個擁有者的餘額,對映表的主鍵是擁有者;而 ERC721 追蹤的是每一個 deed ID 以及誰擁有它,對映表的主鍵是 deed ID。非同質化代幣的所有性質,都由這個基本差異衍生而來。)
—— Ch.10 “ERC721: Non-fungible Token (Deed) Standard”(PDF p.463)
標準是什麼(“What Are Token Standards? What Is Their Purpose?”,p.466):標準是實作的最低規格——要符合 ERC20,你至少要實作它指定的 function 與行為;你也可以自由加上標準之外的功能。
“The primary purpose of these standards is to encourage interoperability between contracts.”
(譯文:這些標準的主要目的,是促進合約之間的互通性。)
—— Ch.10 “What Are Token Standards? What Is Their Purpose?”(PDF p.466)
具體好處:所有錢包、交易所、使用者介面與其他基礎設施元件,都能以可預期的方式與任何遵循該規格的合約互動——你部署一份符合 ERC20 的合約,所有既有錢包的使用者就能無縫開始交易你的代幣,不需要升級錢包,你也不必額外做什麼。另一個關鍵性質:標準是描述性的(descriptive)而非規定性的(prescriptive),怎麼實作那些 function 由你決定,合約內部運作與標準無關;標準只有少數規範特定情況下行為的功能性要求(書舉的例子:transfer 在 value 為零時的行為)。
Security by maturity(p.468):選完標準還要選實作,而這個選擇有嚴重的安全意涵。
“Existing implementations are “battle-tested.” While it is impossible to prove that they are secure, many of them underpin millions of dollars’ worth of tokens. They have been attacked, repeatedly and vigorously. So far, no significant vulnerabilities have been discovered.”
(譯文:既有實作是「經過實戰檢驗」的。雖然無法證明它們安全,但其中許多支撐著價值數百萬美元的代幣,並且反覆而猛烈地被攻擊過。到目前為止,尚未發現重大漏洞。)
—— Ch.10 “Security by Maturity”(PDF p.468)
“Complexity is the enemy of security. Every single line of code you add expands the attack surface of your contract and could represent a vulnerability lying in wait.”
(譯文:複雜性是安全的敵人。你加的每一行程式碼都在擴大合約的攻擊面,都可能是一個潛伏等待的漏洞。)
—— Ch.10 “Security by Maturity”(PDF p.468)
常見的擴充功能(“Extensions to Token Interface Standards”,p.469–470):Owner control(給特定地址或多簽群組特殊能力:黑名單、白名單、鑄造、回收等)、Burning(把代幣送到不可花用的地址或直接抹掉餘額並減少供給)、Minting(以可預期的速率或依創建者「意志」增加總供給)、Crowdfunding(透過拍賣、市場銷售、反向拍賣等出售代幣)、Caps(為總供給設定預先定義且不可變的上限,與 minting 相反)、Recovery backdoors(由指定地址啟動的資金回收、反向轉帳或拆除代幣的函式)、Whitelisting(把轉帳等動作限制在特定地址,最常見於各法域審核後只提供給「合格投資人」)、Blacklisting(禁止特定地址轉帳)。書提醒:這些功能目前沒有被廣泛接受的介面標準,而是否擴充標準本身,就是「創新/風險」與「互通性/安全」之間的取捨。
“Due to high gas costs and the currently low block gas limit, smart contracts are not well suited to storing or processing large amounts of data.”
(譯文:由於 gas 成本高昂、且目前區塊 gas 上限偏低,智能合約並不適合儲存或處理大量資料。)
使用者記不住 0x 開頭的地址。Ch.12 “The Ethereum Name Service (ENS)“(p.518)舉的例子:以太坊基金會捐款地址是 0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359,在支援 ENS 的錢包裡就只是 ethereum.eth。
前端還掛在自己的 web server 上,等於整個「去中心化應用」有一顆單點故障的心臟。
要決定 DApp 該不該留管理員鑰匙(“DApp governance”,p.508–509)。
先記住本章對 DApp 的定義與它主張的三個優點(“What Is a DApp?”,p.497–498):
“A DApp is an application that is mostly or entirely decentralized.”
(譯文:DApp 是一個大部分或完全去中心化的應用程式。)
“Decentralized P2P storage is ideal for storing and distributing large static assets such as images, videos, and the resources of the application’s frontend web interface (HTML, CSS, JavaScript, etc.).”
(譯文:去中心化的 P2P 儲存最適合用來儲存與散布大型靜態資產,例如圖片、影片,以及應用程式前端網頁介面的各項資源(HTML、CSS、JavaScript 等)。)
2. 選一個內容定址(content-addressable)的 P2P 儲存。 書中給兩個選項:
IPFS(“IPFS”,p.501):
“‘Content addressable’ means that each piece of content (file) is hashed and the hash is used to identify that file.”
(譯文:「內容定址」的意思是:每一份內容(檔案)都會被雜湊,而這個雜湊值就用來識別該檔案。)
IPFS 的目標是取代 HTTP 成為傳遞網頁應用的協定——網頁應用不再放在單一伺服器上,而是存在 IPFS 上、可從任一 IPFS 節點取回。
Swarm(“Swarm”,p.501–502):
“Swarm is another content-addressable P2P storage system, similar to IPFS. Swarm was created by the Ethereum Foundation, as part of the Go-Ethereum suite of tools.”
(譯文:Swarm 是另一套內容定址的 P2P 儲存系統,和 IPFS 類似。Swarm 由以太坊基金會打造,屬於 Go-Ethereum 工具組的一部分。)
Swarm 自己的首頁就存在 Swarm 上(https://swarm-gateways.net/bzz:/theswarm.eth/),本身就是示範。
3. 實作步驟(書中 “Preparing Swarm” 起,p.514–517):
安裝 Swarm(Go-Ethereum 工具組的一部分),swarm version 確認可用(書中示範版本為 0.3)。
啟動 Swarm 時要告訴它怎麼連上一個 Geth 實例以存取 JSON-RPC API;啟動記錄裡會看到 connecting to ENS API url=http://127.0.0.1:8545。
“The root node is defined as 0x0000000000000000000000000000000000000000000000000000000000000000 (32 zero bytes).”
(譯文:root node 被定義為 0x000…000(32 個零位元組)。)
“In a traditional Vickrey auction, every bidder submits a sealed bid, and all of them are revealed simultaneously, at which point the highest bidder wins the auction but only pays the second-highest bid.”
(譯文:在傳統的 Vickrey 拍賣中,每位競標者提交一份密封標,所有標同時揭曉,此時出價最高者贏得拍賣,但只需支付第二高的出價。)
“Because you can’t hide secrets on a blockchain, bidders must execute at least two transactions (a commit–reveal process), in order to hide the original value and name they bid on.”
(譯文:因為在區塊鏈上藏不住秘密,出價者必須執行至少兩筆交易(一個 commit–reveal 流程),才能隱藏他們原本的出價金額與所競標的名稱。)
“Either choice carries risk, but in the long run, true DApps cannot have specialized access for privileged accounts — that’s not decentralized.”
(譯文:兩種選擇都有風險,但長遠來看,真正的 DApp 不能為特權帳號保留特殊存取權——那不叫去中心化。)
🧪 我實際套用的紀錄
(待填)
⚠️ 注意 / 什麼時候不適用
本卡完全依據《Mastering Ethereum》(O’Reilly, 2018) Ch.12 原文。 ENS 的 .eth 註冊機制在本書之後已經改版,書中描述的 Vickrey 密封拍賣+deed 鎖定資金是 2017–2018 年當時的做法,實際要註冊名字前必須查現行規格,不要照書操作。書中自己也標明「at the time of writing」。
In the context of blockchains, an oracle is a system that can answer questions that are external to Ethereum. Ideally oracles are systems that are trustless, meaning that they do not need to be trusted because they operate on decentralized principles.
The term “oracle” comes from Greek mythology, where it referred to a person in communication with the gods who could see visions of the future.
(譯文)「oracle」一詞源自希臘神話,指的是能與神溝通、能看見未來景象的人。
⚙️ 怎麼用
1. 先搞懂為什麼非要預言機不可(這是整章的靈魂)
Ch.11 “Why Oracles Are Needed”(p.474)的論證:共識要求 EVM 完全確定性,而這一個要求直接推導出兩個後果——
In order to maintain consensus, EVM execution must be totally deterministic and based only on the shared context of the Ethereum state and signed transactions. This has two particularly important consequences: the first is that there can be no intrinsic source of randomness for the EVM and smart contracts to work with; the second is that extrinsic data can only be introduced as the data payload of a transaction.
(譯文)為了維持共識,EVM 的執行必須是完全確定性的,且只能基於「以太坊狀態」與「已簽名交易」這個共享脈絡。這帶來兩個特別重要的後果:第一,EVM 與智能合約沒有任何內生的亂數來源可用;第二,外部資料只能以交易的 data payload 形式被引入。
為什麼亂數不行:同一份合約在節點 A 執行存下 3、節點 B 執行存下 7,同樣的程式碼、同樣的脈絡卻得到不同狀態,網路永遠無法對結果達成去中心化共識;而且連鎖效應(包括 ether 轉帳)會指數級放大。
為什麼偽隨機也不夠(p.474):雜湊函數是確定性的、可以放進 EVM,但對很多應用不夠。
a miner can gain an advantage by playing the game and only including their transactions in blocks for which they will win.
(譯文)礦工可以透過自己下場玩、且只把「自己會贏」的那些交易打包進區塊,來取得優勢。
為什麼「塞進交易裡」不算解決(p.475):所有節點都能對已簽名交易的內容取得共識,所以亂數、價格、天氣預報都可以當作交易的 data 部分送進網路,但——
However, such data simply cannot be trusted, because it comes from unverifiable sources. As such, we have just deferred the problem.
Ch.11 “Oracle Use Cases and Examples”(p.476–478)列出的完整清單:
實體來源的亂數/熵(量子/熱力學過程):例如樂透合約公平選出贏家
與自然災害連動的參數化觸發器:例如地震債券用芮氏規模觸發巨災債券合約
匯率資料:例如加密貨幣對法幣的精確錨定
資本市場資料:例如為代幣化資產/證券的組合定價
基準參考資料:例如把利率帶進智慧金融衍生品
靜態/半靜態資料:證券識別碼、國碼、幣別代碼等
時間與區間資料:需要精確時間量測的事件觸發
天氣資料:例如依天氣預報計算保費
政治事件:預測市場的結算
體育賽事:預測市場結算與夢幻運動合約
地理位置資料:例如供應鏈追蹤
損害驗證:保險合約
其他區塊鏈上發生的事件:互通性功能
以太幣市價:例如法幣計價的 gas price 預言機
航班統計:例如社團/俱樂部的機票 pooling
書中也提醒另一類:學歷證明、政府 ID 這種來自特定私有資料源的資料,其來源(大學、政府部門)是被完全信任的,真相是主觀的(只能訴諸來源的權威),因此本質上無法 trustless 地提供。這類資料通常以 attestation(護照、成就紀錄)的形式呈現。
3. 知道所有預言機都在做同樣三件事
Ch.11 “Oracle Design Patterns”(p.479):
Collect data from an off-chain source. / Transfer the data on-chain with a signed message. / Make the data available by putting it in a smart contract’s storage.
Generally, when considering the use of an oracle be very careful about the trust model. If you assume the oracle can be trusted, you may be undermining the security of your smart contract by exposing it to potentially false inputs.
書中同時說:「if they are trusted sources and can be compromised, they can result in compromised execution of the smart contracts they feed.」(譯文:如果它們是被信任的來源、而且可能被攻破,就會導致它們所餵養的智能合約執行也被攻破。)
2. 合約管的錢越多,攻擊預言機的誘因越大(p.476 的 smart will 例子):
If the inheritance amount controlled by such a contract is high enough, the incentive to hack the oracle and trigger distribution of assets before the owner dies is very high.
「From a computer science perspective, Ethereum is a deterministic but practically unbounded state machine, consisting of a globally accessible singleton state and a virtual machine that applies changes to that state.」(Ch.1 開篇,PDF p.43)
—— 譯文:從計算機科學的角度看,以太坊是一台確定性但實際上無界的狀態機,由一個全球可存取的單例狀態、以及一台對該狀態施加變更的虛擬機所組成。
「While providing high availability, auditability, transparency, and neutrality, it also reduces or eliminates censorship and reduces certain counterparty risks.」(Ch.1 開篇,PDF p.43)
—— 譯文:在提供高可用性、可稽核性、透明性與中立性的同時,它也減少或消除審查,並降低某些交易對手風險。(注意書用的是「減少或消除」而非「不可能被關閉」——這種謹慎值得學。)
「In the context of Ethereum, the term is actually a bit of a misnomer, given that Ethereum smart contracts are neither smart nor legal contracts, but the term has stuck.」(Ch.7 “What Is a Smart Contract?”,PDF p.255)
—— 譯文:在以太坊的脈絡下,「智能合約」這個詞其實有點名不副實——以太坊的智能合約既不智能,也不是法律上的合約,但這個叫法就這麼定下來了。
「As with other programs, a smart contract will execute exactly what is written, which is not always what the programmer intended. … Any vulnerability can be exploited, and losses are almost always impossible to recover.」(Ch.9 章首,PDF p.328)
—— 譯文:跟其他程式一樣,智能合約會完全照著寫的執行,而那不見得是寫的人想要的。……任何漏洞都會被利用,而損失幾乎總是無法追回。