想要了解以太坊嗎?
這份白皮書發布於 2014 年,當時以太坊尚未推出。經過 10 多年的發展、重大升級和生態系統的成長,最初的白皮書已無法反映以太坊現今的樣貌。
雖然已經過去幾年,我們仍保留下方的原始論文,因為它繼續作為有用的參考資料,並準確地呈現了以太坊及其願景。
下一代智能合約與去中心化應用程式平台
中本聰在 2009 年開發的比特幣常被譽為貨幣領域的革命性發展,它是第一個同時沒有背書或「內在價值 (在新分頁開啟)」,也沒有中心化發行者或控制者的數位資產實例。然而,比特幣實驗中另一個可以說更重要的部分,是作為分散式共識工具的底層區塊鏈技術,而人們的注意力正迅速轉移到比特幣的這個層面上。常被提及的區塊鏈技術替代應用包括:使用區塊鏈上的數位資產來代表自訂貨幣和金融工具(「彩色幣 (在新分頁開啟)」)、底層實體裝置的所有權(「智能財產 (在新分頁開啟)」)、網域名稱等非同質化資產(「Namecoin (在新分頁開啟)」),以及更複雜的應用,例如由實作任意規則的程式碼直接控制數位資產(「智能合約 (在新分頁開啟)」),甚至是基於區塊鏈的「去中心化自治組織 (在新分頁開啟)」(DAO)。以太坊打算提供的是一個內建成熟且圖靈完備程式語言的區塊鏈,可用於建立「合約」來編碼任意的狀態轉換函數,讓使用者只需用幾行程式碼寫出邏輯,就能建立上述的任何系統,以及許多我們尚未想像到的其他系統。
比特幣與現有概念簡介
歷史
去中心化數位貨幣的概念,以及財產登記等替代應用程式,已經存在了幾十年。1980 年代和 1990 年代的匿名電子現金協定,主要依賴於被稱為喬姆盲簽 (Chaumian blinding) 的密碼學原語,提供了一種具有高度隱私的貨幣,但這些協定大多未能獲得關注,因為它們依賴於中心化的中介機構。1998 年,戴偉的 b-money (在新分頁開啟) 成為第一個提出透過解決計算難題以及去中心化共識來創造貨幣概念的提案,但該提案對於如何實際實作去中心化共識的細節卻很匱乏。2005 年,Hal Finney 引入了「可重複使用的工作量證明 (在新分頁開啟)」概念,該系統結合了 b-money 的想法與 Adam Back 計算難度高的 Hashcash 難題,創造了一種加密貨幣的概念,但由於依賴可信運算作為後端,再次未能達到理想狀態。2009 年,中本聰 (Satoshi Nakamoto) 首次在實務中實作了去中心化貨幣,將透過公鑰密碼學管理所有權的既有原語,與用於追蹤誰擁有硬幣的共識演算法(稱為「工作量證明 (PoW)」)結合在一起。
工作量證明背後的機制是該領域的一大突破,因為它同時解決了兩個問題。首先,它提供了一個簡單且適度有效的共識演算法,允許網路中的節點共同對比特幣帳本狀態的一組規範更新達成一致。其次,它提供了一種允許自由進入共識過程的機制,解決了決定誰能影響共識的政治問題,同時防止了女巫攻擊 (sybil attacks)。它的做法是用經濟障礙取代參與的正式障礙(例如要求在特定名單上註冊為唯一實體)——單一節點在共識投票過程中的權重,與該節點帶來的運算能力成正比。從那時起,有人提出了一種稱為權益證明 (PoS) 的替代方法,將節點的權重計算為與其持有的貨幣成正比,而不是運算資源;這兩種方法的相對優缺點討論超出了本文的範圍,但應注意的是,這兩種方法都可以用作加密貨幣的骨幹。
作為狀態轉換系統的比特幣
從技術角度來看,比特幣等加密貨幣的帳本可以被視為一個狀態轉換系統,其中有一個由所有現有比特幣所有權狀態組成的「狀態」,以及一個接收狀態和交易並輸出新狀態作為結果的「狀態轉換函數」。例如,在標準銀行系統中,狀態是資產負債表,交易是將 $X 從 A 轉移到 B 的請求,而狀態轉換函數會將 A 帳戶中的價值減少 $X,並將 B 帳戶中的價值增加 $X。如果 A 的帳戶一開始少於 $X,狀態轉換函數會回傳錯誤。因此,可以正式定義為:
APPLY(S,TX) -> S' or ERROR
在上述定義的銀行系統中:
APPLY({ Alice: $50, Bob: $50 },"send $20 from Alice to Bob") = { Alice: $30, Bob: $70 }
但是:
APPLY({ Alice: $50, Bob: $50 },"send $70 from Alice to Bob") = ERROR
比特幣中的「狀態」是所有已鑄造且尚未花費的硬幣(技術上稱為「未花費的交易輸出」或 UTXO)的集合,每個 UTXO 都有一個面額和一個擁有者(由一個 20 位元組的地址定義,該地址本質上是一個密碼學公鑰fn1)。一筆交易包含一個或多個輸入,每個輸入包含對現有 UTXO 的引用以及由與擁有者地址關聯的私鑰產生的密碼學簽章;以及一個或多個輸出,每個輸出包含要新增到狀態中的新 UTXO。
狀態轉換函數 APPLY(S,TX) -> S' 可以大致定義如下:
對於
TX中的每個輸入:- 如果引用的 UTXO 不在
S中,則回傳錯誤。 - 如果提供的簽章與 UTXO 的擁有者不符,則回傳錯誤。
- 如果引用的 UTXO 不在
- 如果所有輸入 UTXO 的面額總和,小於所有輸出 UTXO 的面額總和,則回傳錯誤。
- 回傳移除了所有輸入 UTXO 並新增了所有輸出 UTXO 的
S。
第一步的前半部分防止交易發送者花費不存在的硬幣,第一步的後半部分防止交易發送者花費他人的硬幣,而第二步則強制執行價值守恆。為了將其用於支付,協定如下。假設 Alice 想發送 11.7 BTC 給 Bob。首先,Alice 會尋找一組她擁有的可用 UTXO,總計至少為 11.7 BTC。實際上,Alice 無法剛好湊齊 11.7 BTC;假設她能湊到的最小值是 6+4+2=12。然後她用這三個輸入和兩個輸出建立一筆交易。第一個輸出將是 11.7 BTC,擁有者為 Bob 的地址,第二個輸出將是剩餘的 0.3 BTC「找零」,擁有者為 Alice 自己。
挖礦
如果我們能使用值得信賴的中心化服務,這個系統的實作將微不足道;它可以完全按照描述進行編碼,使用中心化伺服器的硬碟來追蹤狀態。然而,對於比特幣,我們試圖建立一個去中心化的貨幣系統,因此我們需要將狀態轉換系統與共識系統結合,以確保每個人都對交易順序達成一致。比特幣的去中心化共識過程要求網路中的節點不斷嘗試產生稱為「區塊」的交易封包。網路旨在每十分鐘左右產生一個區塊,每個區塊包含一個時間戳記、一個隨機數、對前一個區塊的引用(即雜湊)以及自前一個區塊以來發生的所有交易的清單。隨著時間的推移,這創造了一個持久、不斷增長的「區塊鏈」,它不斷更新以代表比特幣帳本的最新狀態。
在此範式中,檢查區塊是否有效的演算法如下:
- 檢查該區塊引用的前一個區塊是否存在且有效。
- 檢查該區塊的時間戳記是否大於前一個區塊的時間戳記fn2,且小於未來的 2 小時。
- 檢查該區塊上的工作量證明是否有效。
- 設
S[0]為前一個區塊結束時的狀態。 - 假設
TX是該區塊的交易清單,包含n筆交易。對於0...n-1中的所有i,設定S[i+1] = APPLY(S[i],TX[i])。如果任何應用程式回傳錯誤,則退出並回傳 false。 - 回傳 true,並將
S[n]註冊為此區塊結束時的狀態。
本質上,區塊中的每筆交易都必須提供一個有效的狀態轉換,從執行交易前的規範狀態轉換為某個新狀態。請注意,狀態並未以任何方式編碼在區塊中;它純粹是驗證節點要記住的抽象概念,並且只能透過從創世狀態開始,依序套用每個區塊中的每筆交易,才能(安全地)為任何區塊計算出來。此外,請注意礦工將交易包含在區塊中的順序很重要;如果區塊中有兩筆交易 A 和 B,使得 B 花費了 A 建立的 UTXO,那麼如果 A 在 B 之前,該區塊將是有效的,否則無效。
上述清單中存在而其他系統中沒有的一個有效性條件,是對「工作量證明」的要求。確切的條件是,每個區塊的雙重 SHA-256 雜湊(視為 256 位元數字)必須小於動態調整的目標值,在撰寫本文時,該目標值約為 2187。這樣做的目的是使區塊建立在運算上變得「困難」,從而防止女巫攻擊者為了自身利益而重製整個區塊鏈。因為 SHA-256 被設計為完全不可預測的偽隨機函數,建立有效區塊的唯一方法就是反覆試驗,不斷增加隨機數並查看新雜湊是否符合條件。
在目前約 2187 的目標下,網路平均必須嘗試約 269 次才能找到一個有效的區塊;一般來說,網路每 2016 個區塊會重新校準目標,以便網路中的某個節點平均每十分鐘產生一個新區塊。為了補償礦工的這項運算工作,每個區塊的礦工都有權包含一筆憑空給予自己 25 BTC 的交易。此外,如果任何交易的輸入總面額高於輸出總面額,差額也將作為「交易手續費」歸礦工所有。順帶一提,這也是發行 BTC 的唯一機制;創世狀態中根本沒有任何硬幣。
為了更了解挖礦的目的,讓我們來看看在發生惡意攻擊者時會發生什麼事。由於已知比特幣的底層密碼學是安全的,攻擊者將針對比特幣系統中未受密碼學直接保護的一個部分:交易順序。攻擊者的策略很簡單:
- 發送 100 BTC 給商家以換取某些產品(最好是快速交付的數位商品)
- 等待產品交付
- 產生另一筆將相同的 100 BTC 發送給自己的交易
- 試圖說服網路,他發送給自己的交易才是最先發生的。
一旦步驟 (1) 發生,幾分鐘後某個礦工會將該交易包含在一個區塊中,假設是第 270000 號區塊。大約一小時後,該區塊之後的鏈上將新增五個區塊,每個區塊都間接指向該交易,從而「確認」了它。此時,商家將接受該付款為已定案並交付產品;由於我們假設這是一種數位商品,因此交付是即時的。現在,攻擊者建立另一筆將 100 BTC 發送給自己的交易。如果攻擊者只是將其發佈到實際網路中,該交易將不會被處理;礦工將嘗試執行 APPLY(S,TX) 並注意到 TX 消耗了一個不再處於狀態中的 UTXO。因此,攻擊者會建立區塊鏈的「分叉」,從挖出另一個版本的 270000 區塊開始,該區塊指向同一個 269999 區塊作為父區塊,但用新交易取代了舊交易。因為區塊資料不同,這需要重新進行工作量證明。此外,攻擊者新版本的 270000 區塊具有不同的雜湊,因此原始的 270001 到 270005 區塊不會「指向」它;因此,原始鏈和攻擊者的新鏈是完全分開的。規則是,在分叉中,最長的區塊鏈被視為真相,因此合法的礦工將在 270005 鏈上工作,而攻擊者獨自在 270000 鏈上工作。為了讓攻擊者使其區塊鏈成為最長的,他需要擁有比網路其餘部分總和更多的運算能力才能趕上(因此稱為「51% 攻擊」)。
默克爾樹
左圖:只需呈現默克爾樹中的少數節點,即可提供分支有效性的證明。
右圖:任何試圖更改默克爾樹任何部分的行為,最終都會導致鏈上某處出現不一致。
比特幣的一個重要可擴展性特徵是,區塊儲存在多層級的資料結構中。區塊的「雜湊」實際上只是區塊頭的雜湊,這是一段大約 200 位元組的資料,包含時間戳記、隨機數、前一個區塊雜湊,以及一個稱為默克爾樹(儲存區塊中所有交易)的資料結構的根雜湊。默克爾樹是一種二元樹,由一組節點組成,樹的底部有大量包含底層資料的葉節點,一組中間節點(每個節點是其兩個子節點的雜湊),最後是一個單一的根節點(同樣由其兩個子節點的雜湊形成),代表樹的「頂部」。默克爾樹的目的是允許區塊中的資料零碎地傳遞:節點可以從一個來源僅下載區塊頭,從另一個來源下載與其相關的樹的一小部分,並且仍然確信所有資料都是正確的。這樣做的原因是雜湊會向上傳播:如果惡意使用者試圖將假交易替換到默克爾樹的底部,這種更改將導致上方節點的更改,然後導致更上方節點的更改,最終更改樹的根,從而更改區塊的雜湊,導致協定將其註冊為完全不同的區塊(幾乎可以肯定具有無效的工作量證明)。
默克爾樹協定可以說是長期永續性的關鍵。比特幣網路中的「全節點」(儲存並處理每個區塊的全部內容)截至 2014 年 4 月在比特幣網路中佔用約 15 GB 的磁碟空間,並且每月增長超過 1 GB。目前,這對於某些桌上型電腦是可行的,但對手機則不然,而在未來,只有企業和愛好者才能參與。一種稱為「簡化支付驗證 (SPV)」的協定允許存在另一類節點,稱為「輕節點」,它們下載區塊頭,驗證區塊頭上的工作量證明,然後僅下載與其相關的交易關聯的「分支」。這使得輕節點能夠在僅下載整個區塊鏈極小部分的情況下,以強大的安全保證確定任何比特幣交易的狀態及其當前餘額。
替代區塊鏈應用程式
將底層區塊鏈理念應用於其他概念的想法也有著悠久的歷史。2005 年,尼克·薩博 (Nick Szabo) 提出了「具有擁有者權限的安全財產所有權 (在新分頁開啟)」的概念,該文件描述了「複製資料庫技術的新進展」將如何允許基於區塊鏈的系統儲存誰擁有什麼土地的登記冊,建立一個包含宅地法、逆權侵占和喬治亞土地稅等概念的複雜框架。然而,不幸的是,當時沒有有效的複製資料庫系統可用,因此該協定從未在實務中實作。然而,在 2009 年之後,一旦比特幣的去中心化共識被開發出來,許多替代應用程式迅速開始出現。
- Namecoin - 建立於 2010 年,Namecoin (在新分頁開啟) 最好的描述是一個去中心化的名稱註冊資料庫。在 Tor、比特幣和 BitMessage 等去中心化協定中,需要有某種方法來識別帳戶,以便其他人可以與之互動,但在所有現有解決方案中,唯一可用的識別碼是像
1LW79wp5ZBqaHW1jL5TCiBCrhQYtHagUWy這樣的偽隨機雜湊。理想情況下,人們希望能夠擁有一個名為「george」的帳戶。然而,問題在於,如果一個人可以建立一個名為「george」的帳戶,那麼其他人也可以使用相同的過程為自己註冊「george」並冒充他們。唯一的解決方案是先申請制範式,即第一個註冊者成功,第二個失敗——這個問題非常適合比特幣共識協定。Namecoin 是使用這種想法的名稱註冊系統中最古老、最成功的實作。 - 彩色幣 (Colored coins) - 彩色幣 (在新分頁開啟) 的目的是作為一種協定,允許人們在比特幣區塊鏈上建立自己的數位貨幣——或者,在只有一個單位的貨幣這種重要且微不足道的情況下,建立數位代幣。在彩色幣協定中,人們透過公開為特定的比特幣 UTXO 分配一種顏色來「發行」一種新貨幣,並且該協定遞迴地將其他 UTXO 的顏色定義為與建立它們的交易所花費的輸入顏色相同(在混合顏色輸入的情況下適用一些特殊規則)。這允許使用者維護僅包含特定顏色 UTXO 的錢包,並像常規比特幣一樣發送它們,透過回溯區塊鏈來確定他們收到的任何 UTXO 的顏色。
- 元硬幣 (Metacoins) - 元硬幣背後的想法是擁有一個存在於比特幣之上的協定,使用比特幣交易來儲存元硬幣交易,但具有不同的狀態轉換函數
APPLY'。因為元硬幣協定無法防止無效的元硬幣交易出現在比特幣區塊鏈中,所以增加了一條規則:如果APPLY'(S,TX)回傳錯誤,協定預設為APPLY'(S,TX) = S。這提供了一種簡單的機制來建立任意的加密貨幣協定,可能具有無法在比特幣本身內部實作的進階功能,但開發成本非常低,因為挖礦和網路的複雜性已經由比特幣協定處理。元硬幣已被用於實作某些類別的金融合約、名稱註冊和去中心化交易所。
因此,一般來說,建立共識協定有兩種方法:建立獨立的網路,以及在比特幣之上建立協定。前一種方法雖然在 Namecoin 等應用程式的情況下相當成功,但難以實作;每個單獨的實作都需要引導一個獨立的區塊鏈,以及建立和測試所有必要的狀態轉換和網路程式碼。此外,我們預測去中心化共識技術的應用程式集合將遵循冪律分佈,其中絕大多數應用程式將太小而不足以保證擁有自己的區塊鏈,並且我們注意到存在大量需要相互互動的去中心化應用程式,特別是去中心化自治組織 (DAO)。
另一方面,基於比特幣的方法存在一個缺陷,即它沒有繼承比特幣的簡化支付驗證功能。SPV 對比特幣有效,因為它可以使用區塊鏈深度作為有效性的代理;在某個時候,一旦交易的祖先追溯得夠遠,就可以安全地說它們是狀態的合法部分。另一方面,基於區塊鏈的元協定無法強制區塊鏈不包含在其自身協定上下文中無效的交易。因此,一個完全安全的 SPV 元協定實作需要向後掃描一直到比特幣區塊鏈的開頭,以確定某些交易是否有效。目前,基於比特幣的元協定的所有「輕量級」實作都依賴於可信伺服器來提供資料,這可以說是一個非常次優的結果,特別是當加密貨幣的主要目的之一是消除對信任的需求時。
腳本
即使沒有任何擴充功能,比特幣協定實際上確實促進了「智能合約」概念的弱化版本。比特幣中的 UTXO 不僅可以由公鑰擁有,還可以由以簡單的基於堆疊的程式語言表達的更複雜的腳本擁有。在這種範式中,花費該 UTXO 的交易必須提供滿足腳本的資料。事實上,即使是基本的公鑰所有權機制也是透過腳本實作的:腳本將橢圓曲線簽章作為輸入,根據交易和擁有 UTXO 的地址對其進行驗證,如果驗證成功則回傳 1,否則回傳 0。其他更複雜的腳本存在於各種額外的使用案例中。例如,可以建構一個腳本,要求給定的三個私鑰中的兩個簽章才能驗證(「多方簽名」),這種設定對於公司帳戶、安全儲蓄帳戶和某些商家託管情況非常有用。腳本也可以用來支付解決運算問題的賞金,甚至可以建構一個腳本,內容類似於「如果你能提供 SPV 證明,證明你向我發送了這種面額的狗狗幣交易,這個比特幣 UTXO 就是你的」,這本質上允許了去中心化的跨加密貨幣兌換。
然而,在比特幣中實作的腳本語言有幾個重要的限制:
- 缺乏圖靈完備性 - 也就是說,雖然比特幣腳本語言支援很大一部分的運算,但它幾乎不支援所有運算。缺少的主要類別是迴圈。這樣做是為了避免在交易驗證期間出現無限迴圈;理論上,這對腳本程式設計師來說是一個可以克服的障礙,因為任何迴圈都可以透過使用 if 語句多次重複底層程式碼來模擬,但這確實會導致腳本的空間效率非常低。例如,實作替代的橢圓曲線簽章演算法可能需要 256 次重複的乘法回合,所有這些回合都單獨包含在程式碼中。
- 價值盲點 - UTXO 腳本無法對可提款的金額提供細粒度的控制。例如,預言機合約的一個強大使用案例是避險合約,其中 A 和 B 投入價值 1000 美元的 BTC,30 天後,腳本將價值 1000 美元的 BTC 發送給 A,其餘的發送給 B。這將需要一個預言機來確定 1 BTC 的美元價值,但即便如此,與目前可用的完全中心化解決方案相比,它在信任和基礎設施要求方面也是一個巨大的改進。然而,因為 UTXO 是全有或全無的,實現這一點的唯一方法是透過非常低效的破解方法,即擁有許多不同面額的 UTXO(例如,對於高達 30 的每個 k,有一個 2k 的 UTXO),並讓預言機選擇將哪些 UTXO 發送給 A,哪些發送給 B。
- 缺乏狀態 - UTXO 只能是已花費或未花費;沒有機會建立多階段合約或腳本來保持除此之外的任何其他內部狀態。這使得很難制定多階段選擇權合約、去中心化交易所報價或兩階段密碼學承諾協定(對於安全的運算賞金是必要的)。這也意味著 UTXO 只能用於建立簡單的、一次性的合約,而不能建立更複雜的「有狀態」合約(例如去中心化組織),並使得元協定難以實作。二進位狀態結合價值盲點也意味著另一個重要的應用程式——提款限制——是不可能的。
- 區塊鏈盲點 - UTXO 對區塊鏈資料(如隨機數、時間戳記和前一個區塊雜湊)是盲目的。這剝奪了腳本語言潛在的寶貴隨機性來源,從而嚴重限制了在賭博和其他幾個類別中的應用程式。
因此,我們看到了在加密貨幣之上建立進階應用程式的三種方法:建立新的區塊鏈、在比特幣之上使用腳本,以及在比特幣之上建立元協定。建立新的區塊鏈允許在建立功能集方面擁有無限的自由,但代價是開發時間、引導工作和安全性。使用腳本很容易實作和標準化,但其功能非常有限,而元協定雖然簡單,但存在可擴展性方面的缺陷。透過以太坊,我們打算建立一個替代框架,在開發便利性以及更強大的輕客戶端屬性方面提供更大的收益,同時允許應用程式共享經濟環境和區塊鏈安全性。
以太坊
以太坊的意圖是建立一個用於構建去中心化應用程式 (dapp) 的替代協定,提供一組不同的權衡,我們相信這對於一大類去中心化應用程式將非常有用,特別強調快速開發時間、小型和罕用應用程式的安全性,以及不同應用程式之間非常高效互動的能力很重要的情況。以太坊透過建立本質上是終極抽象基礎層來實現這一點:一個內建圖靈完備程式語言的區塊鏈,允許任何人編寫智能合約和去中心化應用程式,在其中他們可以為所有權、交易格式和狀態轉換函數建立自己任意的規則。一個基本版本的 Namecoin 可以用兩行程式碼寫成,而其他協定(如貨幣和聲譽系統)可以在二十行以內建構完成。智能合約,即包含價值且僅在滿足特定條件時才解鎖的密碼學「盒子」,也可以建構在該平台之上,由於增加了圖靈完備性、價值感知、區塊鏈感知和狀態的能力,其功能比比特幣腳本所提供的強大得多。
以太坊帳戶
在以太坊中,狀態由稱為「帳戶」的物件組成,每個帳戶都有一個 20 位元組的地址,而狀態轉換則是帳戶之間價值和資訊的直接轉移。一個以太坊帳戶包含四個欄位:
- 隨機數 (nonce),一個用於確保每筆交易只能被處理一次的計數器
- 帳戶目前的以太幣餘額
- 帳戶的合約程式碼(如果存在)
- 帳戶的儲存空間(預設為空)
「以太幣」是以太坊主要的內部加密燃料,用於支付交易手續費。一般來說,有兩種類型的帳戶:由私鑰控制的外部擁有帳戶,以及由其合約程式碼控制的合約帳戶。外部擁有帳戶沒有程式碼,人們可以透過建立並簽署交易來從外部擁有帳戶發送訊息;在合約帳戶中,每次合約帳戶收到訊息時,其程式碼就會啟動,允許它讀取和寫入內部儲存空間,並依次發送其他訊息或建立合約。
請注意,以太坊中的「合約」不應被視為應該被「履行」或「遵守」的東西;相反,它們更像是生活在以太坊執行環境中的「自治代理」,當被訊息或交易「觸發」時,總是執行一段特定的程式碼,並直接控制自己的以太幣餘額和自己的鍵/值儲存,以追蹤持久性變數。
訊息與交易
在以太坊中,「交易」一詞用於指代儲存要從外部擁有帳戶發送之訊息的已簽署資料包。交易包含:
- 訊息的接收者
- 識別發送者的簽章
- 要從發送者轉帳給接收者的以太幣數量
- 一個可選的資料欄位
- 一個
STARTGAS值,代表允許交易執行採取的最大運算步驟數 (Gas 限制) - 一個
GASPRICE值,代表發送者為每個運算步驟支付的費用
前三個是任何加密貨幣中預期的標準欄位。資料欄位預設沒有功能,但虛擬機有一個操作碼,合約可以使用它來存取資料;作為一個範例使用案例,如果合約作為區塊鏈上的網域註冊服務運作,那麼它可能希望將傳遞給它的資料解釋為包含兩個「欄位」,第一個欄位是要註冊的網域,第二個欄位是要將其註冊到的 IP 地址。合約將從訊息資料中讀取這些值,並將它們適當地放入儲存空間中。
STARTGAS 和 GASPRICE 欄位對於以太坊的反阻斷服務模型至關重要。為了防止程式碼中意外或惡意的無限迴圈或其他運算浪費,每筆交易都必須設定其可以使用的程式碼執行運算步驟數的限制。運算的基本單位是「燃料 (gas)」;通常,一個運算步驟花費 1 單位燃料,但某些操作會花費更多數量的燃料,因為它們的運算成本更高,或者增加了必須作為狀態一部分儲存的資料量。交易資料中的每個位元組還需支付 5 單位燃料的費用。費用系統的意圖是要求攻擊者按比例為他們消耗的每項資源付費,包括運算、頻寬和儲存空間;因此,任何導致網路消耗更多這些資源的交易,都必須具有與增量大致成比例的 Gas 費。
訊息
合約有能力向其他合約發送「訊息」。訊息是從未被序列化且僅存在於以太坊執行環境中的虛擬物件。訊息包含:
- 訊息的發送者(隱含的)
- 訊息的接收者
- 隨訊息一起轉帳的以太幣數量
- 一個可選的資料欄位
- 一個
STARTGAS值
本質上,訊息就像一筆交易,只不過它是由合約而不是外部參與者產生的。當目前正在執行程式碼的合約執行 CALL 操作碼時,就會產生一則訊息,該操作碼會產生並執行一則訊息。就像交易一樣,訊息會導致接收帳戶執行其程式碼。因此,合約可以與其他合約建立關係,其方式與外部參與者完全相同。
請注意,由交易或合約分配的燃料授權額度適用於該交易和所有子執行所消耗的總燃料。例如,如果外部參與者 A 向 B 發送一筆帶有 1000 單位燃料的交易,而 B 在向 C 發送訊息之前消耗了 600 單位燃料,並且 C 的內部執行在返回之前消耗了 300 單位燃料,那麼 B 在燃料耗盡之前還可以再花費 100 單位燃料。
以太坊狀態轉換函數
以太坊狀態轉換函數 APPLY(S,TX) -> S' 可以定義如下:
- 檢查交易格式是否正確(即具有正確數量的值)、簽章是否有效,以及隨機數是否與發送者帳戶中的隨機數相符。如果不是,則返回錯誤。
- 將交易手續費計算為
STARTGAS * GASPRICE,並從簽章中確定發送地址。從發送者的帳戶餘額中減去費用,並增加發送者的隨機數。如果沒有足夠的餘額可供花費,則返回錯誤。 - 初始化
GAS = STARTGAS,並為每個位元組扣除一定數量的燃料,以支付交易中的位元組費用。 - 將交易值從發送者的帳戶轉帳到接收帳戶。如果接收帳戶尚不存在,則建立它。如果接收帳戶是合約,則執行合約的程式碼,直到完成或執行耗盡燃料為止。
- 如果因為發送者沒有足夠的資金導致價值轉移失敗,或者程式碼執行耗盡了燃料,則回滾除支付費用之外的所有狀態變更,並將費用新增至礦工的帳戶。
- 否則,將所有剩餘燃料的費用退還給發送者,並將消耗燃料所支付的費用發送給礦工。
例如,假設合約的程式碼是:
if !self.storage[calldataload(0)]:
self.storage[calldataload(0)] = calldataload(32)
請注意,實際上合約程式碼是用低階的 EVM 程式碼編寫的;為了清晰起見,這個範例是用我們的高階語言之一 Serpent 編寫的,並且可以編譯成 EVM 程式碼。假設合約的儲存空間一開始是空的,並且發送了一筆交易,包含 10 顆以太幣的價值、2000 單位燃料、0.001 顆以太幣的 gasprice,以及 64 位元組的資料,其中位元組 0-31 代表數字 2,位元組 32-63 代表字串 CHARLIEfn3。在這種情況下,狀態轉換函數的過程如下:
- 檢查交易是否有效且格式正確。
- 檢查交易發送者是否至少有 2000 * 0.001 = 2 顆以太幣。如果是,則從發送者的帳戶中減去 2 顆以太幣。
- 初始化 gas = 2000;假設交易長度為 170 位元組,且位元組費用為 5,則減去 850,剩下 1150 單位燃料。
- 從發送者的帳戶中再減去 10 顆以太幣,並將其新增至合約的帳戶中。
- 執行程式碼。在這種情況下,這很簡單:它檢查合約在索引
2處的儲存空間是否被使用,注意到它沒有,因此它將索引2處的儲存空間設定為值CHARLIE。假設這花費了 187 單位燃料,因此剩餘的燃料量為 1150 - 187 = 963 - 將 963 * 0.001 = 0.963 顆以太幣加回發送者的帳戶,並返回結果狀態。
如果交易的接收端沒有合約,那麼總交易手續費將簡單地等於提供的 GASPRICE 乘以交易的位元組長度,並且隨交易發送的資料將無關緊要。
請注意,在回滾方面,訊息的運作方式與交易等效:如果訊息執行耗盡了燃料,那麼該訊息的執行以及由該執行觸發的所有其他執行都會回滾,但父執行不需要回滾。這意味著合約呼叫另一個合約是「安全的」,因為如果 A 用 G 單位燃料呼叫 B,那麼 A 的執行保證最多損失 G 單位燃料。最後,請注意有一個操作碼 CREATE 用於建立合約;其執行機制通常與 CALL 相似,例外之處在於執行的輸出決定了新建立合約的程式碼。
程式碼執行
以太坊合約中的程式碼是用一種低階、基於堆疊的位元組碼語言編寫的,稱為「以太坊虛擬機程式碼」或「EVM 程式碼」。程式碼由一系列位元組組成,其中每個位元組代表一個操作。一般來說,程式碼執行是一個無限迴圈,包括重複執行目前程式計數器(從零開始)處的操作,然後將程式計數器加一,直到到達程式碼末尾,或者偵測到錯誤或 STOP 或 RETURN 指令。這些操作可以存取三種類型的空間來儲存資料:
- 堆疊 (stack),一個後進先出的容器,可以將值推入和彈出
- 記憶體 (memory),一個可無限擴展的位元組陣列
- 合約的長期儲存空間 (storage),一個鍵/值儲存。與運算結束後會重設的堆疊和記憶體不同,儲存空間會長期保留。
程式碼還可以存取傳入訊息的值、發送者和資料,以及區塊頭資料,並且程式碼還可以返回一個位元組陣列的資料作為輸出。
EVM 程式碼的正式執行模型出奇地簡單。當以太坊虛擬機 (EVM) 運行時,其完整的運算狀態可以由元組 (block_state, transaction, message, code, memory, stack, pc, gas) 定義,其中 block_state 是包含所有帳戶並包括餘額和儲存空間的全域狀態。在每一輪執行開始時,透過取 code 的第 pc 個位元組(如果 pc >= len(code) 則為 0)來找到目前的指令,並且每個指令都有其自己關於如何影響該元組的定義。例如,ADD 從堆疊中彈出兩個項目並推入它們的總和,將 gas 減 1 並將 pc 加 1,而 SSTORE 從堆疊中彈出頂部的兩個項目,並將第二個項目插入到合約儲存空間中由第一個項目指定的索引處。儘管有許多方法可以透過即時編譯來最佳化以太坊虛擬機的執行,但以太坊的基本實作可以用幾百行程式碼完成。
區塊鏈與挖礦
以太坊區塊鏈在許多方面與比特幣區塊鏈相似,儘管它確實有一些差異。關於區塊鏈架構,以太坊和比特幣之間的主要區別在於,與比特幣不同,以太坊區塊包含交易列表和最新狀態的副本。除此之外,區塊中還儲存了另外兩個值:區塊號和難度。以太坊中的基本區塊驗證演算法如下:
- 檢查所引用的前一個區塊是否存在且有效。
- 檢查區塊的時間戳記是否大於所引用的前一個區塊的時間戳記,並且小於未來的 15 分鐘。
- 檢查區塊號、難度、交易根、叔塊根和 Gas 限制(各種低階的以太坊特定概念)是否有效。
- 檢查區塊上的工作量證明 (PoW) 是否有效。
- 設
S[0]為前一個區塊末尾的狀態。 - 設
TX為區塊的交易列表,包含n筆交易。對於0...n-1中的所有i,設定S[i+1] = APPLY(S[i],TX[i])。如果任何應用程式返回錯誤,或者如果到目前為止區塊中消耗的總燃料超過了GASLIMIT,則返回錯誤。 - 設
S_FINAL為S[n],但加上支付給礦工的區塊獎勵。 - 檢查狀態
S_FINAL的默克爾樹根是否等於區塊頭中提供的最終狀態根。如果是,則區塊有效;否則,無效。
乍看之下,這種方法似乎非常低效,因為它需要將整個狀態與每個區塊一起儲存,但實際上效率應該與比特幣相當。原因是狀態儲存在樹狀結構中,並且在每個區塊之後,只需要更改樹的一小部分。因此,一般來說,在兩個相鄰的區塊之間,樹的絕大部分應該是相同的,因此資料可以儲存一次,並使用指標(即子樹的雜湊)引用兩次。一種稱為「帕特里夏樹 (Patricia tree)」的特殊樹被用來實現這一點,包括對默克爾樹概念的修改,允許高效地插入和刪除節點,而不僅僅是更改。此外,因為所有的狀態資訊都是最後一個區塊的一部分,所以不需要儲存整個區塊鏈歷史——如果這種策略可以應用於比特幣,經計算可以節省 5-20 倍的空間。
一個常見的問題是,就實體硬體而言,合約程式碼是「在哪裡」執行的。這有一個簡單的答案:執行合約程式碼的過程是狀態轉換函數定義的一部分,而狀態轉換函數是區塊驗證演算法的一部分,因此如果一筆交易被新增到區塊 B 中,由該交易產生的程式碼執行將由現在和未來下載並驗證區塊 B 的所有節點執行。
應用
一般來說,以太坊之上有三種類型的應用。第一類是金融應用,為使用者提供更強大的方式來管理和使用他們的資金簽訂合約。這包括子貨幣、金融衍生品、對沖合約、儲蓄錢包、遺囑,甚至最終包括某些類別的全面僱傭合約。第二類是半金融應用,其中涉及金錢,但所做的事情也有很重的非金錢層面;一個完美的例子是為解決運算問題而設的自動執行懸賞。最後,還有像線上投票和去中心化治理這類完全非金融的應用。
代幣系統
鏈上代幣系統有許多應用,從代表美元或黃金等資產的子貨幣,到公司股票、代表智能財產的個人代幣、安全不可偽造的優惠券,甚至完全與傳統價值無關、用作激勵積分系統的代幣系統。在以太坊中實作代幣系統出奇地容易。需要理解的關鍵點是,所有的貨幣或代幣系統,從根本上來說,就是一個只有一種操作的資料庫:從 A 扣除 X 個單位並給予 B X 個單位,條件是 (i) A 在交易前至少有 X 個單位,以及 (2) 該交易得到 A 的批准。實作代幣系統所需要的,就只是將這個邏輯實作到合約中。
在 Serpent 中實作代幣系統的基本程式碼如下所示:
def send(to, value):
if self.storage[msg.sender] >= value:
self.storage[msg.sender] = self.storage[msg.sender] - value
self.storage[to] = self.storage[to] + value
這本質上是本文件上文所述「銀行系統」狀態轉換函數的字面實作。需要添加幾行額外的程式碼,以提供最初分配貨幣單位的初始步驟以及其他幾個邊緣情況,理想情況下還會添加一個函數,讓其他合約可以查詢某個地址的餘額。但這就是全部了。理論上,作為子貨幣的基於以太坊的代幣系統,可能包含另一個基於比特幣的鏈上元貨幣所缺乏的重要功能:直接用該貨幣支付交易手續費的能力。其實作方式是,合約將維持一個以太幣餘額,用來向發送者退還用於支付手續費的以太幣,並且它會透過收集作為手續費收取的內部貨幣單位,並在持續進行的拍賣中轉售它們,來補充這個餘額。因此,使用者需要用以太幣「啟動」他們的帳戶,但一旦有了以太幣,它就可以重複使用,因為合約每次都會退還它。
金融衍生品與穩定價值貨幣
金融衍生品是「智能合約」最常見的應用,也是在程式碼中最容易實作的應用之一。實作金融合約的主要挑戰在於,它們大多數需要參考外部的價格行情;例如,一個非常理想的應用是能夠對沖以太幣(或其他加密貨幣)相對於美元波動的智能合約,但要做到這一點,需要合約知道 ETH/USD 的價值是多少。最簡單的方法是透過由特定方(例如 NASDAQ)維護的「資料饋送」合約,其設計使該方能夠根據需要更新合約,並提供一個介面,允許其他合約發送訊息給該合約,並獲得提供價格的回應。
有了這個關鍵要素,對沖合約將如下所示:
- 等待 A 方輸入 1000 顆以太幣。
- 等待 B 方輸入 1000 顆以太幣。
- 透過查詢資料饋送合約來計算 1000 顆以太幣的美元價值,並將其記錄在儲存空間中,假設為 $x。
- 30 天後,允許 A 或 B「重新啟動」合約,以便將價值 $x 的以太幣(透過再次查詢資料饋送合約以獲取新價格來計算)發送給 A,其餘的發送給 B。
這樣的合約在加密商務中將具有巨大的潛力。關於加密貨幣,常被提及的主要問題之一是其波動性;儘管許多使用者和商家可能希望獲得處理密碼學資產的安全性和便利性,但他們可能不希望面臨在一天內損失 23% 資金價值的風險。到目前為止,最常被提出的解決方案是發行方支持的資產;其想法是發行方創建一種子貨幣,他們有權發行和撤銷單位,並向任何(在線下)向他們提供一個單位特定標的資產(例如黃金、美元)的人提供一個單位的該貨幣。然後,發行方承諾向任何送回一個單位加密資產的人提供一個單位的標的資產。只要發行方值得信任,這種機制就允許任何非密碼學資產被「提升」為密碼學資產。
然而,在實務上,發行方並不總是值得信任的,而且在某些情況下,銀行基礎設施太弱或太不友善,導致此類服務無法存在。金融衍生品提供了一種替代方案。在這裡,扮演這個角色的不是提供資金來支持資產的單一發行方,而是一個由投機者組成的去中心化的市場,他們押注密碼學參考資產(例如 ETH)的價格會上漲。與發行方不同,投機者無法選擇在交易中違約,因為對沖合約將他們的資金託管起來。請注意,這種方法並非完全去中心化的,因為仍然需要一個受信任的來源來提供價格行情,儘管可以說,在減少基礎設施需求(與作為發行方不同,發布價格饋送不需要許可證,並且很可能被歸類為言論自由)和減少潛在詐欺方面,這仍然是一個巨大的進步。
身分與聲譽系統
最早的替代加密貨幣 Namecoin (在新分頁開啟) 試圖使用類似比特幣的區塊鏈來提供名稱註冊系統,使用者可以在公共資料庫中註冊他們的名稱以及其他資料。被引用最多的主要使用案例是 DNS (在新分頁開啟) 系統,將諸如「bitcoin.org」(或在 Namecoin 的情況下為「bitcoin.bit」)之類的網域名稱對應到 IP 地址。其他使用案例包括電子郵件驗證以及潛在更進階的聲譽系統。以下是在以太坊上提供類似 Namecoin 的名稱註冊系統的基本合約:
def register(name, value):
if !self.storage[name]:
self.storage[name] = value
該合約非常簡單;它只是以太坊網路內部的一個資料庫,可以新增內容,但不能修改或刪除。任何人都可以用某個值註冊一個名稱,然後該註冊將永遠保留。更複雜的名稱註冊合約還將具有一個「函數子句」,允許其他合約查詢它,以及一個讓名稱的「擁有者」(即第一個註冊者)更改資料或轉移所有權的機制。人們甚至可以在其上添加聲譽和信任網(web-of-trust)功能。
去中心化檔案儲存
在過去幾年中,出現了許多受歡迎的線上檔案儲存新創公司,最著名的是 Dropbox,它們試圖讓使用者上傳硬碟的備份,並由服務儲存備份並允許使用者存取,以換取月費。然而,在目前這個階段,檔案儲存市場有時相對缺乏效率;粗略地看一下各種現有的解決方案就會發現,特別是在 20-200 GB 這個既沒有免費額度也沒有企業級折扣的「恐怖谷」級別,主流檔案儲存成本的月費高到讓你一個月支付的費用就超過了整個硬碟的成本。以太坊合約可以允許開發一個去中心化的檔案儲存生態系統,個別使用者可以透過出租自己的硬碟來賺取少量金錢,而未使用的空間可以用來進一步降低檔案儲存的成本。
這種機制的關鍵基礎部分將是我們所稱的「去中心化 Dropbox 合約」。該合約的運作方式如下。首先,將所需的資料分割成多個區塊,為了隱私對每個區塊進行加密,並從中建立一棵默克爾樹。然後,建立一個合約,其規則是:每 N 個區塊,合約會在默克爾樹中挑選一個隨機索引(使用可從合約程式碼存取的上一個區塊雜湊作為隨機性來源),並將 X 顆以太幣給予第一個提供交易的實體,該交易帶有類似簡化支付驗證的證明,證明其擁有樹中該特定索引處的區塊。當使用者想要重新下載他們的檔案時,他們可以使用微支付通道協定(例如,每 32 KB 支付 1 薩博)來復原檔案;最節省手續費的方法是付款人直到最後才發布交易,而是在每 32 KB 之後,用具有相同隨機數但稍微更豐厚獎勵的交易來替換該交易。
該協定的一個重要特徵是,雖然看起來像是信任許多隨機節點不會決定忘記該檔案,但可以透過秘密分享將檔案分割成許多片段,並觀察合約以確保每個片段仍然在某個節點的掌控中,從而將該風險降低到接近零。如果合約仍在支付金錢,這就提供了一個密碼學證明,證明外面有人仍在儲存該檔案。
去中心化自治組織 (DAO)
「去中心化自治組織 (DAO)」的一般概念是一個虛擬實體,它擁有特定的一群成員或股東,他們(也許需要 67% 的多數決)有權花費該實體的資金並修改其程式碼。成員將共同決定組織應如何分配其資金。分配 DAO 資金的方法可以從懸賞、薪水,甚至到更奇特的機制,例如用內部貨幣來獎勵工作。這本質上複製了傳統公司或非營利組織的法律框架,但僅使用密碼學區塊鏈技術來執行。到目前為止,圍繞 DAO 的許多討論都集中在「去中心化自治公司」(DAC)的「資本主義」模型上,該模型具有收取股息的股東和可交易的股份;另一種選擇,或許可以描述為「去中心化自治社群」,將使所有成員在決策中擁有平等的份額,並需要 67% 的現有成員同意才能新增或移除成員。然後,一個人只能擁有一個成員資格的要求將需要由該群體共同執行。
如何編寫 DAO 程式碼的一般大綱如下。最簡單的設計只是一段自我修改的程式碼,如果三分之二的成員同意更改,它就會改變。儘管程式碼在理論上是不可變的,但人們可以輕鬆地繞過這一點,透過將程式碼區塊放在獨立的合約中,並將要呼叫哪些合約的地址儲存在可修改的儲存空間中,從而實現事實上的可變性。在這種 DAO 合約的簡單實作中,將會有三種交易類型,透過交易中提供的資料來區分:
[0,i,K,V]註冊一個索引為i的提案,以將儲存索引K處的地址更改為值V[1,i]登記對提案i投贊成票[2,i]如果已獲得足夠的投票,則將提案i定案
然後,合約將為這些操作中的每一個設定子句。它將維護所有未決儲存變更的記錄,以及投票支持這些變更的人員名單。它還將有一份所有成員的名單。當任何儲存變更獲得三分之二的成員投票支持時,一個定案交易就可以執行該變更。更複雜的骨架還將內建針對發送交易、新增成員和移除成員等功能的投票能力,甚至可能提供 流動式民主(Liquid Democracy) (在新分頁開啟) 風格的投票委託(即,任何人都可以指定某人為他們投票,並且指定是具傳遞性的,因此如果 A 指定 B,而 B 指定 C,那麼 C 將決定 A 的投票)。這種設計將允許 DAO 作為一個去中心化社群有機地成長,讓人們最終能夠將過濾誰是成員的任務委託給專家,儘管與「現行系統」不同的是,隨著個別社群成員改變他們的立場,專家可以隨著時間的推移輕鬆地出現和消失。
另一種模型是去中心化公司,其中任何帳戶都可以擁有零股或多股,並且需要三分之二的股份才能做出決定。一個完整的骨架將涉及資產管理功能、提出買賣股份報價的能力,以及接受報價的能力(最好在合約內部具有訂單媒合機制)。委託也將以流動式民主的風格存在,從而概括了「董事會」的概念。
進一步的應用
1. 儲蓄錢包。假設 Alice 想要確保她的資金安全,但擔心她會遺失私鑰或有人會駭入她的私鑰。她將以太幣放入與銀行 Bob 簽訂的合約中,如下所示:
- 僅 Alice 一人每天最多可以提款 1% 的資金。
- 僅 Bob 一人每天最多可以提款 1% 的資金,但 Alice 有能力使用她的金鑰發起交易來關閉此能力。
- Alice 和 Bob 一起可以提款任何金額。
通常,每天 1% 對 Alice 來說已經足夠了,如果 Alice 想要提款更多,她可以聯絡 Bob 尋求協助。如果 Alice 的金鑰被駭,她會跑去找 Bob 將資金轉移到新合約中。如果她遺失了金鑰,Bob 最終會將資金取出。如果 Bob 被證明是惡意的,那麼她可以關閉他提款的能力。
2. 農作物保險。人們可以輕鬆地制定金融衍生品合約,但使用的是天氣的資料饋送,而不是任何價格指數。如果愛荷華州的一位農民購買了一種根據愛荷華州降水量成反比支付的衍生品,那麼如果發生乾旱,農民將自動收到錢,如果有足夠的雨水,農民會很高興,因為他們的農作物會長得很好。這可以廣泛擴展到自然災害保險。
3. 去中心化資料饋送。對於金融差價合約,實際上可能透過稱為「SchellingCoin (在新分頁開啟)」的協定來去中心化資料饋送。SchellingCoin 的基本運作方式如下:N 個參與方都將給定資料的值(例如 ETH/USD 價格)輸入系統,這些值會被排序,介於第 25 和第 75 百分位數之間的每個人都會獲得一個代幣作為獎勵。每個人都有動機提供其他人會提供的答案,而大量參與者實際上能夠達成共識的唯一價值就是明顯的預設值:真相。這創造了一個去中心化協定,理論上可以提供任何數量的數值,包括 ETH/USD 價格、柏林的溫度,甚至特定困難運算的結果。
4. 智能多方簽名託管。比特幣允許使用多方簽名交易合約,例如,給定的五把金鑰中的三把可以花費資金。以太坊允許更細的粒度;例如,五分之四可以花費所有資金,五分之三每天最多可以花費 10%,五分之二每天最多可以花費 0.5%。此外,以太坊多方簽名是非同步的——兩方可以在不同時間在區塊鏈上註冊他們的簽章,最後一個簽章將自動發送交易。
5. 雲端運算。EVM 技術也可用於建立可驗證的運算環境,允許使用者要求他人執行運算,然後選擇性地要求提供證明,證明在某些隨機選擇的檢查點上的運算是正確完成的。這允許建立一個雲端運算市場,任何使用者都可以使用他們的桌上型電腦、筆記型電腦或專用伺服器參與,並且抽查與保證金一起可用於確保系統是值得信任的(即,節點無法透過作弊獲利)。儘管這樣的系統可能不適合所有任務;例如,需要高度行程間通訊的任務,無法輕易在由大量節點組成的雲端上完成。然而,其他任務則更容易平行化;像 SETI@home、folding@home 和基因演算法等專案可以很容易地在這樣的平台上實作。
6. 點對點賭博。任何數量的點對點賭博協定,例如 Frank Stajano 和 Richard Clayton 的 Cyberdice (在新分頁開啟),都可以在以太坊區塊鏈上實作。最簡單的賭博協定實際上只是針對下一個區塊雜湊的差價合約,並且可以從那裡建立更進階的協定,創造出幾乎零手續費且無法作弊的賭博服務。
7. 預測市場。只要有預言機或 SchellingCoin,預測市場也很容易實作,而且預測市場與 SchellingCoin 一起可能被證明是 未來政治(futarchy) (在新分頁開啟) 作為去中心化組織治理協定的第一個主流應用。
8. 鏈上去中心化市場,以身分和聲譽系統為基礎。
雜項與疑慮
修改後的 GHOST 實作
「貪婪最重觀察子樹」(Greedy Heaviest Observed Subtree, GHOST) 協定是由 Yonatan Sompolinsky 和 Aviv Zohar 在2013 年 12 月 (在新分頁開啟)首次引入的一項創新。GHOST 背後的動機是,具有快速確認時間的區塊鏈目前會因為高過時率 (stale rate) 而導致安全性降低——因為區塊在網路中傳播需要一定的時間,如果礦工 A 挖出一個區塊,然後礦工 B 碰巧在礦工 A 的區塊傳播到 B 之前挖出另一個區塊,礦工 B 的區塊最終將被浪費,並且不會對網路安全性做出貢獻。此外,還存在中心化問題:如果礦工 A 是擁有 30% 算力的礦池,而 B 擁有 10% 算力,A 將有 70% 的時間面臨產生過時區塊的風險(因為另外 30% 的時間 A 產生了上一個區塊,因此會立即獲得挖礦資料),而 B 將有 90% 的時間面臨產生過時區塊的風險。因此,如果區塊間隔夠短,導致過時率很高,A 僅憑其規模就會大幅提高效率。結合這兩種效應,快速產生區塊的區塊鏈很可能導致一個礦池擁有足夠大比例的網路算力,從而實質上控制挖礦過程。
正如 Sompolinsky 和 Zohar 所描述的,GHOST 透過將過時區塊納入計算哪條鏈是「最長」鏈的過程中,解決了網路安全性流失的第一個問題;也就是說,不僅是區塊的父區塊和更早的祖先區塊,該區塊祖先的過時後代(在以太坊術語中稱為「叔塊」(uncles))也會被加入計算哪個區塊擁有最大的總工作量證明 (PoW) 支持。為了解決中心化偏差的第二個問題,我們超越了 Sompolinsky 和 Zohar 描述的協定,也向過時區塊提供區塊獎勵:一個過時區塊會獲得其基礎獎勵的 87.5%,而包含該過時區塊的侄子區塊 (nephew) 則獲得剩餘的 12.5%。然而,交易手續費不會獎勵給叔塊。
以太坊實作了一個簡化版的 GHOST,只向下追溯七層。具體定義如下:
- 區塊必須指定一個父區塊,並且必須指定 0 個或多個叔塊
- 包含在區塊 B 中的叔塊必須具備以下屬性:
- 它必須是 B 的第 k 代祖先的直接子區塊,其中
2 <= k <= 7。 - 它不能是 B 的祖先區塊
- 叔塊必須是有效的區塊頭,但不需要是先前已驗證過甚至有效的區塊
- 叔塊必須不同於先前區塊中包含的所有叔塊,以及同一區塊中包含的所有其他叔塊(非重複包含)
- 它必須是 B 的第 k 代祖先的直接子區塊,其中
- 對於區塊 B 中的每個叔塊 U,B 的礦工會在其 coinbase 獎勵中額外獲得 3.125%,而 U 的礦工會獲得標準 coinbase 獎勵的 93.75%。
使用這種僅允許包含最多 7 代叔塊的受限版 GHOST 有兩個原因。首先,無限制的 GHOST 會在計算給定區塊的哪些叔塊有效時引入太多複雜性。其次,以太坊中使用的帶有補償機制的無限制 GHOST,會消除礦工在主鏈上挖礦而不是在公開攻擊者鏈上挖礦的動機。
手續費
因為發佈到區塊鏈中的每筆交易都會給網路帶來需要下載和驗證它的成本,所以需要某種監管機制(通常涉及交易手續費)來防止濫用。比特幣中使用的預設方法是採用純自願的手續費,依賴礦工充當守門員並設定動態最低限額。這種方法在比特幣社群中非常受歡迎,特別是因為它是「基於市場的」,允許礦工和交易發送者之間的供需來決定價格。然而,這種推理的問題在於,交易處理並不是一個市場;雖然將交易處理直觀地解釋為礦工向發送者提供的服務很有吸引力,但實際上,礦工包含的每筆交易都需要由網路中的每個節點進行處理,因此交易處理的絕大部分成本由第三方承擔,而不是由決定是否包含該交易的礦工承擔。因此,非常容易發生公地悲劇問題。
然而,事實證明,當給定一個特定的不準確簡化假設時,基於市場機制的這種缺陷會神奇地自我抵消。論點如下。假設:
- 一筆交易會導致
k個操作,並向包含它的任何礦工提供kR的獎勵,其中R由發送者設定,且k和R事先對礦工(大致)可見。 - 一個操作對任何節點的處理成本為
C(即所有節點具有相同的效率) - 有
N個挖礦節點,每個節點具有完全相同的處理能力(即佔總數的1/N) - 不存在非挖礦的全節點。
如果預期獎勵大於成本,礦工將願意處理一筆交易。因此,預期獎勵為 kR/N,因為礦工有 1/N 的機會處理下一個區塊,而礦工的處理成本僅為 kC。因此,礦工將包含滿足 kR/N > kC 或 R > NC 的交易。請注意,R 是發送者提供的每個操作的手續費,因此是發送者從交易中獲得的利益下限,而 NC 是整個網路共同處理一個操作的成本。因此,礦工有動機只包含那些總效用利益超過成本的交易。
然而,在現實中,與這些假設有幾個重要的偏差:
- 礦工處理交易的成本確實高於其他驗證節點,因為額外的驗證時間會延遲區塊傳播,從而增加區塊成為過時區塊的機會。
- 確實存在非挖礦的全節點。
- 在實踐中,算力分佈最終可能會變得極度不平等。
- 確實存在投機者、政治敵人和瘋子,他們的效用函數包括對網路造成損害,並且他們可以巧妙地設定合約,使其成本遠低於其他驗證節點支付的成本。
(1) 提供了礦工包含較少交易的傾向,而
(2) 增加了 NC;因此,這兩種效應至少部分地
相互抵消。如何抵消? (在新分頁開啟)
(3) 和 (4) 是主要問題;為了解決這些問題,我們只需制定一個
浮動上限:任何區塊的操作數量都不能超過
長期指數移動平均值的 BLK_LIMIT_FACTOR 倍。
具體來說:
blk.oplimit = floor((blk.parent.oplimit \* (EMAFACTOR - 1) +
floor(parent.opcount \* BLK\_LIMIT\_FACTOR)) / EMA\_FACTOR)
BLK_LIMIT_FACTOR 和 EMA_FACTOR 是常數,目前將設定為 65536 和 1.5,但在進一步分析後可能會更改。
在比特幣中,還有另一個因素會抑制大區塊大小:較大的區塊需要更長的時間來傳播,因此成為過時區塊的機率更高。在以太坊中,消耗大量燃料的區塊也可能需要更長的時間來傳播,這既是因為它們在實體上更大,也是因為它們需要更長的時間來處理交易狀態轉換以進行驗證。這種延遲抑制因素在比特幣中是一個重要的考量,但在以太坊中則不然,因為有 GHOST 協定;因此,依賴受監管的區塊限制提供了更穩定的基準。
運算與圖靈完備性
需要特別注意的是,以太坊虛擬機 (EVM) 是圖靈完備的;這意味著 EVM 程式碼可以編碼任何可以想像到的運算,包括無限迴圈。EVM 程式碼允許以兩種方式進行迴圈。首先,有一個 JUMP 指令允許程式跳回程式碼中先前的位置,以及一個 JUMPI 指令來執行條件跳轉,從而允許像 while x < 27: x = x * 2 這樣的陳述式。其次,合約可以呼叫其他合約,這可能允許透過遞迴進行迴圈。這自然引發了一個問題:惡意使用者是否可以透過強迫礦工和全節點進入無限迴圈來實質上關閉它們?這個問題的出現是因為電腦科學中一個被稱為停機問題 (halting problem) 的難題:在一般情況下,無法判斷給定的程式是否會停止。
正如狀態轉換部分所述,我們的解決方案是要求交易設定其允許執行的最大運算步驟數,如果執行時間超過該限制,運算將被回滾,但仍需支付手續費。訊息的運作方式相同。為了說明我們解決方案背後的動機,請考慮以下範例:
- 攻擊者建立一個執行無限迴圈的合約,然後向礦工發送一筆啟動該迴圈的交易。礦工將處理該交易,執行無限迴圈,並等待其耗盡燃料。即使執行耗盡燃料並在中途停止,該交易仍然有效,並且礦工仍然會針對每個運算步驟向攻擊者收取手續費。
- 攻擊者建立一個非常長的無限迴圈,意圖強迫礦工持續運算很長時間,以至於當運算完成時,已經產生了幾個新區塊,礦工將無法包含該交易來收取手續費。然而,攻擊者將被要求提交一個
STARTGAS值來限制執行可以採取的運算步驟數,因此礦工會提前知道該運算將花費過多的步驟。 - 攻擊者看到一個包含類似
send(A,contract.storage[A]); contract.storage[A] = 0形式程式碼的合約,並發送一筆帶有剛好足夠執行第一步但不足以執行第二步的燃料的交易(即進行提款但不讓餘額減少)。合約作者不需要擔心防範此類攻擊,因為如果執行在中途停止,變更將被回滾。 - 一個金融合約透過取九個專有資料饋送的中位數來運作,以將風險降至最低。攻擊者接管了其中一個資料饋送(該資料饋送被設計為可透過去中心化自治組織 (DAO) 部分中描述的變數地址呼叫機制進行修改),並將其轉換為執行無限迴圈,從而試圖迫使任何從金融合約申領資金的嘗試耗盡燃料。然而,金融合約可以對訊息設定 Gas 限制以防止此問題。
圖靈完備性的替代方案是圖靈不完備性,其中不存在 JUMP 和 JUMPI,並且在任何給定時間,呼叫堆疊中只允許存在每個合約的一個副本。在這個系統中,所描述的手續費系統以及圍繞我們解決方案有效性的不確定性可能就沒有必要了,因為執行合約的成本將受其大小的上限約束。此外,圖靈不完備性甚至不是那麼大的限制;在我們內部構思的所有合約範例中,到目前為止只有一個需要迴圈,甚至那個迴圈也可以透過將一行程式碼重複 26 次來移除。鑑於圖靈完備性的嚴重影響以及有限的好處,為什麼不乾脆使用圖靈不完備的語言呢?然而,在現實中,圖靈不完備性遠非解決該問題的完美方案。要了解原因,請考慮以下合約:
C0: call(C1); call(C1);
C1: call(C2); call(C2);
C2: call(C3); call(C3);
...
C49: call(C50); call(C50);
C50: (run one step of a program and record the change in storage)
現在,向 A 發送一筆交易。因此,在 51 筆交易中,我們就有了一個佔用 250 個運算步驟的合約。礦工可以嘗試提前偵測此類邏輯炸彈,方法是在每個合約旁邊維護一個值,指定它可以採取的最大運算步驟數,並為遞迴呼叫其他合約的合約計算此值,但這將要求礦工禁止建立其他合約的合約(因為上述所有 26 個合約的建立和執行可以輕易地合併到單一合約中)。另一個有問題的點是,訊息的地址欄位是一個變數,因此一般來說,甚至可能無法提前判斷給定合約將呼叫哪些其他合約。因此,總而言之,我們得出了一個令人驚訝的結論:圖靈完備性出乎意料地容易管理,而缺乏圖靈完備性同樣出乎意料地難以管理,除非實施完全相同的控制措施——但在這種情況下,為什麼不直接讓協定具備圖靈完備性呢?
貨幣與發行
以太坊網路包含其內建貨幣——以太幣 (ether),它具有雙重目的:提供主要的流動性層以允許各種類型的數位資產之間進行有效率的兌換,更重要的是,提供一種支付交易手續費的機制。為了方便起見並避免未來的爭論(參見目前比特幣中關於 mBTC/uBTC/satoshi 的爭論),面額將預先標記:
- 1: Wei
- 1012: 薩博
- 1015: 芬尼
- 1018: 以太幣
這應該被視為「元」和「分」或「BTC」和「satoshi」概念的擴展版本。在不久的將來,我們預期「以太幣」將用於一般交易,「芬尼」用於微型交易,而「薩博」和「Wei」用於圍繞手續費和協定實作的技術討論;其餘面額稍後可能會變得有用,目前不應包含在客戶端中。
發行模型將如下所示:
- 以太幣將以每 BTC 兌換 1000-2000 以太幣的價格在貨幣銷售中發行,這是一種旨在為以太坊組織提供資金並支付開發費用的機制,該機制已被 Mastercoin 和 NXT 等其他平台成功使用。較早的買家將受益於較大的折扣。從銷售中獲得的 BTC 將全部用於支付開發人員的薪水和獎金,並投資於以太坊和加密貨幣生態系統中的各種營利性和非營利性專案。
- 總銷售量(60102216 ETH)的 0.099 倍將分配給組織,以補償早期貢獻者並支付創世區塊之前以 ETH 計價的費用。
- 總銷售量的 0.099 倍將作為長期儲備金保留。
- 在那之後,每年將把總銷售量的 0.26 倍永久分配給礦工。
| 群體 | 啟動時 | 1 年後 | 5 年後 |
|---|---|---|---|
| 貨幣單位 | 1.198X | 1.458X | 2.498X |
| 購買者 | 83.5% | 68.6% | 40.0% |
| 預售前花費的儲備金 | 8.26% | 6.79% | 3.96% |
| 售後使用的儲備金 | 8.26% | 6.79% | 3.96% |
| 礦工 | 0% | 17.8% | 52.0% |
長期供應成長率(百分比)
儘管貨幣發行是線性的,但就像比特幣一樣,隨著時間的推移,供應成長率仍然趨近於零。
上述模型中的兩個主要選擇是 (1) 捐贈池的存在與規模,以及 (2) 存在永久成長的線性供應,而不是像比特幣那樣有上限的供應。捐贈池的理由如下。如果捐贈池不存在,並且線性發行減少到 0.217 倍以提供相同的通貨膨脹率,那麼以太幣的總量將減少 16.5%,因此每個單位的價值將增加 19.8%。因此,在平衡狀態下,銷售中將多購買 19.8% 的以太幣,因此每個單位的價值將再次與以前完全相同。該組織隨後也將擁有 1.198 倍的 BTC,這可以被認為分為兩部分:原始的 BTC 和額外的 0.198 倍。因此,這種情況與捐贈_完全等效_,但有一個重要的區別:該組織純粹持有 BTC,因此沒有動機去支持以太幣單位的價值。
永久的線性供應成長模型降低了某些人認為比特幣中財富過度集中的風險,並為生活在現在和未來時代的個人提供了獲取貨幣單位的公平機會,同時保留了獲取和持有以太幣的強烈動機,因為作為百分比的「供應成長率」隨著時間的推移仍然趨近於零。我們還推論,由於代幣總是會隨著時間的推移因粗心、死亡等原因而遺失,並且代幣遺失可以建模為每年總供應量的百分比,因此流通中的總貨幣供應量實際上最終將穩定在一個等於年度發行量除以遺失率的值(例如,在 1% 的遺失率下,一旦供應量達到 26 倍,那麼每年將挖出 0.26 倍並遺失 0.26 倍,從而創造一個平衡)。
請注意,在未來,以太坊很可能會為了安全性而切換到權益證明 (PoS) 模型,將發行需求降低到每年零到 0.05 倍之間。如果以太坊組織失去資金或因任何其他原因消失,我們將開放一份「社會契約」:任何人都有權建立未來的以太坊候選版本,唯一的條件是以太幣的數量最多必須等於 60102216 * (1.198 + 0.26 * n),其中 n 是創世區塊之後的年數。建立者可以自由地進行群眾募資,或以其他方式分配 PoS 驅動的供應擴張與最大允許供應擴張之間的部分或全部差額,以支付開發費用。不符合社會契約的候選升級可以合理地分叉成合規版本。
挖礦中心化
比特幣挖礦演算法的運作方式是讓礦工對稍微修改過的區塊頭版本反覆計算數百萬次 SHA-256,直到最終有一個節點得出一個雜湊值小於目標值(目前約為 2192)的版本。然而,這種挖礦演算法容易受到兩種形式的中心化影響。首先,挖礦生態系統已經被 ASIC(特殊應用積體電路)所主導,這是一種專為比特幣挖礦特定任務而設計的電腦晶片,因此效率高出數千倍。這意味著比特幣挖礦不再是一項高度去中心化和人人平等的追求,而是需要數百萬美元的資金才能有效參與。其次,大多數比特幣礦工實際上並不在本地執行區塊驗證;相反,他們依賴中心化的礦池來提供區塊頭。這個問題可以說更糟:在撰寫本文時,排名前三的礦池間接控制了比特幣網路中大約 50% 的處理能力,儘管如果某個礦池或聯盟試圖發動 51% 攻擊,礦工可以切換到其他礦池,這在一定程度上緩解了這個問題。
以太坊目前的意圖是使用一種挖礦演算法,要求礦工從狀態中擷取隨機資料,計算區塊鏈中最後 N 個區塊中隨機選擇的一些交易,並回傳結果的雜湊值。這有兩個重要的好處。首先,以太坊合約可以包含任何類型的運算,因此以太坊 ASIC 實質上將是用於一般運算的 ASIC——即更好的 CPU。其次,挖礦需要存取整個區塊鏈,迫使礦工儲存整個區塊鏈,並且至少能夠驗證每筆交易。這消除了對中心化礦池的需求;雖然礦池仍然可以發揮平衡獎勵分配隨機性的正當作用,但沒有中央控制的點對點礦池同樣可以很好地發揮這項功能。
這個模型尚未經過測試,在使用合約執行作為挖礦演算法時,在避免某些巧妙的最佳化方面可能會遇到困難。然而,這個演算法一個特別有趣的功能是,它允許任何人「在井裡下毒」,方法是在區塊鏈中引入大量專門設計用來阻礙某些 ASIC 的合約。ASIC 製造商有經濟動機使用這種技巧來互相攻擊。因此,我們正在開發的解決方案最終是一種適應性的經濟人類解決方案,而不純粹是技術解決方案。
擴展性
關於以太坊的一個常見疑慮是擴展性問題。與比特幣一樣,以太坊也存在每筆交易都需要由網路中每個節點處理的缺陷。在比特幣中,目前區塊鏈的大小約為 15 GB,以每小時約 1 MB 的速度成長。如果比特幣網路要處理 Visa 每秒 2000 筆的交易,它將以每三秒 1 MB 的速度成長(每小時 1 GB,每年 8 TB)。以太坊很可能會經歷類似的成長模式,而且由於以太坊區塊鏈上將會有許多應用程式,而不僅僅是像比特幣那樣的單一貨幣,這會使情況變得更糟;但以太坊全節點只需要儲存狀態而不是整個區塊鏈歷史記錄,這又在一定程度上改善了情況。
如此龐大的區塊鏈大小帶來的問題是中心化風險。如果區塊鏈大小增加到(例如)100 TB,那麼可能的情況將是只有極少數的大型企業會執行全節點,而所有一般使用者都使用輕量級 SPV 節點。在這種情況下,就會產生潛在的疑慮:全節點可能會聯合起來,並一致同意以某種有利可圖的方式作弊(例如,更改區塊獎勵、給自己發放 BTC)。輕節點將無法立即偵測到這一點。當然,很可能至少存在一個誠實的全節點,幾個小時後,關於詐欺的資訊會透過 Reddit 等管道流出,但到那時就太遲了:這將取決於一般使用者組織起來將給定的區塊列入黑名單,這是一個與成功發動 51% 攻擊規模相似的龐大且可能無法實行的協調問題。在比特幣的情況下,這目前是一個問題,但存在一個由 Peter Todd 建議 (在新分頁開啟)的區塊鏈修改方案,將會緩解這個問題。
在短期內,以太坊將使用兩種額外的策略來應對這個問題。首先,由於基於區塊鏈的挖礦演算法,至少每個礦工都將被迫成為全節點,從而為全節點的數量設定了下限。然而,其次且更重要的是,我們將在處理每筆交易後,在區塊鏈中包含一個中間狀態樹根。即使區塊驗證是中心化的,只要存在一個誠實的驗證節點,就可以透過驗證協定來規避中心化問題。如果礦工發佈了一個無效區塊,該區塊要麼格式錯誤,要麼狀態 S[n] 不正確。由於已知 S[0] 是正確的,因此必然存在某個第一個不正確的狀態 S[i],而 S[i-1] 是正確的。驗證節點將提供索引 i,以及由處理 APPLY(S[i-1],TX[i]) -> S[i] 所需的 Patricia 樹節點子集組成的「無效性證明」。節點將能夠使用這些節點來執行該部分的運算,並發現產生的 S[i] 與提供的 S[i] 不符。
另一種更複雜的攻擊將涉及惡意礦工發佈不完整的區塊,因此甚至不存在完整的資訊來判斷區塊是否有效。解決這個問題的方法是質詢-回應 (challenge-response) 協定:驗證節點以目標交易索引的形式發出「質詢」,輕節點在收到節點後會將該區塊視為不可信,直到另一個節點(無論是礦工還是另一個驗證者)提供 Patricia 節點的子集作為有效性證明。
結論
以太坊協定最初被構想為一種升級版的加密貨幣,透過高度通用的程式語言提供進階功能,例如區塊鏈上託管、提款限制、金融合約、博弈市場等。以太坊協定不會直接「支援」任何應用程式,但圖靈完備程式語言的存在,意味著理論上可以為任何交易類型或應用程式建立任意合約。然而,以太坊更有趣的地方在於,以太坊協定的發展已遠遠超越了單純的貨幣範疇。圍繞著去中心化檔案儲存、去中心化運算和去中心化預測市場等數十種概念的協定,有潛力大幅提升運算產業的效率,並透過首次加入經濟層,為其他點對點協定提供巨大的推動力。最後,還有大量與金錢完全無關的應用程式。
以太坊協定所實作的任意狀態轉換函數概念,提供了一個具有獨特潛力的平台;以太坊在設計上是開放式的,而非針對資料儲存、博弈或金融領域中特定應用程式所設計的封閉式、單一用途協定。我們相信,在未來的幾年裡,它非常適合做為大量金融與非金融協定的基礎層。
註解與延伸閱讀
註解
- 敏銳的讀者可能會注意到,事實上比特幣地址是橢圓曲線公鑰的雜湊,而不是公鑰本身。然而,在密碼學術語中,將公鑰雜湊本身稱為公鑰是完全合理的。這是因為比特幣的密碼學可以被視為一種自訂的數位簽章演算法,其中公鑰由 ECC 公鑰的雜湊組成,簽章由 ECC 公鑰與 ECC 簽章串接而成,而驗證演算法包含將簽章中的 ECC 公鑰與作為公鑰提供的 ECC 公鑰雜湊進行比對,然後針對 ECC 公鑰驗證 ECC 簽章。
- 技術上來說,是前 11 個區塊的中位數。
- 在內部,2 和 "CHARLIE" 都是數字,後者採用大端序的 256 進位表示法。數字最小可以是 0,最大可以是 2256-1。
延伸閱讀
- 內在價值 (在新分頁開啟)
- 智能財產 (在新分頁開啟)
- 智能合約 (在新分頁開啟)
- B-money (在新分頁開啟)
- 可重複使用的工作量證明 (在新分頁開啟)
- 具備所有者權限的安全財產所有權 (在新分頁開啟)
- 比特幣白皮書 (在新分頁開啟)
- Namecoin (在新分頁開啟)
- Zooko 三角 (在新分頁開啟)
- 彩色幣白皮書 (在新分頁開啟)
- Mastercoin 白皮書 (在新分頁開啟)
- 去中心化自治公司,比特幣雜誌 (在新分頁開啟)
- 簡化支付驗證 (在新分頁開啟)
- 默克爾樹 (在新分頁開啟)
- Patricia 樹 (在新分頁開啟)
- GHOST (在新分頁開啟)
- StorJ 與自治代理,Jeff Garzik (在新分頁開啟)
- Mike Hearn 在圖靈節上探討智能財產 (在新分頁開啟)
- 以太坊 RLP
- 以太坊默克爾 Patricia 樹
- Peter Todd 探討默克爾總和樹 (在新分頁開啟)
有關白皮書的歷史,請參閱此 wiki (在新分頁開啟)。
與許多社群驅動的開源軟體專案一樣,以太坊自最初成立以來已經歷了許多演進。若要了解以太坊的最新發展,以及協定是如何進行變更的,我們推薦閱讀本指南。





