以太坊紫皮書(中文版) <ignore_js_op> 做者:Vitalik Buterin 譯者&來源:LinktimeTech 微信公衆號 在剛剛閉幕的以太坊Devcon 2大會上,以太坊創始人Vitalik分享了他的最新研究成果《以太坊紫皮書》,在此咱們將其翻譯成中文,供你們閱讀。《紫皮書英文》原版你們也能夠從咱們的公衆號中找到並閱讀。固然,如此前沿和複雜的論文翻譯是很大的考驗,若是你們以爲如下內容有問題,請及時與咱們反饋,咱們將在後期的公衆號文章中進行糾正。論文全文內容以下: <ignore_js_op> (爲何叫紫皮書?) 前言 在過去十年中,諸如Bitcoin、Namecoin和以太坊這些項目充分展示了密碼經濟共識網絡對促成下一代去中心化系統的強大推力,並潛移默化的將開發視野從簡單的數據存儲和信息服務擴展到任何狀態應用的後臺管理。基於這個系統,在全球範圍內提議和執行的應用,涵蓋了全球低價支付系統,金融合同,市場預測,身份註冊和現實世界產權,創建更安全的證書管理系統,甚至經過供應鏈對製造品進行溯源和跟蹤管理。 可是,這個系統的技術基礎仍然存在嚴重的效率問題。由於在網絡上每一個全節點都必須維護整個系統的狀態和處理每一個交易,整個區塊網絡效率受限於單個計算節點。如今大部分系統所採用的共識機制,工做量證實(POW),須要消耗大量的電力去運營; 基於POW機制的最大的工做區塊鏈Bitcoin,消耗了至關於整個愛爾蘭的用電量。 這篇文章爲上述問題提供將POS和基於分片證實進行合併的解決方案。POS自己並非一個新奇的主意,2011年就已經存在,但新的算法展示了實質性的好處,不只解決了前一系統的缺陷,甚至擁有POW未曾有的屬性。 POS能夠被想象成一種虛擬挖礦。然而在POW模式下,用戶須要花費必定的金錢買一臺電腦,而後消耗真實的電力,其隨機得到區塊鏈的成本與消耗的電力大體成比例。在POS模式下,用戶花費金錢購買系統內的虛擬代幣,而後用一個內部協議機制將虛擬代幣轉換成虛擬電腦,系統模擬隨機產生的區塊的成本與購買成本大體成比例,達到了POW一樣的出塊效果,卻不用消耗電力。 分片也並不新穎,在現行的分佈式數據庫設計中有超過10年的應用,可是到目前爲止,研究將其應用在區塊鏈上,仍有頗多限制。基本的路徑是解決可擴展的挑戰, 經過架構中的全球驗證程序集合中的節點(在咱們的狀況下,經過股權結合證實了)被隨機分配到特定的「碎片」,其中每一個碎片並行處理全局狀態的不一樣部分,從而確保工做是跨節點分佈處理,而不是每一個節點都重複作。 咱們渴望實現如下目標
咱們從描述一個算法開始,該算法實現目標1和2, 而後在第二個算法實現了目標3, 而後在第三個算法中必定程度上實現目標4,5(做爲一個限制條件,對一個節點的計算能力的平方大體成比例,如(4)和一個24小時的延遲跨碎片信息,有可能創建更快的消息做爲一個層上經過雙用途的存款,在例(5)。對目標(4)和(5)的更強級別的滿意,(6)也同樣,使得從新設計2.1和3.0。 常數 咱們設置:
最小的POS (注意,後續內容假設讀者有對以太坊1.0的基本瞭解) 咱們能夠建立一個最小可行的PoS算法,沒有諸如敲定肯定、額外的抗審查以及分片等特性。在地址CASPER_ADDRESS存在一個合約,其主要功能是追蹤驗證者集合的變化。該合約沒有特殊的特權,除了調用該合約是驗證區塊標頭過程當中的一部分,並且是包括在創世區塊,而不是經過交易被動態添加的。驗證者集合初始設置在創世區塊中,並能夠經過如下函數進行調整:
接受必定量的以太幣做爲保證金,發送者指定一段驗證代碼(本質爲EVM字節碼,代碼主要功能是用做一種公鑰,以便後續其餘的節點驗證由他們進行簽名的區塊數據以及相關的網絡共識消息),一個隨機提交的交易(一個32字節的哈希用於驗證者的選擇;詳見下文)和最終提現地址一併發送。值得注意的是,提現能夠在一個特定的地址發送,該地址的合約功能惟一用途就是特定的地址條件下釋放資金,若是須要還能夠雙重用保證金。若是全部參數都被接受,在下一個時期將增長該驗證者到驗證者集合。(例如,若是保證金在第N個時期請求提取, 而驗證者在第N+2個時期被加入驗證者集合,這個一個時期等於EPOCH_LENGTH個區塊時間週期)。驗證代碼的哈希值(叫作vchash)能夠被驗證者用做識別號;不一樣驗證者具備一樣的哈希值是被禁止的。) startWithdrawal(bytes32 vchash, bytes sig): 開始撤回流程,要求一個簽名,該簽名須要經過驗證者的驗證代碼。若是簽名經過,從下一個時期開始,驗證者被從驗證者集撤回。注意,這個函數不退回以太幣。 還有一個函數: withdraw(bytes32 vchash): 撤回驗證者的以太幣到指定的提現地址,增長獎勵減小懲罰,只要驗證者已經從驗證者活動集合中經過使用 StartWithdrawal至少是WITHDRAWAL_DELAY幾秒前撤回。 準確的講,驗證代碼就像是放入區塊標頭的哈希碼,加上簽名,若是簽名有效返回1,反之,則返回0。這個機制確保了咱們不會將驗證者鎖定到任何一個特殊簽名的算法,相反容許驗證者使用驗證代碼從多重私鑰驗證簽名取代單一驗證,也容許使用Lamport簽名對抗量子計算機的攻擊。這個代碼在黑匣子環境下經過使用新的CALL_BLACKBOX操做碼執行,以保證執行獨立於外部狀態。這樣能夠防止一些攻擊,如一個驗證者建立了驗證代碼在狀態良好的時候返回1,在情況很差的時候(例如 Dunkle inclusion)返回0. deposit函數中randao 參數的值應該是計算一段長鏈哈希值結果,即設置祕密隨機的X,執行計算randao = sha3(sha3(sha3(sha3(.....(sha3(x))…))。每一個驗證者提供randao的值保存在Casper 合約中的存儲空間。 Casper合約也含有一個叫GlobalRandao的變量,初始化爲0。這個合約含有一個函數getValidator(uint256 skips):返回 skips 跳過之後的驗證者的代碼。例如 getValidator(0)返回第一個驗證者(驗證者通常來說能夠創造區塊),getValidator(1)返回第二個驗證者(若是第一個不能建立區塊,驗證者能夠建立) 每一個驗證者都是經過僞隨機算法從目前活動的驗證者集合進行選擇,隨機對初始保證金規模進行加權,並以Casper 合約中的globalRandao值爲僞隨機種子。除了簽名外,一個有效的區塊也必須包含爲那個驗證者目前保存Randao的原像。這個原像而後替換保存Randao值,而後也經過異或運算保存到合約的globalRandao值中。這樣,一個驗證者生成的每一區塊都要求脫掉一個驗證者的randao的一層。這是一種基於在這裏解釋( http://vitalik.ca/files/randomness.html )的隨機算法。 總之,一個區塊必須包含的以下的額外數據: <vchash><randao><sig> 其中,vchash是驗證代碼的32字節哈希值,用於快速識別驗證者。randao含義如上所描述(也是32字節),sig是簽名,能夠是任意長度(雖然咱們將區塊標頭的大小限制爲2048字節)。 <ignore_js_op> 建立區塊所須要的最短期能夠簡單的定義爲: GENESIS_TIME + BLOCK_TIME * <block height> + SKIP_TIME * <自創世區塊後全部的驗證者跳數和>。 在實際過程當中,這意味着,一旦發佈了某個區塊,那麼下一個區塊的0-skip驗證者會在BLOCK_TIME秒以後發佈,同理,1-skip驗證者則在BLOCK_TIME + SKIP_TIME秒以後發佈,以此類推。 若是一個驗證者發佈一個區塊太早,其餘的驗證者會忽視該區塊,直到在規定的時間以後,纔會處理該區塊(該中機制的進一步描述和驗證詳見這裏(http://vitalik.ca/files/timing.html);短BLOCK_TIME和長SKIP_TIME之間的不對稱性,能夠確保:在正常狀況下,區塊的平均保留時間能夠很是短,而在網絡延遲更長的狀況下,也能夠保證網絡的安全性)。 若是一個驗證者建立了一個包括在鏈內的區塊,他們獲得的區塊獎勵至關於此週期內活動驗證者集合內以太的總量乘以REWARD_COEFFICIENT * BLOCK_TIME。所以,若是驗證者老是正確的履行職責,REWARD_COEFFICIENT本質上成爲驗證者的「預期每秒收益率」;乘以~3200萬獲得近似的年化收益率。若是一個驗證者建立了一個不包括在鏈內的區塊,以後,在未來的任意時間(直到驗證者調用withdraw函數爲止)該區塊標頭能夠做爲一個「dunkle」經過Casper合約的includeDunkle函數,被包括在鏈內;這使得驗證者損失了至關於區塊獎勵的錢數(以及向包括dunkle在內的當事方提供一小部分罰款做爲激勵)。所以,驗證者應當在肯定該區塊在鏈內的可能性超過50%,才實際建立該區塊;該機制不鼓勵全部鏈上的驗證。驗證者的累計保證金,包括獎勵和罰款,存儲在Casper合約的狀態內。 「dunkle」機制的目的是爲了解決權益證實中的「零賭注」的問題,其中,若是沒有罰款,只有獎勵,那麼驗證者將被物質激勵,試圖在每一個可能的鏈上建立區塊。在工做量證實場景下,建立區塊須要成本,而且只有在「主鏈」上建立區塊纔有利可圖。Dunkle機制試圖複製工做量證實中的經濟理論,針對建立非主鏈上區塊進行人工罰款,來代替工做量證實中電費用的「天然罰款」。 假設一個固定大小的驗證者集合,咱們能夠很容易的定義分叉選擇規則:計算區塊數,最長鏈勝出。假設驗證者集合能夠變大和縮小,可是,該規則就不太適用了,由於做爲少數支持的分叉的速度一個時期之後將像多數支持的分叉同樣。所以,咱們能夠用計算的區塊數代替定義的分叉選擇規則,給每一個區塊一個至關於區塊獎勵的權重。由於區塊獎勵與積極驗證的以太總量成正比,這確保了更積極驗證以太的鏈得分增加速度更快。 咱們能夠看出,這條規則能夠用另外一種方式很方便的理解:基於價值損失的分叉選擇模型。該原則是:咱們選擇驗證者賭最多價值的鏈,就是說,驗證者認可除了上述的鏈外,全部其餘鏈都會損失大量的資金。咱們能夠等同認爲,這條鏈是驗證者失去資金最少的鏈。在這樣一個簡單的模式中,很容易看出這如何簡單的對應着區塊權重爲區塊獎勵的最長鏈。該算法是儘管簡單,但用於股權證實的實現來講也足夠高效。 添加敲定 下一步是增長經濟敲定的概念。咱們按照如下方式進行。在區塊標頭內部,除了指向上一個區塊的哈希以外,如今驗證者也對某個之前區塊FINALIZATION_TARGET敲定機率作出了一個斷言。該斷言被當作一個賭注,如「我相信區塊0x5e81d……將被敲定,而且在全部區塊史中,若是這一斷言是錯誤的,我願意損失V_LOSS,假設在全部區塊史中,這一斷言是正確的,我將獲得V_GAIN。」驗證者選擇odds參數,而V_LOSS和V_GAIN,按照以下方式計算(令total_validating_ether爲活動驗證者集合的以太總量,MAX_REWARD是容許的區塊獎勵的最大值,bet_coeff是下文定義的係數):
<ignore_js_op> V_GAIN and V_LOSS values relative to the BASE_REWARD, assuming bet_coeff = 1,假設bet_coeff = 1,V_GAIN值和V_LOSS值與BASE_REWARD的相關性 FINALIZATION_TARGET從null開始, 可是區塊1期間,它被設置成區塊0,。bet_coeff初始(開始)值被設置爲1,另外一個變量cached_bet_coeff設置爲0。可是bet_coeff不能減小到低於MIN_BET_COEFF,在每一個區塊,咱們設置bet_coeff -= bet_coeff / FINALITY_REWARD_DECAY_FACTOR,cached_bet_coeff -= cached_bet_coeff / FINALITY_REWARD_DECAY_FACTOR(這確保了總有激勵驅動去打賭)。當建立一個區塊,驗證者獲得BASE_REWARD * log(MAXODDS) * cached_bet_coeff,其中MAXODDS是最大的可能賠率,如MAX_DEPOSIT_SIZE / BASE_REWARD。該機制隨所實現的是,一旦某一區塊被肯定被敲定,驗證者從中獲得獎勵,就像他們以最大odds繼續進行驗證同樣。這確保了,驗證者不會受到不正當的激勵而共謀經過延遲敲定某個區塊以得到最大收益。 當Casper合約肯定FINALIZATION_TARGET已被敲定(即已知區塊的總價值損失超過某個閾值),咱們將新的FINALIZATION_TARGET設置成當前區塊,咱們設置cached_bet_coeff += bet_coeff,而且bet_coeff從新設置爲1。從下一個區塊開始,敲定過程從新開始設置新的FINALIZATION_TARGET。若是,有一個短鏈分裂,敲定過程可能同時處理多個區塊,甚至是不一樣高度的區塊;可是,鑑於區塊投注的默認驗證者策略,以及支持它的最高價值損失,咱們預計收斂過程傾向於選擇他們其中的一個(此處的收斂參數基本上與最小權益證實相一致)。 當新的區塊敲定過程開始啓動時,咱們指望最初的賠率很低,這表示驗證者對短範圍分叉的恐懼,可是隨着時間的推移,驗證者願意投注的賠率會逐漸增長。特別的若是他們看到其餘驗證者對該區塊進行高賠率投注,驗證者的賭注也會增長。能夠預計,該區塊的價值損失將以指數倍增長,從而在對數時間內,達到最大「總保證金損失」。 在區塊標頭的額外數據中,咱們如今將所需的數據格式更改成如下格式: <vchash><randao><blockhash><logodds><sig> 其中區塊哈希是上個打賭的區塊的哈希,而且logodds爲1字節值,表明對數形式的賠率(即,0對應1,8對應2,16對應4等)。 請注意,咱們不能容許驗證者徹底自由地設置賠率。考慮以下場景,若是有兩個競爭關係的敲定目標,B1和B2(即存在兩個鏈,其中一個的FINALIZATION_TARGET設置爲B1,另外一個的的FINALIZATION_TARGET設置爲B2),而且圍繞B1開始造成共識,而後一個惡意驗證者可能會忽然對B2投入一個高賠率賭注,它的價值損失足夠影響共識,從而引起短範圍分叉。所以,咱們使用如下規則,經過限制V_LOSS來限制賠率:
該規則設計上引入了一個安全約束:當至少(樣本)三分之二的其它驗證者風險爲x後,當前驗證者的風險僅能夠爲1.5x。這與拜占庭容錯共識算法的事先承諾或承諾模式相似,一個驗證者應等待其餘三分之二的驗證者完成給定的步驟後,才能進行下一步,並確保必定的安全,也確保大多數共謀不能參與「惡意破壞」攻擊(如,讓其餘的驗證者講大量賭注添加在一個區塊,而且隨後推進共識到一個別的區塊),沒法共謀,由於共謀自己須要耗費大量資金(實際上,共謀損失金錢的速度比受害者損失金錢的速度更快,這是一個顯著的特性,由於它確保,在大多數敵對狀況下,惡意操做者會隨着時間的推移,常常會被「淘汰」。) 若是一個區塊做爲一個dunkle被加入鏈中,賭注被處理,而且罰款和獎勵也會產生。例如,若是有兩個高度爲5000的區塊A1和A2,互爲競爭的敲定目標,而且有兩個高度爲5050的區塊B1和B2(兩區塊均以A1爲上一代區塊),而且驗證者在B1上構建區塊C,對A1下賭注,隨後,若是B2最終肯定爲主鏈區塊,B1和C將成爲dunkle,而且C也將因B1 vs B2下錯注而被懲罰,可是仍是會因A1被賭對而進行獎勵。 然而,假設C中的V_LOSS是這樣的,若是B1包含在內,則V_LOSS < V_LOSS_MAX;若是B2包含在內,則V_LOSS > V_LOSS_MAX。以後,爲了保證預期的價值損失特性,咱們制定了一個額外的罰款:即便驗證者賭對了,但咱們仍以V_LOSS - V_LOSS_MAX對他們進行處罰。所以,咱們有效地將V_LOSS賭注,分解成(i)價值損失V_LOSS_MAX的賭注和(ii)V_LOSS - V_LOSS_MAX的單純價值銷燬,從而保證這種規模過大的賭注仍僅經過V_LOSS_MAX經由分叉選擇規則變換。這意味着投注在某種意義上是不「徹底的」,由於若是該區塊的子代區塊中的不少都分叉了,即便該區塊已經完成敲定肯定,某個區塊的賭注仍可能引發罰款。在投注模型中的單純價值損失,被認爲是對價值損失分叉選擇規則利潤純度的一個可接受的權衡。 計分與策略實現 價值損失計分能夠經過如下算法實現:
<ignore_js_op> 此處用於舉例的V_LOSS;在現實中,他們不會被容許這樣快速的增加,而且B或C會要求A上的較高的V_LOSS成爲敲定候選區塊。 一個簡單的驗證者策略是僅在頭部建立區塊,而且作出敲定賭注,此處的價值損失是所描述的最大價值損失的80%。 輕客戶端同步 敲定機制開啓了一個快速輕客戶端同步算法的大門。該算法包括如下幾步: <ignore_js_op>
很是值得關注的是,經過步驟1到5能夠用兩個網絡請求和幾秒鐘計算來驗證全天的區塊。 分片 如今,咱們考慮從一個分片擴大到多個分片。咱們構建的模型以下。取代已有的單條區塊鏈,咱們如今擁有被咱們稱爲「分片」的多條相關聯的區塊鏈。NUM_SHARDS分片的編號爲分片0至分片NUM_SHARDS – 1,其中分片0簡單的做爲常規股權證實區塊鏈進行,其肯定性如上所述,可是分片1……NUM_SHARDS – 1工做機制有所不一樣。在每一個時期的開始,爲每一個分片隨機挑選VALIDATORS_PER_SHARD個驗證者,而且被分配爲下一個時期的驗證者(如,n+1時期的驗證者在n時期時被指配)。當調用getValidator(skip)以肯定這些分片內一個分片的驗證者,僅僅隨機從選取的驗證者集合中選擇一個驗證者(平等地分配,由於在挑選的時候就已經對保證金大小進行加權)。分片1……NUM_SHARDS – 1的肯定性賭注並未在分片內作出,而是在分片0內作出。當賭注被作出,它就被存儲,賭注僅在子代區塊週期結束後,才被處理(如,n+1時期的區塊肯定斷言,將在n+3區塊週期開始時,在分片0內進行處理)。 <ignore_js_op> 若是已經爲一個分片挑選了一個驗證者,那麼這個驗證者將須要調用Casper合約的registerForShard(bytes32 vchash,uint256 shard,uint256 index,bytes32 randao)函數,其中vchash是驗證者的驗證代碼哈希,shard是分片ID,index是一個數值且0 <= index < VALIDATORS_PER_SHARD,其中得getShardValidator(uint256 shard,uint256 index)返回給定的驗證代碼哈希,而且randao是一個randao承諾。爲了引導驗證者,該函數生成了一個收據,該收據可以經過利用confirmReceipt(uint256 receiptId)在目標分片上進行確認。 getShardValidator依賴於一個單獨的隨機源,業務邏輯與getValidator相似。該隨機源,按照以下步驟得出:
使用Iddo Bentov的低影響函數,增長了隨機源的操縱成本,由於,這個特別的隨機源種子會產生實質性的經濟結果,所以,它比正常操縱目標更大一些。 跨分片敲定賭注並不在區塊標頭上,因此不會過分的阻礙輕客戶端;相反,驗證者將建立一個交易,在它們建立的任何區塊間,調用一個registerFinalityBets(bytes32[] hashes,bytes logodds)函數,任意一個區塊中建立預期的NUM_SHARDS個哈希和一個長度爲NUM_SHARDS的字節數組,每一個字節表明相應的區塊哈希的賠率。 驗證者的典型工做流程是維持分片0的一個「全節點」,而且保持追蹤被分配給它們的將來分片。若是一個驗證者被分配給一個分片,他們將利用Merkle樹證實下載狀態,而且確保當他們須要開始驗證時,他們已經下載了相應狀態。對於該時期,他們做爲該分片的驗證者,而且建立區塊,同時,他們將在全部的分片上作出敲定賭注,他們經過觀測(i)每一個分片上的最長鏈,(ii)其餘的驗證者的敲定賭注,以及(iii)在片區內試圖達到51%成功攻擊的各類二次啓發方法和機制(如,欺詐證實)。注意,分配到任何給定分片的機率與驗證者的累計以太成比例,所以,若是驗證者的資產成倍,那麼須要處理的計算也會加倍。這個特性被認爲是何意的,由於它增長了公平性,並下降了礦池激勵,同時引入了一個原則,該原則下處理交易並存儲區塊鏈自己也成爲了「工做量混合證實」的一種形式。 取樣機制的初衷是爲了確保系統僅依靠少許驗證者進行實際交易驗證,同時系統可以安全應對累積以太保證金高達~33-40%(低於50%,由於總累積以太爲33-50%的攻擊者在某些給定的分片會很「幸運」)的攻擊者;由於取樣是隨機的,攻擊者不可以選擇將他們的權益集中在一個分片上,許多工做量分片方案的一個致命缺陷上。即便一個分片被攻擊了,還有第二道防線:若是其餘驗證者發現攻擊的證據,那麼他們能夠拒絕作出跟隨攻擊者分叉的敲定聲明,而確認由誠實節點建立的鏈。若是一個分片上的一個攻擊者試圖從無效區塊建立一個鏈,其餘分片的驗證者能夠檢測到,而且以後暫時徹底驗證該分片上的節點,而且確保他們僅敲定有效的區塊。 跨分片通訊 本方案中的跨分片通訊遵循以下工做。咱們建立一個ETHLOG操做碼(帶有兩個參數:to value),其建立的一個日誌記錄,其存儲內容是空字符串(注意,該空字符串,不是32個零字節,一個傳統的LOG只能存儲32字節的字符串),它的數據是一個64字節的字符串,包括目標和具體值。咱們建立的GETLOG操做碼,須要一個由區塊定義ID的單獨的參數。number * 2**64 + txindex * 2**32 + logindex(其中txindex是交易的index,包括區塊的log,logindex是交易receipt中的log index)試圖獲取指定的存儲內容,存儲在狀態中的日誌代表,該日誌已被消耗,而且將日誌數據放在目標數組內。若是日誌值爲空串,這也將傳輸以太給收件人。爲了成功獲得日誌內容,調用操做碼的交易必須攜帶日誌ID參數。若是v=0,咱們容許簽名中的r值從新用於此目的(注意:這意味着此處僅可使用EIP 86交易;咱們但願到如今爲止,EIP 86交易將是交易的主要形式)。 如今抽象共識不再是一個單鏈,而是一個鏈的集合,c[0]…c[NUM_SHARDS - 1]。狀態轉移函數再也不是stf(state, block) -> state',而是stf(state_k, block, r_c[0]…r_c[NUM_SHARDS - 1]) ->state_k,其中
|