以太坊是如何運作的? (一)
Last updated
Last updated
不管你是否了解它究竟是什麼,也許你已經聽說過以太坊。因為它在新聞中經常出現。假如你對以太坊沒有基本了解,閱讀本文可能有點摸不著頭腦。那以太坊到底是什麼?它本質上是公共數據庫,它保存數字交易的永久記錄。重要的是,這個數據庫並不要求任何中心機構來維持和保護它的安全。相反,它作為一個“去中介信任”的交易系統進行運作,這是一種框架,在其中個人可以進行對等交易,同時無需任何第三方或彼此之間的信任。
還感到困惑嗎?這就是本文可以發揮作用的地方。我的目標是從技術層面來解釋以太坊是如何運作的,這裡不會有復雜的數學或嚇人的公式。即使你不是程序員,我也希望你至少能有所收穫。如果有部分太過於技術化和太過於晦澀,這也沒有關係。你不需要懂得所有細節。我建議只需從大的層面去理解它。
本文中提到的主題都是以太坊黃皮書中的概念剖析。我添加了自己的解釋和圖表,這樣更容易理解。如果你對技術挑戰感興趣,也可直接閱讀黃皮書。
區塊鍊是一種“具有共享狀態的加密安全的交易單例機。”讓我們拆解一下。
“加密安全”是指所創建的由複雜的數學算法來保證它的安全,這個算法很難被破解。想一下各種防火牆。他們幾乎不可能欺騙系統,例如創造虛假交易、刪除交易記錄等。
“交易的單例機”是指有單個規範實例機負責所有在系統中創建的交易。換句話說,這裡有一個所有人都相信的單一全球事實。
“具有共享狀態”是指存儲在這個機器上的狀態是共享的,向每個人公開。
以太坊實現的是這種區塊鏈的範式。
以太坊區塊鏈本質上是基於交易的狀態機。在計算機科學中,狀態機指的是讀取一系列的輸入的東西,基於這些輸入,會轉換到新的狀態。
有了以太坊的狀態機,我們從“創世狀態”開始。這類似於空白平板,沒有任何交易在網絡上發生過。當交易執行,創世狀態轉換為某種最終狀態。在任何時間點,最終狀態代表以太坊的當前狀態。
以太坊的狀態有數百萬的交易。這些交易組成區塊。一個區塊包含一系列的交易,並且每個區塊與其前一個區塊鏈接在一起。
網絡上的任何節點都可以聲明自己是礦工節點,都可以試圖創建和驗證區塊。全世界有很多礦工試圖在同一時間創建和驗證區塊。當向區塊鏈提交區塊時,每個礦工都會提供一個數學“證明”,該證明作為一個保證:如果證明存在,區塊必須有效。
對於要添入主鏈的區塊,礦工必須比其他競爭對手更快地證明。通過讓礦工提供數學證明的方法來驗證每個區塊的過程也就是所謂的“工作量證明”。
驗證新區塊的礦工會被獎勵一定數量的價值,以激勵他們完成此項工作。什麼樣的價值?以太坊區塊鏈使用原生數字代幣“Ether”。每次礦工證明了一個區塊,新的Ether代幣就會產生並給予礦工獎勵。
你可能會想:用什麼來保證大家都在同一條鏈上?我們怎麼能肯定不會存在一部分礦工決定創建自己的鏈?
在上文也提到,我們把區塊鏈定義為一個具有共享狀態的交易單例機。使用此定義,我們可以理解,正確的當前狀態是一個單一的全球事實,每個人都必須接受。如有多種狀態(或多條鏈)會毀掉整個系統,因為它不可能就哪個狀態才是正確狀態方面達成一致。如果鏈有多條,你可能在一條鏈上有10個代幣,另外一條上有20個代幣,還有一條上有40個代幣。在這種情況下,無法確定那條鍊是最“有效”的。
不管什麼時候,只要有多條路徑,就會產生“分叉”。我們通常希望避免分叉,因為它們會破壞系統並強迫人們選擇相信那一條鏈。
為了決定那條路徑是最有效的,並且防止多條鏈產生,以太坊使用稱為“GHOST協議”的機制。 “GHOST”=“Greedy Heaviest Observed Subtree”
簡單來說,GHOST協議說我們必須挑選耗費最多算力的那條路徑。決定那條路徑的一個方法是使用最新區塊的區塊編號(“葉區塊”),它表示當前該路徑的全部區塊總數(不包括創世區塊)。區塊編號越高,路徑就越長,抵達“葉區塊”所需的挖礦工作量就越大。使用這種推理方法,我們能夠就當前狀態的規範版本達成一致。
現在你已經多少了解一些區塊鏈的大概,讓我們更加深入了解以太坊系統的主要組件:
賬戶
狀態
gas和費用
交易
區塊
交易執行
挖礦
PoW
開始前要注意一個事情:本文說的X的“哈希”時,通常是指以太坊使用的KECCAK-256哈希。
以太坊的全球“共享狀態”是由很多小的對象(賬戶)組成,這些賬戶通過消息傳遞框架實現彼此交互。每個賬戶都有一個與之關聯的狀態以及一個20字節的地址。以太坊中的地址是160位比特的標識符,用於標識任何賬戶。
有兩種類型的賬戶:
外部賬戶,由私鑰控制,沒有與之關聯的代碼。
合約賬戶,由合約代碼控制,有與之關聯的代碼。
理解外部賬戶和合約賬戶之間的根本區別是非常重要的。通過創建及使用其私鑰簽名一個交易,外部賬戶能夠給其他外部賬戶或其他合約賬戶發送消息。兩個外部賬戶之間的消息只是簡單的價值傳輸。但從外部賬戶發送到合約賬戶的消息可以激活合約賬戶的代碼,允許它執行各種操作(例如,轉移代幣、寫入內部存儲、發新幣、執行計算、創建新合約等。)
與外部賬戶不同,合約賬戶無法自行啟動新的交易。相反,合約賬戶僅能夠通過響應其他它們收到的交易來觸發自身的交易。比如從外部賬戶或從其他的合約賬戶的交易來觸發。我們會在“交易和消息”章節中了解到更多合約到合約的請求。
因此,任何以太坊區塊鏈上發生的操作始終由外部賬戶所觸發的交易來啟動。
賬戶狀態由四個部分組成,無論賬戶類型是什麼,它們都存在:
Nonce:如果該賬戶是外部賬戶,這個數代表從這個賬戶地址發出來的交易數。如果該賬戶是合約賬戶,則該nonce是該賬戶創建的合約數。
餘額:該地址擁有的Wei數。每個Ether有1e+18Wei。
StorageRoot:Merkle Patricia樹的根節點的哈希值(後續會解釋Merkle tree)。 Merkle tree對該賬戶的存儲內容的哈希進行編碼,默認情況下為空。
CodeHash:odeHash:該賬戶EVM代碼的哈希。對合約賬戶而言,這是被哈希後並存儲為CodeHash的代碼。對於外部賬戶而言,codehash字段是空字符串的哈希。
我們知道以太坊的全球狀態包括賬戶地址和賬戶狀態之間的映射。該映射存儲在Merkle Patricia tree樹的數據結構中。
Merkle樹是一種由一組節點組成的二叉樹,其中:
樹底部的大量葉節點包含底層數據
一組中間節點,其中每個節點都是兩個子節點的哈希
一個根節點,也是由兩個子節點的哈希形成,表示樹的頂部
樹底部的數據是通過拆分數據產生,這些數據我們希望存儲進入塊中,然後把塊拆分進入桶中,之後取每個桶的哈希並重複相同的過程,直到剩餘的哈希總數變為只有一個:根哈希。
Merkle樹要求每個存儲其中的值都有一個鍵。從樹的根節點開始,鍵應該告訴你要遵循哪個子節點,以獲取相應的值,值是存儲在葉節點上的。在以太坊的案例中,狀態樹的鍵/值映射是在地址和它們相關的賬戶之間的,包括了每個賬戶的餘額、nonce、codeHash、StorageRoot(其中StorageRoot本身就是一顆樹)。
(來源:以太坊白皮書)
相同的trie結構也被用於存儲交易和收據。更具體來說,每個區塊都有一個“塊頭”,塊頭存儲三種不同Merkle trie結構的根節點哈希,包括:
狀態trie
交易trie
收據trie
把所有這些信息有效地存入Merkle tries的能力在以太坊中非常有用,因為我們有“輕客戶端”和“輕節點”。請記住,區塊鏈由一堆節點維護。廣義上講,有兩類節點:全節點和輕節點。
完整節點通過下載整個鏈數據來同步區塊鏈,從創世區塊到當前區塊,執行其中包含的所有交易。通常,礦工存儲完整到歸檔節點,因為它們要去挖礦必須執行該操作。無須執行任一操作也可以下載完整節點。無論如何,任何全節點包括所有鏈。
但,除非一個節點有必要執行每個交易或為方便查詢歷史數據,否則,沒有必要存儲整條鏈的數據。這也是輕節點概念的由來。無須下載和存儲完整鏈的數據以及執行所有交易,輕節點僅下載鏈頭,從創世區塊到當前區塊的塊頭,而無須執行任何交易或檢索任何相關的狀態。由於輕節點可以訪問區塊頭,區塊頭包含了三種tries的哈希,它們依然能夠輕易生成和接收可驗證的答案,如關於交易、事件、餘額等。
這樣做能行的原因是Merkle樹中的哈希是向上傳播的——如果一個惡意用戶試圖把虛假交易置入Merkle樹的底部,這樣的改變會導致上面節點的哈希發生變化,然後會繼續改變上面節點的哈希,如此傳遞下去,最終改變了樹根的哈希。
想要驗證數據的任何節點都能使用“Merkle證明”來達成目的。 Merkle證明包含:
要證明的一堆數據和它的哈希
樹的根哈希
“分支”(所有夥伴哈希從塊到根的路徑順延而上)
所有讀取證明的人都能驗證分支的哈希是沿著樹向上一致的,因此,給定的區塊實際上是在樹中的某個位置上。
總之,使用Merkle Patricia樹的好處是該結構的根節點在加密方面依賴於存儲在樹上的數據,因此根節點哈希能夠用於該數據的安全標識。既然區塊頭包含狀態、交易以及收據樹三者的根哈希,因此,任何節點都可以驗證一小部分的以太坊狀態,而無需存儲所有狀態,完整節點可能會非常大。
要讓一個狀態轉換到下一個狀態,交易必須是有效的。一個交易要被認可為有效,必須經過驗證的過程,這個過程稱之為。一群節點(計算機)花費它們的計算資源來創建包含有效交易的區塊,這就是挖礦。