乾貨 | 深入探索以太坊世界狀態,Part-2

2021-02-15 以太坊愛好者

Part-1

以太坊前綴樹的實際示例

以太坊的各個主流客戶端使用兩種不同的資料庫軟體來存儲前綴樹,其中用 Rust 寫成的 Parity 客戶端使用 RocksDB ,而以太坊的 Go 、C++ 以及 Python 客戶端使用 LevelDB 。

以太坊和 RocksDB

Rocksdb 不在本文的討論範圍之內,可能在以後我們會推出相關的文章,但是現在,讓我們一起看看使用 LevelDB 的三種主流以太坊客戶端吧。

以太坊和 LevelDB

LevelDB 是谷歌開源的一個鍵值存儲庫,除開其他方面,它提供了對數據的前向和後向迭代,從字符串類型鍵到字符串類型值的有向圖,自定義比較算法以及自動壓縮等功能。數據會自動地使用 「Snappy」 進行壓縮,那是谷歌的一個開源壓縮/解壓縮庫。

雖然 Snappy 並不致力於高的壓縮比率,但具備極高的壓縮速率。LevelDB 是管理以太坊網絡狀態的重要存儲和檢索手段。因此,LevelDB也成為了最流行的幾種以太坊客戶端(節點)的必要依賴環境,例如 go-ethereum, cpp-ethereum 和 pyethereum 。

雖然前綴樹數據結構的生成能在硬碟上完成(使用像 levelDB 一樣的資料庫軟體),但需要明白在前綴樹中增刪改和在單純的鍵值對資料庫中進行操作是截然不同的。

為了更深入的理解,我們必須使用合適的帕特裡夏樹庫來在 LevelDB 中進行數據存取操作。這個練習要求我們安裝以太坊。

關於安裝以太坊的操作我們已經寫了一篇額外的教程(和本文配套)。另一篇名為 「面向實驗和測試來快速搭建一個以太坊私有網絡」 的文章提供了指引你安裝和配置以太坊私有網絡的手把手教程。

一旦搭建好你的以太坊私有網絡,你就能執行交易並探究以太坊的「狀態」是如何根據交易、合約和挖礦來進行改變的。如果你並沒有準備好來配置一個以太坊私有網絡,也沒關係,下文將提供我們的範例代碼和以太坊私有網絡運行時的截圖。

分析以太坊資料庫

正如我們上文中提到的那樣,以太坊區塊鏈中有眾多的 Merkle Patricia 前綴樹(在每一個區塊中都有引用):

接下來的章節中我們將假設你已經安裝並配置好了你自己的以太坊私有網絡,或者你願意跟著看看我們運行代碼並對以太坊 LevelDB 資料庫進行的討論。

為了找到某一個區塊中特定的默克爾帕特裡夏樹,我們需要獲得它的根哈希作為索引。下圖中的三條指令分別可以使我們得到創世區塊中狀態前綴樹、交易前綴樹和收據前綴樹的根哈希值。

web3.eth.getBlock(0).stateRootweb3.eth.getBlock(0).transactionsRootweb3.eth.getBlock(0).receiptsRoot

注意:如果你想得到最近的一個區塊的根哈希值時(而不是創世區塊),你可以使用如下指令。

web3.eth.getBlock(web3.eth.blockNumber).stateRoot

安裝 npm、node、level 以及 ethereumjs

我們將使用 nodejs、level 以及 ehereumjs 一系列工具來探查 LevelDB 資料庫的變化。下面的指令用於進一步搭建實驗環境。

cd ~sudo apt-get updatesudo apt-get upgradecurl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash - sudo apt-get install -y nodejssudo apt-get install nodejsnpm -vnodejs -vnpm install levelup leveldown rlp merkle-patricia-tree --savegit clone https://github.com/ethereumjs/ethereumjs-vm.gitcd ethereumjs-vmnpm install ethereumjs-account ethereumjs-util --save

在這一步運行如下代碼可以得到以太坊帳戶的公鑰(存儲於你以太坊私有網絡的狀態根之中)。這個代碼連接了以太坊的 LevelDB 資料庫 ,進入到了以太坊世界狀態中(使用區塊鏈中一個區塊的 stateRoot 值),然後接入了以太坊私有網絡中所有帳戶的鍵索引。

//Just importing the requirementsvar Trie = require('merkle-patricia-tree/secure');var levelup = require('levelup');var leveldown = require('leveldown');var RLP = require('rlp');var assert = require('assert');//Connecting to the leveldb databasevar db = levelup(leveldown('/home/timothymccallum/gethDataDir/geth/chaindata'));//Adding the "stateRoot" value from the block so that we can inspect the state root at that block height.var root = '0x8c77785e3e9171715dd34117b047dffe44575c32ede59bde39fbf5dc074f2976';//Creating a trie object of the merkle-patricia-tree libraryvar trie = new Trie(db, root);//Creating a nodejs stream object so that we can access the datavar stream = trie.createReadStream()//Turning on the stream (because the node js stream is set to pause by default)stream.on('data', function (data){  //printing out the keys of the "state trie"  console.log(data.key);});

有趣的是,以太坊的帳戶中只在(與該帳戶有關的)交易完成後才加入到狀態前綴樹中。舉例來說,僅僅使用 「geth account new」 指令在本地生成一個以太坊帳戶並不會改變狀態前綴樹,即使這之後網絡又挖礦驗證了數個區塊也不會。然而一旦一個和該帳戶有關的交易成功(交易執行消耗了 gas *並且*被挖礦驗證)執行了,若且唯若此時這個帳戶會加入到狀態前綴樹中。這種做法機智地避免了不懷好意的攻擊者通過不斷製造新帳戶來使狀態前綴樹過度膨脹的後果。

解碼數據

你現在應當注意到了 LevelDB 所返回的是加密後的結果。這是因為以太坊事實上使用了自己獨特的 「默克爾帕特裡夏樹」 來與 LevelDB 進行交互。以太坊維基百科提供了改良 「默克爾帕特裡夏樹」 和 遞歸長度前綴(RLP)編碼 的設計和實現方法。簡單來說,以太坊通過上述的方法來對前綴樹數據結構進行了拓展。比如說改良默克爾帕特裡夏樹通過使用「拓展」節點找到路徑捷徑(順著前綴樹)的方法。

在以太坊中,一個改良默克爾帕特裡夏樹節點只可能是以下的某一種:

一個空字符串(記作 NULL)

一個包含17個元素的數組(記作一個分支)

一個包含兩個元素的數組(記作一個葉子節點)

一個包含兩個元素的數組(記作一個拓展節點)

以太坊前綴樹依循嚴格的規則設計並構建,而理解他們的最好方式則是通過使用計算機代碼。如下的例子中用到了 ethereumjs 。ethereumjs 庫的安裝和使用都十分簡便,是我們快速了解以太坊 LevelDB 資料庫的絕佳工具。

以下代碼(在有了某特定區塊的 stateRoot 以及以太坊帳戶地址的情況下)將返回可直接閱讀的帳戶餘額。

-代碼的輸出結果(地址 0xccc6b46fa5606826ce8c18fece6f519064e6130b 的帳戶餘額)-

//Mozilla Public License 2.0 //As per https://github.com/ethereumjs/ethereumjs-vm/blob/master/LICENSE//Requires the following packages to run as nodejs file https://gist.github.com/tpmccallum/0e58fc4ba9061a2e634b7a877e60143a//Getting the requirementsvar Trie = require('merkle-patricia-tree/secure');var levelup = require('levelup');var leveldown = require('leveldown');var utils = require('ethereumjs-util');var BN = utils.BN;var Account = require('ethereumjs-account');//Connecting to the leveldb databasevar db = levelup(leveldown('/home/timothymccallum/gethDataDir/geth/chaindata'));//Adding the "stateRoot" value from the block so that we can inspect the state root at that block height.var root = '0x9369577baeb7c4e971ebe76f5d5daddba44c2aa42193248245cf686d20a73028';//Creating a trie object of the merkle-patricia-tree libraryvar trie = new Trie(db, root);var address = '0xccc6b46fa5606826ce8c18fece6f519064e6130b';trie.get(address, function (err, raw) {    if (err) return cb(err)    //Using ethereumjs-account to create an instance of an account    var account = new Account(raw)    console.log('Account Address: ' + address);    //Using ethereumjs-util to decode and present the account balance    console.log('Balance: ' + (new BN(account.balance)).toString());})

結論

在上文中我們闡述了以太坊能夠良好地管理其「狀態」。這種聰明的預先設計有許多好處。

移動端親和性

隨著行動裝置和物聯網設備的無處不在,未來的電子商務必將依賴於安全、強健且快速的移動應用。

既然我們承認了移動性上的優勢,我們也必須認識到區塊鏈數據大小不可避免地不斷增加。在每一個行動裝置上存儲完整的區塊鏈網絡顯然是不切實際的。

高速而不降低安全性

以太坊世界狀態的設計和使用改良默克爾帕特裡夏樹的做法在這一領域提供很多優勢。在前綴樹上操作的每一種函數(增刪改)都有一個確定的密碼學哈希,進一步來說,前綴樹根節點獨一無二的密碼學哈希能作為證據,保證前綴樹未被篡改。

舉例而言,任何對前綴樹進行的任何程度的改變(例如在 LevelDB 資料庫種增加某一帳戶的餘額),都將會完全顛覆根哈希。這樣的密碼學特性使得輕客戶端(不存儲整條區塊鏈的設備)成為可能,用戶可以很迅速且可信地查詢區塊類似某某帳戶 「0x … 4857」 是否有足夠餘額在 「5044866」 高度完成購買的問題。

「默克爾證明關於所存儲的數據量大小是對數複雜的。這就意味著即使整個狀態前綴樹有數 Gb 大小,如果一個節點能從可信源得到狀態根,那它就可以在僅僅下載數 Kb 證明數據的情況下百分百驗證樹上的任何信息。」[2]

限制消費

在以太坊白皮書 [3] 中提到了儲蓄帳戶這樣一種有意思的想法。在這種場景下,兩個用戶(也許是丈夫和妻子,或者是商業夥伴)可以每天從餘額中提走 1% 的存款。這個創意僅僅在白皮書中的 「未來應用」 中被提及,但它的意義在於理論上這樣的做法可以作為以太坊的基礎協議層(作為第二層解決方案或是第三方錢包的必要支持方案)。你可能會想到了本文開篇中對 UTXOs 的討論。正如我們所說 UTXOs 在區塊鏈上是黑箱的數據,比特幣區塊鏈實際上不存儲用戶的帳戶餘額。

因此比特幣網絡很難(也許不可能)實現任何一種限制消費的應用。

消費者信心

我們可以看到在這一領域的許多工作都離不開輕客戶端的發展。更確切地說,離不開安全、穩健且快速的,能與區塊鏈科技交互的移動應用。

一個能支撐電子商務的成功區塊鏈必須做到高速、安全和易用。提供更好用、更安全和性能更強的設計聰明的產品往往能增加消費者的信心,並且使普羅大眾得以認可。CyberMiles 團隊正在向著這個目標努力邁進著!

參考文獻

[1] Wood, G., 2014. Ethereum: A secure decentralised generalised transaction ledger. Ethereum Project Yellow Paper, 151.

[2] https://github.com/ethereum/wiki/wiki/Light-client-protocol

[3] https://github.com/ethereum/wiki/wiki/White-Paper#further-applications

原文連結: 

https://medium.com/cybermiles/diving-into-ethereums-world-state-c893102030ed
作者: Timothy McCallum
翻譯&校對: 安仔 Clint & Elisa

你可能還會喜歡:

引介 | 以太坊交易的生命周期
教程 | 以太坊智能合約漫遊指南,Part-1
觀點 | 區塊鏈十年,世界發生巨變

相關焦點

  • 乾貨 | 以太坊工具集合,解決你的入門困難
    如果你之前已經有Web應用程式的開發經驗,還可以參考我之前寫的一篇比較以太坊區塊鏈和Web應用程式架構的文章https://medium.com/@mvmurthy/ethereum-for-web-developers-890be23d1d0c#.8wo4bi611,這可能有助於你更深入地了解以太坊。
  • 通往以太坊2.0之路
    作者 | Lucas Campbell 編譯 | Jhonny以太坊 2.0,即 Serenity,是一個歷時多年的雄心勃勃項目,旨在對當前以太坊1.0鏈進行一些列重大變革,為世界提供更易於使用的可編程貨幣。在接下來的幾年裡,以太坊將經歷多次升級和分叉,以實現以太坊白皮書中所描述的願景。截至目前,以太坊每秒大約可以處理25筆交易。
  • 四項指標帶你讀懂以太坊 2.0
    這四個指標只是分析以太坊 2.0 的部分指標,我們應該將它們當作起點,進而深入分析以太坊 2.0 網絡的活動。不同於比特幣和以太坊 1.0,以太坊 2.0 是以 epoch 而非區塊為單位推進的。每個 epoch 約為 6.4 分鐘。
  • 用DPos共識改造以太坊,網際網路企業美圖的公鏈探索之路
    也有一些鏈很早之前也在通過分片的方式來解決性能,包括以太坊本身也在做分片相關的探索(預計是 2020 年左右會落地)。另外一個解決性能問題的方式是優化共識算法本身,比如一些免 CPU 計算的算法 PoS, DPoS 等等。DApp 方面,目前大多數區塊鏈公司都在尋找一款殺手級的 DApp ,以及很多公鏈也在各個方向上尋找突破點。
  • 以太坊的競爭者——DFINITY
    本文是「以太坊的競爭者」系列的第二篇文章,這個系列會對挑戰以太坊在智能合約平臺領域統治地位的項目進行探究。今天我們來看一看DFINITY。記者:鉛筆盒DFINITY是一個兼容以太坊的智能合約平臺,實施一些處理區塊鏈性能、擴張及管理的創意。雖然DFINITY屬於「以太坊殺手「的範疇,但該項目對以太坊的態度更傾向於合作,而非對抗。
  • 以太坊白皮書與區塊鏈2.0
    這個人果然不一般身家將近3000億比馬雲還高,他就是以太坊的創始人維塔利克·布特林,人稱「V神」。在講以太坊之前,讓我們先對這個以太坊之父好好了解下吧。 來看看他有哪些綽號或頭銜,比如網癮少年、戳學少年、天才少年、《魔獸世界》資深玩家、比特幣雜誌撰稿人、V神、泰爾獎學金獲得者、以太坊創始人、身家超馬雲等等。用網絡比較流行的一個詞來說,V神簡直是一個大大的斜槓青年。
  • 以太坊2.0? 親歷3天的Devcon我看到了這樣一個以太坊 | 見聞錄
    以太坊 2.0:沒有時間表的計劃以太坊的下一個上線版本叫君士坦丁堡,再下一個叫做寧靜,也就是大家常說的以太坊 2.0。區塊鏈軟體必須在任何時候都能處理從第一個創世塊到現在的所有塊,不能有與 1.0 不兼容的 2.0 軟體。但是,以太坊的寧靜版有很大的改變,是對目前以太坊的硬分叉,所以也叫以太坊 2.0。
  • 以太坊都這麼堵了,Eth 2.0 在幹嘛呢?
    預計將初步啟動 64 個分片,且系統的總可用數據約在每秒 1 到 4 MB 之間。註:Eth 2.0 的推出分為 4 個階段:階段 0、階段 1、階段 1.5 和階段 2。階段 0 的目標是與遍布全球的數千個節點以及數十萬個共識實體(驗證器)達成共識。保證區塊鏈有能力處理大量驗證程序是這個階段的難點。
  • 以太坊DeFi怎麼玩?以太坊DeFi挖礦攻略教程
    在以太坊的區塊鏈上,有很多成功的DAPP,像MakerDAO/DAI、Compound等,這些項目都是一些DeFi項目。有很多投資者還不知道以太坊DeFi怎麼玩?下面就讓濤叔為大家帶來以太坊DeFi挖礦攻略教程。
  • 以太坊2.0將啟動牛市?
    存款合約如同以太坊2.0世界最先對外開放的大門,質押者通過存入ETH參與創世,某種程度也可算作長線投資。畢竟,這個大門現階段只許進、不準出,存入的Token將成為「信標鏈」上的一部分。信標鏈是以太坊2.0的核心,可以理解為一個「PoS系統」,它更像是一名「主管」,主要負責驗證來自分片鏈的數據。
  • 以太坊又一次大擁堵何去何從?深度對話美圖以太坊DPoS算法實現團隊
    Patricia Trie 和 Merkle Trie 之前在很多非區塊鏈場景都使用到了(比如 kernel 的新 ip 路由查找算法使用的就是 patricia trie )。 存儲餘額的樹是所有區塊共享的, 如下圖:
  • Echo | 以太坊的願景
    Bitcoin 2.0以太坊是在一次比特幣大會上公開的 [6]。因此早期的媒體報導都側重於將以太坊與比特幣這一密碼學貨幣的前輩作比較(參見 2014 年 Al Jazeera 寫的《比特幣最有雄心的繼承者》 [7];Bloomberg 寫的《比特幣 2.0》)。創立以太坊的最初動機來源於比特幣的腳本語言限制。
  • V神演講乾貨全送上!關於以太坊2.0,你想知道的都在這裡!
    以太坊創始人、以太坊核心研究員及數位行業頂尖創始人對 DeFi、智能合約、行業應用等方面進行了深入解析,為開發者們帶來了一次別開生面的技術論道。 大會中,以太坊創始人 V 神針對以太坊2.0 現狀及上線問題進行了回應,並基於以太坊1.0發展至今的歷程,梳理了以太坊生態系統在過去的五年中所取得的進步及優化。
  • 引介 | 以太坊交易的生命周期
    以太坊交易的生命周期了解以太坊交易是如何生成並在網絡中廣播的交易是以太坊區塊鏈(或任何類似的區塊鏈)的核心。在與以太坊區塊鏈進行交互之時,你是在執行交易並更新其狀態。你有沒有想過要了解當你在以太坊執行交易之時到底發生了什麼?讓我們通過一則交易例子來解答這一問題。本文包括如下內容。
  • GoNetwork:手機端上的以太坊
    在移動平臺上用於以太坊的高度可擴展,低成本,低延遲的p2p網絡。 有許多特殊的社區(等離子,雷電)開發工具來克服桌面平臺區塊鏈的可擴展性限制。 GoNetworks的貢獻解決了與移動平臺上的可擴展性有關的問題,即GoNetwork埠狀態通道轉移到移動平臺。
  • 2個關鍵點讀懂從以太坊1.0到2.0的大遷徙
    自Vitalik在2019年12月提出一個早期以太坊1.0和以太坊2.0合併替代方案之後,研究人員一直在進行積極討論。以太坊1.0到以太坊2.0鏈遷移時候,有兩個重要的因素需要考慮。首先,現有ETH代幣遷移,其次;鏈狀態遷移。
  • 以太坊2.0時代的大幕升起
    如果不出意外,以太坊向2.0時代進發的步伐將於北京時間2020年12月1日20:00:23正式開始。過去數月,DeFi的興起為以太坊生態提供了足夠堅實的應用價值支撐,但也讓以太坊的「天然缺陷」再次顯現:網絡過於擁堵、交易Gas費太高,很多普通用戶都在感嘆已經無法參與其中。可拓展性和交易效率等問題一直是當前的以太坊網絡被人詬病的地方。
  • 以太坊(ETH)與以太經典(ETC)對比
    以太坊和以太經典之間是一場道德和意識形態的鬥爭。在我們現在看到的兩個不同的以太坊之前,只有一個以太坊。一次事件,5000萬美元被一名不知名的黑客或多個黑客竊取,這導致加密貨幣世界中兩個截然不同的陣營正在形成。下面是以太坊 - 正如我們現在所知道的那樣 - 以及它與以太經典的比較。
  • 0.166666667小時,教會你深挖以太坊數據層
    以以太坊為例,在本文中,MIT 孵化初創公司 TowardsBlockChain 聯合創始人 vasa 詳細闡述了以太坊的數據存儲機制、以太坊如何存儲區塊鏈狀態與交易以及以太坊和比特幣在存儲機制上的異同。此外,本文將帶你深入了解 「Patricia 字典樹」數據結構背後的理論基礎,並通過使用 Google 的 levelDB 資料庫演示以太坊字典樹的具體實現。
  • Foresight Ventures: 以太坊智能合約的對手「Arweave 與比特幣」
    實際上, 比特幣早已支持"智能合約", 雖然並非像以太坊的智能合約那樣完整, 但是通過各個功能模塊的組合, 一樣能做出一個比較完備的應用. 早在比特幣誕生的最初幾年, 就已經有開發者去用比特幣簡陋的腳本語言來探索去中心化應用的可能性.