以太坊的主要數據對象以前,我想先向各位簡要介紹一下默爾克樹究竟是什麼,以使得它得以發揮做用的屬性特徵數據庫
假設由定製的默克爾-帕特里夏樹維護世界狀態和交易。編程
在默克爾樹中,由葉子節點保存區塊數據的哈希,而由非葉子節點保存其子節點的哈希。數組
-默克爾樹示意圖(包括節點以及他們之間的關係)網絡
默克爾樹所指向數據的任何改動都會引發節點哈希的變化。因爲每個父節點中所保存的哈希值都取決於子節點所包含的數據,因此子節點中數據的變動都會引發父節點哈希的變化。而且這樣的影響是連鎖反應,從葉子節點直達根節點的。所以對葉子節點所指向數據的改動會引發根節點所保存哈希的變化。由上述結構特徵,咱們能夠引伸出兩條重要的屬性:分佈式
在判斷兩棵默克爾樹所指向數據是否徹底相同時,咱們不須要比較每一個葉子節點,而只需比較根節點所保存的哈希。學習
在判斷特定數據是否被樹所指向時,咱們可使用 默克爾證實 技術。此處不對該技術做過多介紹,只需知道這是證實數據存在於默克爾樹中的一種簡單、高效的方法。區塊鏈
第一種屬性的重要之處在於,咱們可以僅利用根節點的哈希值,就標示某一時刻整棵樹所指向的數據。這意味着僅經過保存根節點的哈希值就能標示區塊(無需儲存區塊鏈中全部的數據),且維護數據的不可篡改。spa
至此咱們理清了默克爾樹中根節點哈希的做用,下面來介紹以太坊中的主要對象。設計
世界狀態是地址(帳戶)到帳戶狀態的映射。雖然世界狀態不保存在區塊鏈上,但在黃皮書的描述中,世界狀態也由樹來保存數據(此樹也被稱爲狀態數據庫或者狀態樹)。世界狀態能夠被視做爲隨着交易的執行而持續更新的全局狀態。以太坊就像一個去中心化的計算機,世界狀態則是這臺電腦的硬盤。日誌
以太坊中全部的帳戶信息都體如今世界狀態之中,並由世界狀態樹保存。若是你想知道某一帳戶的餘額,或者某智能合約當前的狀態,就須要經過查詢世界狀態樹來獲取該帳戶的具體狀態信息。下文中我也會簡要介紹這些信息是如何存儲的。
-世界狀態樹與帳戶存儲-
以太坊中有兩種帳戶類型:外部全部帳戶(Externally Owned Accounts 簡稱 EOA)以及合約帳戶。咱們用來互相收發以太幣、部署智能合約的帳戶就是 EOA 帳戶,而部署智能合約時自動生成的帳戶則是合約帳戶。每個智能合約都有其獨一無二的以太坊帳戶。
帳戶狀態反映了一個以太坊帳戶的各項信息。例如,它存儲了當前帳戶以太幣的餘額信息、當前帳戶發送過的交易數量...每個帳戶都有帳戶狀態。
下面就來看看帳戶狀態中都包括什麼:
nonce
今後地址發送出去的交易數量(若是當前爲 EOA 帳戶)或者此帳號產生的合約建立操做(如今先別管合約建立操做是什麼)。
balance
此帳號所擁有的以太幣數量(以 Wei 計量)。
storageRoot
帳戶存儲樹的根節點哈希值(稍後介紹帳戶存儲是什麼)。
codeHash
對於合約帳戶,就是此帳戶存儲 EVM 代碼的哈希值。對於 EOA 帳戶,此處留空。
帳戶狀態中不容忽視的一個細節是,上述對象在內的全部對象均可變(除了 codeHash)。舉例來講,當一個帳戶向其餘帳戶發送以太幣時,除了 nonce 會增長,帳戶的餘額也會相應改變。
而 codeHash 的不可變性使得,若是部署了有漏洞的智能合約,也沒法修復更新此合約。對應的,只能部署一個新合約(而有漏洞的版本會一直存在於區塊鏈上)。這也是爲何使用 Truffle 進行智能合約的開發和部署十分必要,而且用 Solidity 編程時要遵循 最佳實踐 的要求。
帳戶存儲樹是保存與帳戶相關聯數據的結構。該項只有合約帳戶纔有,而在 EOA 中, storageRoot 留空、 codeHash 則是一串空字符串的哈希值。全部智能合約的數據都以 32 字節映射的形式保存在帳戶存儲樹中。此處再也不贅述帳戶狀態樹如何維持合約數據。若是讀者對其內部實現感興趣,強烈建議閱讀這篇文章。帳戶狀態中的 storageRoot 區域負責維持帳戶存儲樹根節點哈希值。
-帳戶狀態與帳戶存儲樹-
交易推進當前狀態到下一狀態的轉變。在以太坊中有三種交易:
EOA 之間傳輸值的交易(例如,改變發送方和接收方餘額大小)。
發送消息來調用合約的交易(例如,經過發送消息調用來觸發 setter 方法,以設置合約中的值)。
用於部署合約的交易(由此建立了合約帳戶)。
(從技術角度來說,前兩種交易是同樣的...它們都是經過消息調用來改變帳戶狀態的交易,只不過一個是 EOA 帳戶,一個是合約帳戶。此處將交易分爲三種是爲了方便讀者的理解。)
交易由如下部分組成:
nonce
此帳戶發出的交易序號數(校對注:能夠粗略理解爲「這是該帳戶的第幾筆交易」)。
gasPrice
執行此交易、進行計算時爲每單位 gas 所支付的費用(以 Wei 計量)。
gasLimit
執行此交易時可使用的最大 gas 數量。
to
若是此交易用於傳送以太幣,此處爲接收以太幣的 EOA 地址。
若是此交易用於向合約發送消息(例如,調用智能合約中的方法),此處爲合約的地址。
若是此交易用於建立合約,此處值爲空。
value
若是此交易用於收發以太幣,此處爲接收帳戶以 Wei 計量的代幣數量。
若是此交易用於發送對合約的消息調用,此處爲向接收此消息智能合約所給付的 Wei 數量。
若是此交易用於建立合約,此處爲合約初始化時帳戶存放的以 Wei 計量的以太幣數量。
v, r, s
在交易的密碼學簽名中用到的值,能夠用於肯定交易的發送方。
data(只用於價值傳輸以及向智能合約發送消息調用)
發送消息調用時附帶的輸入數據(例如,假設你想要執行智能合約中的 setter 方法,數據區就應該包括 setter 方法的標識符,以及你想要設定的參數值)。
init(只用於合約建立)
用於初始化合約的 EVM 代碼。
別想着一會兒就把這些概念消化完... 必須對以太坊的內部機理有更深的認識才真正理解、使用像 data 區、init 區這樣的概念。
相信不出你的意料,區塊中全部的交易也是存儲在默克爾樹中的。而且這棵樹的根節點哈希值由區塊頭保存!下面咱們就來剖析一下以太坊區塊結構。
區塊分爲兩部分,即區塊頭和區塊體。
區塊頭就是以太坊中的區塊鏈部分。它保存了前一個區塊(也可稱爲父區塊)的哈希值,經過區塊頭的鏈接造成了一條由密碼學背書的鏈。
區塊體包含了此區塊中記錄的一系列交易,以及叔塊(ommer)區塊頭列表。若是想要進一步瞭解叔塊,我推薦閱讀這篇文章。
-以太坊區塊的抽象示意圖-
下面就來介紹區塊頭包括哪些部分。
parentHash
前一個區塊的區塊頭哈希值。每一個區塊都包含前序區塊的哈希值,一路可回溯至鏈上的創世塊。這也就是維護數據不會被篡改的結構設計(任何對前序區塊的篡改都會影響後續全部區塊的哈希值)。
ommersHash
叔塊頭以及部分區塊體的哈希值。
beneficiary
由於挖到此區塊而得到收益的以太坊帳戶。
stateRoot
世界狀態樹的根節點哈希值(在全部交易被執行後)。
transactionsRoot
交易樹根節點的哈希值。這棵樹包含了區塊體的全部交易。
receiptsRoot
每當交易執行時,以太坊都會生成對應結果的交易收據。此處就是這個交易收據樹的根節點哈希。
logsBloom
布隆過濾器,用於判斷某區塊的交易是否產生了某日誌(若是對這方面感興趣,能夠查閱 Stack Overflow 的這個答案)。這避免了在區塊中存儲日誌信息(節省了大量空間)。
difficulty
此區塊的難度值。這是當前區塊挖礦難度的度量值(此處不對此概念的細節和計算做介紹)。
number
前序區塊的總數。這標示了區塊鏈的高度(即區塊鏈上有多少區塊)。創世區塊的 number 爲 0 。
gasLimit
每個交易都須要消耗 gas 。gas limit 標示了該區塊所記錄的全部交易可使用的 gas 總量。這是限制區塊內交易數量的一種手段。
gasUsed
區塊中各條交易所實際消耗的 gas 總量。
timestamp
區塊建立時的 Unix 時間戳。謹記因爲以太坊網絡去中心化的特性,咱們不能信任這個值,特別是撰寫智能合約、涉及到時間相關的商業邏輯時不能依靠這個值。
extraData
能輸入任何東西的不定長字節數組。當礦工建立區塊時,能夠在這個區域添加任何東西。
mixHash
用於驗證一個區塊是否被真正記錄到鏈上的哈希值(若是想要真正理解這個概念,建議閱讀這篇文章 Ethash proof-of-work function )。
nonce
和 mixHash 同樣,用於驗證區塊是否被真正記錄到鏈上的值。
哎呀...真是講到我嘴都酸了...建議你彆着急,慢慢吸取!不過我要再次強調,閱讀本文不該以記住每個名詞及其做用爲目標(在谷歌上這些都能搜到)。個人寫做初衷是想用一種簡單的方式(至少比黃皮書簡單)介紹以太坊對象的方方面面,來幫助新手理解那些專業名詞表明什麼。把這篇文章看成「笨方法學以太坊對象」就行了!🙂
讓咱們簡要回顧一下學到了什麼!整體而言,以太坊有四種前綴樹:
世界狀態樹包括了從地址到帳戶狀態之間的映射。 世界狀態樹的根節點哈希值由區塊保存(在 stateRoot 字段),它標示了區塊建立時的當前狀態。整個網絡中只有一個世界狀態樹。
帳戶存儲樹保存了與某一智能合約相關的數據信息。由帳戶狀態保存帳戶存儲樹的根節點哈希值(在 storageRoot 字段)。每一個帳戶都有一個帳戶存儲樹。
交易樹包含了一個區塊中的全部交易信息。由區塊頭(在 transactionsRoot 區域)保存交易樹的根節點哈希值。每一個區塊都有一棵交易樹。
交易收據樹包含了一個區塊中全部交易的收據信息。一樣由區塊頭(在 receiptsRoot 區域)保存交易收據樹的根節點哈希值;每一個區塊都有對應的交易收據樹。
咱們今天討論的對象有:
世界狀態: 以太坊這臺分佈式計算機的硬盤。它是從地址到帳戶狀態的映射。
帳戶狀態: 保存着每一個以太坊帳戶的狀態信息。帳戶狀態一樣保存着帳戶狀態樹的 storageRoot,後者包含了該帳戶的存儲數據。
交易: 標示了系統中的狀態轉移。它能夠是資金的轉移、消息調用或是合約的部署。
區塊: 包括對前序區塊(parentHash)的連接,而且保存了當執行時會在系統中產生新狀態的交易。區塊同時保存了 stateRoot 、transactionRoot 、 receiptsRoot 、 世界狀態樹的根節點哈希、交易樹以及對應的交易收據樹。
我想用一張圖來表示文中說起的各類概念信息。
-區塊、交易、帳戶狀態對象以及以太坊的默克爾樹-
根據個人經驗,直接從黃皮書中學習以太坊並不方便,且須要巨大的耐心。如前所述,本文的主要目標就是用區塊鏈初學者能聽得懂的語言描述以太坊的主要對象。衷心但願這篇文章能指引你的學習之路!