bCamp 是由國內區塊鏈頂級開發者、極客與投資人共同發起,旨在發現和培養國內頂級的區塊鏈技術合夥人,圍繞區塊鏈核心技術打造國內頂級的區塊鏈開發者社羣。

理解 以太坊 Serenity - 第一部分 : 深度抽象

理解 以太坊 Serenity - 第一部分 : 深度抽象

Serenity 會有兩大主要特性:深度抽象和 Casper,基於保證金的權益證明 (PoS) 算法。此外,也在探索平滑的部署可伸縮性 (scalability) 改進的方法,至少是一個腳手架,同時完全解決這裏對並行性的擔憂 – 運行在私有鏈環境下,多核 CPU 專有服務器之上的以太坊節點性能將會有立竿見影的巨大提升,甚至公有鏈的可伸縮性也能看到 2 到 5 倍的提升。在過去的幾個月中,Casper 的研究和對可伸縮性與抽象改進的形式化工作 (eg. EIP101) 都在快速推進。

ethereum 目錄下運行 python test.py 就可以把概念原型跑起來(別忘了先從 https://github.com/ethereum/serpentSerpent 下載和安裝最新的 develop 分支),如果看到這樣的輸出就對了:

    [email protected] 15:01:03 serenity/ethereum: python test.py  
    REVERTING 940534 gas from account 0x0000000000000000000000000000000000000000 to account 0x98c78be58d729dcdc3de9efb3428820990e4e3bf with data 0x  
    Warning (file \"casper.se.py\", line 74, char 0): Warning: function return type inconsistent!  
    Running with 13 maximum nodes  
    Warning (file \"casper.se.py\", line 74, char 0): Warning: function return type inconsistent!  
    Warning (file \"casper.se.py\", line 74, char 0): Warning: function return type inconsistent!  
    Length of validation code: 57  
    Length of account code: 0  
    Joined with index 0  
    Length of validation code: 57  
    Length of account code: 0  
    Joined with index 1  
    Length of validation code: 57

在每 5 秒一個塊,使用 Casper+Serenity 協議的條件下,這個程序模擬了的 13 個節點的運行;這個模擬已經很接近當前客戶端能處理的上限了,不過要注意:(i) 這是 python 寫的,C++和 Go 的實現很可能會有更好的表現,以及 (ii) 所有這些節點都同時運行在一臺電腦上,所以你有理由相信在一個更“正常”的環境中 python 版本的 Casper 可以處理大約 169 個節點(不過,從另一方面來說,我們希望共識的開銷遠低於 100% 的 CPU 佔用,因此這兩點注意並不表示你可以期待 Casper 和上千個節點一起工作!)。如果你的電腦太慢處理不了 13 個節點,試試用 python test.py 10 來模擬 10 個節點(或者 python test.py 7 來模擬 7 個節點,你懂的)。當然,改進 Casper 效率的研究仍在繼續,雖然這改進可能會以減慢終局性 (finality) 的收斂爲代價,這些問題都會逐漸解決。network.py 文件模擬了一個基本的 P2P 網絡接口,接下來的工作會把它替換成運行在真實網絡上的真實計算機。

程序代碼被分割到幾個主要文件中:

  • serenity_blocks.py – 描述 block 類,state 類,以及 block 和 transaction 級別狀態轉移函數的代碼(比以前的版本簡單一倍)。

  • serenity_transactions.py – 描述 transaction 的代碼(比之前簡單一倍)。

  • casper.se.py – Casper 合約的 serpent 實現,激勵正確的下注行爲。

  • bet.py – Casper 的下注邏輯和完整的客戶端實現。

  • ecdsa_accounts.py – 賬戶相關代碼,讓你可以在 Serenity 上模擬當前的賬戶驗證邏輯。

  • test.py – 測試腳本

  • config.py – 參數配置

  • vm.py – 虛擬機(fastvm.py 提供了一個更快的實現)

  • network.py – 網絡模擬

在這篇文章中,我們只討論深度抽象的特性,因此關鍵文件是 serenity_blocks.py, ecdsa_accounts.pyserenity_transactions.py;在下一篇討論 Casper 的文章中,casper.se.pybet.py 將會是焦點。

1

賬戶的抽象

目前以太坊中有兩種類型的賬戶:外部擁有的賬戶,由私鑰控制,和合約賬戶,由代碼控制。對於外部擁有的賬戶,我們指定了一種特別的數字簽名算法 (secp256k1 橢圓曲線簽名) 和一個序號體系 (nonce),要求每一個交易都必須包含一個比前一個交易序號大 1 的數字,目的是防止重放攻擊 (replay attacks)。我們爲提高抽象程度而做的主要改動是:不再有兩種不同類型的賬戶,而是統一爲一種 – 合約賬戶。將會存在一個特殊的“入口”賬戶,0x0000000000000000000000000000000000000000,任何人都可以從這個賬戶發起交易。因此,協議中將不再包含簽名+nonce 的賬戶驗證邏輯,用戶必須用合約來保護他們自己的賬戶。

最簡單有效的此類合約可能要屬橢圓曲線數字簽名驗證合約了,它可以提供和現在完全一樣的功能:只有擁有有效簽名和序號的交易才能通過驗證,而且序號在交易成功後增加 1。這個合約的代碼如下:

    Length of account code: 0  
    Joined with index 1  
    Length of validation code: 57  

    # We assume that data takes the following schema:  
    # bytes 0-31: v (ECDSA sig)  
    # bytes 32-63: r (ECDSA sig)  
    # bytes 64-95: s (ECDSA sig)  
    # bytes 96-127: sequence number (formerly called \"nonce\")  
    # bytes 128-159: gasprice  
    # bytes 172-191: to  
    # bytes 192-223: value  
    # bytes 224+: data  

    # Get the hash for transaction signing  
    ~mstore(0, ~txexecgas())  
    ~calldatacopy(32, 96, ~calldatasize() - 96)  
    ~mstore(0, ~sha3(0, ~calldatasize() - 64))  
    ~calldatacopy(32, 0, 96)  
    # Call ECRECOVER contract to get the sender  
    ~call(5000, 1, 0, 0, 128, 0, 32)  
    # Check sender correctness; exception if not  
    if ~mload(0) != 0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1:  
    ~invalid()  
    # Sequence number operations  
    with minusone = ~sub(0, 1):  
     with curseq = self.storage[minusone]:  
      # Check sequence number correctness, exception if not  
            if ~calldataload(96) != curseq:  
             ~invalid()  
             # Increment sequence number  
             self.storage[minusone] = curseq + 1  
       # Make the sub-call and discard output  
       with x = ~msize():  
       ~call(msg.gas - 50000, ~calldataload(160), ~calldataload(192), 160, ~calldatasize() - 224, x, 1000)  
       # Pay for gas  
       ~mstore(0, ~calldataload(128))  
       ~mstore(32, (~txexecgas() - msg.gas + 50000))     
         ~call(12000, ETHER, 0, 0, 64, 0, 0)  
         ~return(x, ~msize() - x)

這段代碼就是用戶賬戶的合約代碼;如果用戶要從自己的賬戶發送一個交易,他們會先從地址 0 發送一個交易到這個賬戶,交易數據會像上述代碼所示那樣包括 ECDSA 簽名,序號,gas 價格,目標地址,數額和真正的交易數據。合約代碼會檢查對交易 gas 限制和數據的簽名,然後檢查交易序號,如果兩者都沒有問題就把保存的序號加一,發送所需的消息,然後發送另一條消息支付 gas 費用作爲結束(注意,礦工可以靜態分析賬戶的合約代碼,如果交易的賬戶合約最後沒有支付 gas 可以拒絕處理)。

Serenity 的這個改動有一個很重要的後果,系統中的所有交易(只要滿足基本的格式)都是有效的。現階段無效的交易在 Serenity 中將僅僅是沒有作用(上例中的 invalid 是一個尚未使用的操作碼,它會使程序執行立即退出)。這意味着交易被打包進區塊不再是交易會被真正執行的保證,作爲彌補,每一筆交易都會有一條收據記錄(receipt entry),通過返回碼指明它是否成功執行:0 表示由於 gas 限制交易沒有執行,1 表示交易執行了但是出錯,2 表示交易成功執行。收據記錄還可以提供更多的信息,例如交易的返回值(現在有自動日誌記錄)或者自己創建的日誌,

這個改動最主要的好處是用戶可以在賬戶策略這個領域自由的創新了。可能的方向包括:

  • 比特幣風格的多重簽名,賬戶要求交易同時具有多個私鑰的簽名,而不是一次接收一個簽名,然後把中間結果臨時存放在區塊鏈裏。

  • 其他的橢圓曲線 , 包括 ed25519。

  • 更好的集成先進的加密算法,例如環狀簽名 (ring signature), 門限簽名 (threshold signature), 零知識證明等等。

  • 更先進的序號方案 , 支持更高程度的並行化,讓用戶可以同時從一個賬戶發出多個交易,並且更快的把這些交易打包。想想傳統的序號和位掩碼 (bitmask) 如果結合會怎樣。我們也可以通過各種機智的方法在有效性檢查中利用時間戳或是區塊的 hash 值。

  • 基於 UTXO 的代幣管理 , 有些用戶處於隱私的元應,不喜歡以太坊使用賬戶而不是比特幣的“未使用的交易輸出”(unspent transaction output, UTXO) 模型來管理代幣的所有權。現在你可以在以太坊中建立一個事實上基於 UTXO 的系統了,並且 Serenity 不再顯式的特殊對待其中某一個。

  • 支付方案的創新,對於某些 dapp, “由合約支付費用”可能比“由使用者支付”更有用,使用者可能沒有以太幣。現在 dapp 就可以實現這個支付模型了。如果礦工能對它的代碼做靜態分析並確信他們可以得到報酬,礦工就會接受這種交易(本質上,我們實現了 Rookstock 想要通過可選的作者支付 (author-pay) 想做的事情,但是是通過一種更抽象和靈活的方法)。

  • 與“以太坊鬧鐘”之類的應用更好的集成,賬戶的檢驗代碼不一定要檢查簽名,也可以檢查收據的 Merkle proof,或是其他賬戶的狀態,等等。

提出這些場景是爲了說明最主要的論點,通過抽象所有這些另外的機制都可以更加容易的實現,不再需要創造一個“傳遞層”來把信息餵給以太坊默認的簽名體系。當沒有應用是特殊的時候,每個應用都特殊。

一個特別有意思的結果是:在 Serenity 的設計下,以太坊將具有可選的量子安全性。如果你害怕 NSA 祕密擁有一臺量子計算機,想要把自己的賬戶變得更安全,你隨時可以個人切換使用 Lamport 簽名。轉換到 PoS 機制進一步鞏固了安全性,即使世界上只有 NSA 有量子計算機他們也不能利用這一點來實施 51% 攻擊。在以太坊的協議層唯一剩下的密碼學安全假設只有 SHA3 的抵禦碰撞(collision-resistance)的性質了。

這些改變的另一個結果是,交易數據會變得更加簡單。交易將會用四個字段取代現在的九個:目標地址,數據,初始 gas 和初始化代碼。目標地址,數據和初始 gas 和現在一樣,“初始化代碼”是一個可選用於保存目標地址賬戶合約創建代碼的字段。

需要這個機制的原因如下。目前以太坊有一個重要的性質,是允許往一個還不存在的賬戶轉賬。爲了在區塊鏈上創建一個合約接受以太幣,你並不需要事先持有任何以太幣。爲了在 Serenity 中實現這個性質,我們讓賬戶地址能事先從它的初始化代碼中推導出來,通過公式 sha3(creator + initcode) % 2**160。這裏 creator 是創建這個合約的賬戶(默認是地址爲 0 的賬戶),而 initcode 就是合約的初始化代碼(這段代碼的運行結果會成爲賬戶合約的代碼,正如現在的 CREATE 一樣)。因此你可以在本地先生成這段初始化代碼,計算它的地址,然後讓其他人往這個地址轉賬。然後一旦你想要從這個地址發出第一筆交易,你可以在交易裏面包含這段初始化代碼,它就會在真正的交易執行之前,被自動執行並創建賬戶(這段邏輯的實現代碼在這裏)。

2

區塊的抽象

Serenity 中將實現的另一個乾淨的分離是將區塊(僅僅是一堆交易),狀態(例如合約的存儲區,代碼和賬戶餘額)和共識層完全分開。共識激勵在合約內部實現,而如果你希望激勵的話,共識級別的對象(例如 PoW, 賭注)應該被包含在發往“共識激勵管理合約”的交易中。

這應該會讓你更容易用其它的共識算法 – Tendermint, HoneyBadgeBFT, subjective consensus 甚至是普通的 PoW – 替換掉 Serenity 代碼中的 Casper。我們非常歡迎這個方向的研究,並且希望能做到最大的靈活。

3

存儲的抽象

目前,以太坊系統的“狀態”數據實際上相當複雜,包括這些部分:

  • 餘額,代碼,nonce,和賬戶存儲區

  • Gas 上限,難度,塊高度,時間戳

  • 最後 256 個塊的 hash 值

  • 在執行區塊內代碼時,需要保存交易索引,收據樹 (receipt tree, receipt 是 EVM 中的一個概念) 和當前消耗的 gas。

這些數據結構存在於許多地方,包括塊狀態轉移函數,狀態樹,區塊頭和前一個區塊頭中。在 Serenity 裏面這些將被大幅簡化:雖然許多數據仍然會存在,但他們會被轉移到特殊的合約中去;因此,唯一的”“狀態”將以一棵樹的形式繼續存在,數學上可以看作是形如 {address: {key: value}} 的映射。賬戶將是一些樹,賬戶合約代碼會被存放在主鍵 (key) 爲 \"\" 的地方(SSTORE 不可以修改),餘額會存在特別的“以太幣合約”中,而序號將由每一個帳號自己決定如何保存。收據也將被轉移到合約存儲區,他們會被保存在一個內容在每個區塊都會被覆蓋的“日誌合約”中。

這樣代碼實現中的狀態對象可以極大的簡化。現在只剩下一個兩級的 trie 了。可伸縮性方面的升級可能要求增加爲三級 trie (分片 ID, 地址,主鍵),這還沒有確定,但即使是這樣複雜性也遠低於現在。

需要注意,把以太幣轉移進一個合約管理並不是以太幣抽象的全部。事實上,一個有爭議的看法是相對於現狀這並不是一個很大的進步,因爲爲了向前兼容那些和以太幣相關的操作碼(帶 value 參數的 CALLBALANCE 等等)依然保留着。某種程度上說,這只是數據存放的一次重組。

4

未來計劃

在第二個概念原型中,我們計劃讓抽象更進一步。目前區塊和交易級別的狀態轉移函數依然有相當的複雜性(例如更新收據,gas 限制,交易索引,區塊高度,狀態根節點),我們的目標是爲交易創建一個“入口”對象來處理所有這些每一個交易都需要的額外的“樣板邏輯”,以及“塊開始”和“塊結束”的入口。理論上的終極目標,是找到一個只有一個入口點的協議,這樣狀態轉移函數只需要從零地址發送一條包含區塊內容數據的消息給入口點即可。這樣做的目的是儘可能的減少客戶端實現的共識關鍵部分(consensus-critical client implementation)的大小,把儘可能多的邏輯推到以太坊自身上去。這樣即使爲了達到我們對交易速度和可伸縮性的目標,我們需要採用一個接受硬分叉和一定的新複雜度的激進開發制度,也能夠個確保以太坊的多重客戶端形態可以持續而無需大量額外開發工作和安全審計。

內容來源:CSDN

作者:小溪

原文鏈接:

https://blog.csdn.net/fidelhl/article/details/50727972

理解 以太坊 Serenity - 第一部分 : 深度抽象

_
_

以下是我們的知識星球,歡迎有興趣的小夥伴加入我們,共同成長 !

_
_

理解 以太坊 Serenity - 第一部分 : 深度抽象

__