盡管以太坊的許多理念在早先的加密貨幣(如比特幣)上已經(jīng)運(yùn)用并測(cè)試了5年之久,但從處理某些協(xié)議功能上來(lái)說(shuō),以太坊的處理方式與常見(jiàn)方式仍有許多不同。很多時(shí)候,以太坊會(huì)被用來(lái)建立全新的經(jīng)濟(jì)方法,因?yàn)樗哂性S多其他系統(tǒng)不具備的功能。本文會(huì)詳細(xì)描述以太坊所有潛在的優(yōu)點(diǎn)以及在構(gòu)建以太坊協(xié)議過(guò)程中某些有爭(zhēng)議的地。另外,也會(huì)指出我們的方案及替代方案潛在的風(fēng)險(xiǎn)。
原則
以太坊協(xié)議的設(shè)計(jì)遵循以下幾點(diǎn)原則:
1.三明治復(fù)雜模型
我們認(rèn)為以太坊的底層協(xié)議應(yīng)盡可能的簡(jiǎn)單,接口設(shè)計(jì)應(yīng)易于理解,那些不可避免的復(fù)雜部分應(yīng)放入中間層。中間層不是核心共識(shí)的一部分,且對(duì)最終用戶不可見(jiàn),它包含:高級(jí)語(yǔ)言編譯器、參數(shù)序列化和反序列化腳本、存儲(chǔ)數(shù)據(jù)結(jié)構(gòu)模型、leveldb存儲(chǔ)接口以及線路協(xié)議等。當(dāng)然,這樣的設(shè)置也并非絕對(duì)。
2.自由
不應(yīng)限制用戶使用以太坊協(xié)議,也不應(yīng)試圖優(yōu)先支持或不支持某些以太坊合約或交易。這一點(diǎn)與“網(wǎng)絡(luò)中立”概念背后的指導(dǎo)原則相似。比特幣交易協(xié)議就沒(méi)有遵循這一原則。在比特幣交易協(xié)議中,并不鼓勵(lì)為了“去除標(biāo)簽”而使用區(qū)塊鏈(如,數(shù)據(jù)存儲(chǔ),元協(xié)議)。某些情況下,對(duì)準(zhǔn)協(xié)議進(jìn)行明顯修改會(huì)引起不法分子以未經(jīng)授權(quán)方式使用區(qū)塊鏈來(lái)攻擊應(yīng)用。因此,在以太坊,我們強(qiáng)烈建議設(shè)置交易費(fèi)用,且用戶使用區(qū)塊鏈的步驟越多,交易費(fèi)用也就越多(類似庇古稅)。這樣,既可以將交易費(fèi)用作為合法礦工的獎(jiǎng)勵(lì),又能讓那些不法分子付出代價(jià),一舉兩得。
3.泛化
以太坊協(xié)議的特性和操作碼應(yīng)最大限度地體現(xiàn)低層次的概念(就像基本粒子一樣),以便它們可以隨意組合。因此,通過(guò)剝離那些不需要的功能,使低層次的概念更加高效。遵循這一原則的例子是,我們選擇LOG操作碼作為向dapps提供信息的方式,而不是像之前那樣記錄下所有交易和消息信息。在早先,“消息(message)”的概念完完全全是多種概念的集合,它包含“函數(shù)調(diào)用(function call)”和“外在觀察者感興趣的事情(event interesting to outside watchers)”,而兩者是完全可以分離開(kāi)來(lái)的。
4.沒(méi)有特點(diǎn)就是最大的特性點(diǎn)
為了遵循泛化原則,我們拒絕將那些高級(jí)用例內(nèi)嵌為協(xié)議的一部分,哪怕是經(jīng)常使用的用例,也絕不這么做。如果人們真的想實(shí)現(xiàn)這些用例,可以在合約內(nèi)創(chuàng)建子協(xié)議(如,基于以太坊的子貨幣,比特幣/萊特幣/狗幣的側(cè)鏈等)。比如,在以太坊中就缺少類似比特幣中的“時(shí)間鎖定”功能。但是,通過(guò)以下協(xié)議可以模擬出這個(gè)功能:用戶發(fā)送簽名數(shù)據(jù)包到特定的合約中處理,如果數(shù)據(jù)包在特定合約中有效,則執(zhí)行相應(yīng)的函數(shù)。
5.沒(méi)有風(fēng)險(xiǎn)規(guī)避機(jī)制
如果風(fēng)險(xiǎn)的增加帶來(lái)了可觀的好處,我們?cè)敢獬袚?dān)更高的風(fēng)險(xiǎn)(例如,廣義狀態(tài)轉(zhuǎn)換,區(qū)塊時(shí)間提升50倍,共識(shí)效率)。
這些原則指導(dǎo)著以太坊的發(fā)展,但它們并不是絕對(duì)的;某些情況下,為了減少開(kāi)發(fā)時(shí)間或者不希望一次作出過(guò)多改變,也會(huì)使我們推遲作出某些修改,把它留到將來(lái)的版本中去修改。
區(qū)塊鏈層協(xié)議
本節(jié)對(duì)以太坊中區(qū)塊鏈層協(xié)議的改變進(jìn)行了描述,包括區(qū)塊和交易是如何工作的、數(shù)據(jù)如何序列化及存儲(chǔ)、賬戶背后的機(jī)制。
賬戶 ,而非UTXO①
比特幣及其許多衍生品,都將用戶的余額信息存儲(chǔ)在UTXO結(jié)構(gòu)中,系統(tǒng)的整個(gè)狀態(tài)由一系列的“有效的輸出”組成(可以將這些“有效的輸出”想象成錢(qián)幣)。每個(gè)UTXO都有擁有者和自身的價(jià)值屬性。一筆交易在消費(fèi)若干個(gè)UTXO同時(shí)也會(huì)生成若干個(gè)新的UTXO。“有效的輸出”中有效需滿足下面幾點(diǎn)約束:
1.每個(gè)被引用的輸入必須有效,且未被使用過(guò);
2.交易的簽名必須與每筆輸入的所有者簽名匹配;
3.輸入的總值必須等于或大于輸出的總值。
因此,比特幣系統(tǒng)中,用戶的“余額”是該用戶的私鑰能夠有效簽名的所有UTXO的總和。下圖展示了比特幣系統(tǒng)中交易輸入輸出過(guò)程:
但是,以太坊拋棄了UTXO的方案,轉(zhuǎn)而使用更簡(jiǎn)單的方法:采用狀態(tài)(state)的概念存儲(chǔ)一系列賬戶,每個(gè)賬戶都有自己的余額,以及以太坊特有的數(shù)據(jù)(代碼或內(nèi)部存儲(chǔ)器)。如果交易發(fā)起方的賬戶余額足夠支付交易費(fèi)用,則交易有效,那么發(fā)起方賬戶會(huì)扣除相應(yīng)金額,而接受賬戶則計(jì)入該金額。某些情況下,接受賬戶內(nèi)有需要執(zhí)行的代碼,則交易會(huì)觸發(fā)該代碼的執(zhí)行,那么賬戶的內(nèi)部存儲(chǔ)器可能就會(huì)發(fā)生變化,甚至可能會(huì)創(chuàng)建額外的信息發(fā)送給其他賬戶,從而導(dǎo)致新的交易發(fā)生。
盡管以太坊沒(méi)有采用UTXO的概念,但UTXO也不乏有一些優(yōu)點(diǎn):
1.較高程度的隱私保護(hù)
如果用戶每次交易都使用一個(gè)新的地址,那么賬戶之間的相互關(guān)聯(lián)就很困難。這樣做適用于對(duì)安全性要求高的貨幣系統(tǒng),但對(duì)任何dapp應(yīng)用來(lái)說(shuō)就不合適了。因?yàn)閐app通常需要跟蹤用戶復(fù)雜的綁定狀態(tài),而dapp的狀態(tài)并不能像貨幣系統(tǒng)中的狀態(tài)那樣簡(jiǎn)單地劃分。
2.潛在地可擴(kuò)展性
UTXO在理論上可擴(kuò)展性更好。因?yàn)槲覀冎荒芤揽磕切┙鹑谪泿艙碛姓邅?lái)維護(hù)能夠證明貨幣所有權(quán)的默克爾樹(shù),即使所有的人(包括數(shù)據(jù)的擁有者)都遺忘了某一數(shù)據(jù),真正受損也只有數(shù)據(jù)的擁有者,其他人不受影響。
在以太坊賬戶系統(tǒng)中,如果一個(gè)賬戶對(duì)應(yīng)在默克爾樹(shù)中信息被所有人都丟失了,那么該賬戶將無(wú)法處理任何能夠影響它的消息,包括發(fā)送給它的消息,它也無(wú)法處理。
不過(guò),并非只有UTXO能夠可擴(kuò)展,也存在不依賴UTXO就能擴(kuò)展的方式(此處沒(méi)有擴(kuò)展開(kāi)來(lái)講,譯者注)。
賬戶的好處有以下幾點(diǎn):
1.節(jié)省大量空間
如果一個(gè)賬戶有5個(gè)UTXO,則從UTXO模式轉(zhuǎn)成賬戶模式所需空間會(huì)從300字節(jié)降到30字節(jié)。具體計(jì)算如下:
300 = (20+32+8)* 5 (20是地址字節(jié)數(shù),32是TX的id字節(jié)數(shù),8是交易金額值字節(jié)數(shù));
30 = 20 + 8 + 2 ( 20是地址字節(jié)數(shù),8是交易金額值字節(jié)數(shù),2是nonce②字節(jié)數(shù))
但實(shí)際節(jié)約并沒(méi)有這么大,因?yàn)橘~戶需要被存儲(chǔ)在帕特里夏樹(shù)中。另外以太坊中交易也比比特幣中的更小(以太坊中100字節(jié),比特幣中200-250字節(jié)),因?yàn)槊看谓灰字恍枰梢淮我茫淮魏灻约耙粋€(gè)輸出。
2.可替代性更高
在UTXO結(jié)構(gòu)中,“有效輸出”的源碼實(shí)現(xiàn)中沒(méi)有區(qū)塊鏈層的概念,所以不管是在技術(shù)還是法律上,通過(guò)建立一個(gè)紅名單/黑名單,并依據(jù)的這些“有效輸出”的來(lái)源區(qū)分它們并不是很實(shí)際。
3.簡(jiǎn)單
以太坊編碼更簡(jiǎn)單、更易于理解,尤其是在涉及到復(fù)雜腳本時(shí)。盡管任何去中心化應(yīng)用都可以用UTXO方式來(lái)實(shí)現(xiàn),但這種方式實(shí)質(zhì)上是通過(guò)賦予一個(gè)腳本限制給定的UTXO能夠使用以及請(qǐng)求的UTXO的種類的方式來(lái)實(shí)現(xiàn),包括腳本評(píng)估的應(yīng)用更改根狀態(tài)的默克爾樹(shù)證明。因此,UTXO實(shí)現(xiàn)方式比以太坊使用賬戶的方式要復(fù)雜的多。
4.輕客戶端
輕客戶端可以隨時(shí)通過(guò)沿指定方向掃描狀態(tài)樹(shù)來(lái)訪問(wèn)與賬戶相關(guān)的所有數(shù)據(jù)。在UTXO方式中,引用隨著每個(gè)交易的變化而變化,這對(duì)于長(zhǎng)時(shí)間運(yùn)行并使用了上文提到的UTXO根狀態(tài)傳播機(jī)制的dapp應(yīng)用來(lái)說(shuō),無(wú)疑是繁重的。
我們認(rèn)為,賬戶的好處大大超過(guò)了其他方式,尤其是對(duì)于我們正在處理的包含任意狀態(tài)和代碼的dapp應(yīng)用而言。另外,本著“沒(méi)有特點(diǎn)就是最大的特點(diǎn)”的指導(dǎo)原則,我們認(rèn)為如果用戶真的關(guān)心私密性,則可以通過(guò)合約中的簽名數(shù)據(jù)包協(xié)議來(lái)建立一個(gè)加密“混合器”進(jìn)行加密。
賬戶方式的一個(gè)弱點(diǎn)是:為了阻止重播攻擊,每筆交易必須有nonce,這就使得賬戶需要跟蹤nonce的使用情況,并且只有在nonce最后使用后且值為1時(shí)才接受交易。這就意味著,即使不再使用的賬戶,也不能從賬戶狀態(tài)中移除。解決這個(gè)問(wèn)題的一個(gè)簡(jiǎn)單方法是讓交易包含一個(gè)區(qū)塊號(hào),使它們?cè)趲讉€(gè)時(shí)間段內(nèi)不重復(fù),并且每個(gè)時(shí)間段重置nonce。由于完全掃描賬戶的開(kāi)銷太大,所以為了刪除未使用的賬戶,礦工或用戶需要通過(guò)“Ping”操作來(lái)實(shí)現(xiàn)。在1.0上我們沒(méi)有實(shí)現(xiàn)這個(gè)機(jī)制,1.1及以上版本可能會(huì)使用這個(gè)機(jī)制。
默克爾帕特里夏樹(shù)
默克爾帕特里夏樹(shù)(Merkle Patricia tree/trie),由Alan Reiner提出設(shè)想,并在瑞波協(xié)議中得到實(shí)現(xiàn),是以太坊的主要數(shù)據(jù)結(jié)構(gòu),用于存儲(chǔ)所有賬戶狀態(tài),以及每個(gè)區(qū)塊中的交易和收據(jù)數(shù)據(jù)。MPT是默克爾樹(shù)和帕特里夏樹(shù)的結(jié)合縮寫(xiě),結(jié)合這兩種樹(shù)創(chuàng)建的結(jié)構(gòu)具有以下屬性:
1.每個(gè)唯一鍵值對(duì)唯一映射到根的hash值;在MPT中,不可能僅用一個(gè)鍵值對(duì)來(lái)欺騙成員(除非攻擊者有~2^128 的算力);
2.增、刪、改鍵值對(duì)的時(shí)間復(fù)雜度是對(duì)數(shù)級(jí)別。
MPT為我們提供了一個(gè)高效、易更新、且代表整個(gè)狀態(tài)樹(shù)的“指紋”。
關(guān)于MPT更詳細(xì)描述:https://github.com/ethereum/wiki/wiki/Patricia-Tree
MPT的具體設(shè)計(jì)決策如下:
1.有兩類節(jié)點(diǎn)
KV節(jié)點(diǎn)和離散節(jié)點(diǎn)。KV節(jié)點(diǎn)的存在提高了效率,因?yàn)槿绻谔囟▍^(qū)域樹(shù)是稀疏的,KV節(jié)點(diǎn)可作為一個(gè)“快捷方式”,代替深度為64的樹(shù)。
2.離散節(jié)點(diǎn)是16進(jìn)制,不是二進(jìn)制
這樣讓查找更有效率,我們現(xiàn)在認(rèn)識(shí)到這種選擇并不理想,因?yàn)?6進(jìn)制樹(shù)的查找效率在二進(jìn)制中可以通過(guò)批次存儲(chǔ)節(jié)點(diǎn)來(lái)模擬。MPT樹(shù)的結(jié)構(gòu)實(shí)現(xiàn)是非常容易出錯(cuò)的,最終至少會(huì)造成狀態(tài)根不匹配。
3.空值(empty value)與非會(huì)員(non-membership)之間沒(méi)有區(qū)別
這樣做是為了簡(jiǎn)化邏輯,以太坊中未設(shè)置的值默認(rèn)為0,空字符串也用0表示。然而,需要強(qiáng)調(diào)的是,這樣做犧牲了一些通用性,因而也不是最優(yōu)的。
4.終節(jié)點(diǎn)和非終節(jié)點(diǎn)的區(qū)別
技術(shù)上,標(biāo)識(shí)一個(gè)節(jié)點(diǎn)“是否是終節(jié)點(diǎn)”是沒(méi)必要的,因?yàn)橐蕴恢兴械臉?shù)都被用于存儲(chǔ)靜態(tài)秘鑰長(zhǎng)度,但為了增加通用性,我們還是會(huì)添加這個(gè)標(biāo)識(shí),以期望以太坊的MPT的實(shí)現(xiàn)方式能夠被其他加密貨幣原樣采納。
5.在安全樹(shù)中采用SHA3(k)作為秘鑰(在狀態(tài)樹(shù)和賬戶存儲(chǔ)樹(shù)中使用)
使用SHA3(k),通過(guò)設(shè)置離散節(jié)點(diǎn)的鏈的深度為64,以及反復(fù)調(diào)用SLOAD 和 SSTORE指令,使那些企圖對(duì)樹(shù)采取Dos攻擊的行為變得非常困難。不過(guò),這也讓窮舉樹(shù)的節(jié)點(diǎn)變得困難,如果你希望你的客戶端有窮舉的能力,最簡(jiǎn)單的方法是維持一個(gè)數(shù)據(jù)庫(kù)映射:sha3(k) -》 k
RLP
RLP(recursive length prefix):遞歸長(zhǎng)度前綴。
RLP編碼是以太坊中主要的序列化格式,它的使用無(wú)處不在:區(qū)塊、交易、賬戶狀態(tài)以及線路協(xié)議消息。詳見(jiàn)RLP正式描述: https://github.com/ethereum/wiki/wiki/RLP
RLP旨在成為高度簡(jiǎn)化的序列化格式,它唯一的目的是存儲(chǔ)嵌套的字節(jié)數(shù)組③。不同于protobuf、BSON等現(xiàn)有的解決方案,RLP并不定義任何指定的數(shù)據(jù)類型,如Boolean、floa、double或者integer。它僅僅是以嵌套數(shù)組的形式存儲(chǔ)結(jié)構(gòu),并將其留給協(xié)議來(lái)確定數(shù)組的含義。RLP也沒(méi)有明確支持map集合,半官方的建議是采用 [[k1, v1], [k2, v2], 。..] 的嵌套數(shù)組來(lái)表示鍵值對(duì)集合,k1,k2 。.. 按照字符串的標(biāo)準(zhǔn)排序。
與RLP具有相同功能的方案是protobuf或BSON,它們是一直被使用的算法。然而,以太坊中,我們更偏向于使用RLP,因?yàn)椋?/p>
1.它易于實(shí)現(xiàn);
2.絕對(duì)保證字節(jié)的一致性。
許多語(yǔ)言的Map集合沒(méi)有明確的排序,并且浮點(diǎn)格式有很多特殊情況,這可能造成相同數(shù)據(jù)卻導(dǎo)致不同編碼和hash值。通過(guò)內(nèi)部開(kāi)發(fā)協(xié)議,我們能確保它是帶著這些目標(biāo)設(shè)計(jì)的(這是一般原則,也適用于代碼的其他部分,如VM)。BitTorrent使用的編碼方式bencode也許可以替代RLP。不過(guò)它采用的是十進(jìn)制的編碼方式,與采用二進(jìn)制的RLP相比,稍微遜色了點(diǎn)。
壓縮算法
線路協(xié)議和數(shù)據(jù)庫(kù)都采用了一個(gè)自定義的壓縮算法來(lái)存儲(chǔ)數(shù)據(jù)。該算法可描述為:行程編碼④值為0并同時(shí)保留其他值(除了一些特殊情況如sha3(‘ ’) ),舉例如下:
》》》 compress(‘horse’)
‘horse’
》》》 compress(‘donkey dragon 1231231243’)
‘donkey dragon 1231231243’
》》》 compress(‘\xf8\xaf\xf8\xab\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbe{b\xd5\xcd\x8d\x87\x97’)
‘\xf8\xaf\xf8\xab\xa0\xfe\x9e\xbe{b\xd5\xcd\x8d\x87\x97’
》》》 compress(“\xc5\xd2F\x01\x86\xf7#《\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82‘;{\xfa\xd8\x04]\x85\xa4p”)
‘\xfe\x01’
壓縮算法存在之前,以太坊協(xié)議的許多地方都有一些特殊情況,例如,sha3經(jīng)常被覆蓋,所以sha3(‘ ’)=‘ ’,這樣不需要在賬戶中存儲(chǔ)代碼,可以節(jié)省64字節(jié)。然而,最近所有這些使得以太坊數(shù)據(jù)結(jié)構(gòu)變得臃腫的特殊情況都被刪除了,取而代之的是將數(shù)據(jù)保存函數(shù)添加到區(qū)塊鏈協(xié)議之外的層,也就是將其放入線路協(xié)議以及將其插入用戶數(shù)據(jù)庫(kù)實(shí)現(xiàn)。這樣增加了模塊化能力,簡(jiǎn)化了共識(shí)層,使得壓縮算法能持續(xù)更新以便相對(duì)容易部署。
樹(shù)(trie)的使用
以太坊區(qū)塊鏈中每個(gè)區(qū)塊頭都包含指向三個(gè)樹(shù)的指針:狀態(tài)樹(shù)、交易樹(shù)、收據(jù)樹(shù)。
狀態(tài)樹(shù)代表訪問(wèn)區(qū)塊后的整個(gè)狀態(tài);
交易樹(shù)代表區(qū)塊中所有交易,這些交易由index索引作為key;(例如,k0:第一個(gè)執(zhí)行的交易,k1:第二個(gè)執(zhí)行的交易)
收據(jù)樹(shù)代表每筆交易相應(yīng)的收據(jù)。交易的收據(jù)是一個(gè)RLP編碼的數(shù)據(jù)結(jié)構(gòu):
[ medstate, gas_used, logbloom, logs ]
其中:
? medstate:交易處理后,樹(shù)的根的狀態(tài);
? gas_used:交易處理后,gas的使用量;
? logs:是表格[address, [topic1, topic2.。.], data]元素的列表。表格由交易執(zhí)行期間調(diào)用的操作碼LOG0 。.. LOG4 生成(包含主調(diào)用和子調(diào)用);address 是生成日志的合約的地址topics是最多4個(gè)32字節(jié)的值;data 是任意字節(jié)大小的數(shù)組;
? logbloom:交易中所有l(wèi)ogs的address和topic組成的布隆過(guò)濾器⑤。
區(qū)塊頭中也存在一個(gè)布隆過(guò)濾器,它是區(qū)塊中交易的所有布隆過(guò)濾器的邏輯或組成。這樣的構(gòu)造使得以太坊協(xié)議輕客戶端的使用盡可能的友好。
Uncle塊(過(guò)時(shí)區(qū)塊)的獎(jiǎng)勵(lì)
2013年10月,由喬森納和特拉維夫首次提出的GHOST協(xié)議是一項(xiàng)不起的革新。它是加快生成區(qū)塊時(shí)間的第一個(gè)認(rèn)真嘗試。因?yàn)閰^(qū)塊在網(wǎng)絡(luò)中傳播需要一定時(shí)間,如果礦工A挖到一個(gè)區(qū)塊并向全網(wǎng)廣播,在廣播的路上,B也挖出了區(qū)塊,那么B的區(qū)塊是過(guò)時(shí)的,且B的本次挖礦對(duì)網(wǎng)絡(luò)的安全沒(méi)有貢獻(xiàn)。GHOST的目的正是要解決挖礦過(guò)時(shí)造成的安全性降低的問(wèn)題。
此外,還有一個(gè)中心化問(wèn)題:如果A是一個(gè)礦池,有30%的算力,B有10%的算力。A有70%的時(shí)間產(chǎn)生過(guò)時(shí)的區(qū)塊(因?yàn)榱硗獾?0%時(shí)間會(huì)產(chǎn)生最新區(qū)塊,所以它會(huì)立即挖到數(shù)據(jù)),而B(niǎo)有90%的時(shí)間產(chǎn)生過(guò)時(shí)區(qū)塊。如果區(qū)塊的產(chǎn)出時(shí)間間隔很短,那么過(guò)時(shí)率就會(huì)變高,則A憑借其更大的算力使挖礦效率也更高。所以,區(qū)塊生成過(guò)快,容易導(dǎo)致網(wǎng)絡(luò)算力大的礦池控制挖礦過(guò)程。
根據(jù)喬森納和特拉維夫的描述,GHOST解決了在計(jì)算哪個(gè)鏈?zhǔn)亲铋L(zhǎng)的鏈的過(guò)程中,因產(chǎn)生過(guò)時(shí)區(qū)塊而造成的網(wǎng)絡(luò)安全性下降的問(wèn)題。也就是說(shuō),不僅是父區(qū)塊和更早的區(qū)塊,同時(shí)Uncle區(qū)塊⑥也被添加到計(jì)算哪個(gè)塊具有最大的工作量證明中去。
為了解決第二個(gè)問(wèn)題:中心化問(wèn)題,我們采用不同的策略:對(duì)過(guò)時(shí)區(qū)塊也提供區(qū)塊獎(jiǎng)勵(lì):挖到過(guò)時(shí)區(qū)塊的獎(jiǎng)勵(lì)是該區(qū)塊基礎(chǔ)獎(jiǎng)勵(lì)的7/8;挖到包含過(guò)時(shí)區(qū)塊的nephew區(qū)塊將收到1/32的基礎(chǔ)獎(jiǎng)勵(lì)作為賞金。但是,交易費(fèi)并不獎(jiǎng)勵(lì)給Uncle區(qū)塊或nephew區(qū)塊。
在以太坊,過(guò)時(shí)分叉上7代內(nèi)的親屬區(qū)塊才能稱作過(guò)時(shí)區(qū)塊。之所以這樣限制是因?yàn)椋紫龋珿HOST協(xié)議若不限制過(guò)時(shí)區(qū)塊數(shù)量,將會(huì)花費(fèi)大量開(kāi)銷在計(jì)算過(guò)時(shí)區(qū)塊的有效性上;其次,無(wú)限制的過(guò)時(shí)區(qū)塊激勵(lì)政策會(huì)讓礦工失去在主鏈上挖礦的熱情;最后,計(jì)算表明,過(guò)時(shí)區(qū)塊獎(jiǎng)勵(lì)政策限制在7層內(nèi)提供了大部分所需的效果,而且不會(huì)帶來(lái)負(fù)面效應(yīng)。
區(qū)塊時(shí)間算法的設(shè)計(jì)決策包括:
? 區(qū)塊時(shí)間12s:選擇12s是因?yàn)檫@已經(jīng)是最快的時(shí)間了,基本上比網(wǎng)絡(luò)延遲更長(zhǎng)。在2013年的一份關(guān)于測(cè)量比特幣網(wǎng)絡(luò)延遲的論文中,確定了12.6秒是新產(chǎn)生的區(qū)塊傳播到95%節(jié)點(diǎn)的時(shí)間;然而,該論文還指出傳播時(shí)間與區(qū)塊大小成比例,因此在更快的貨幣中,我們可以期待傳播時(shí)間大大減少。傳播間隔時(shí)間是恒定的,約為2秒。然而,為了安全起見(jiàn),在我們的分析中,我們假定區(qū)塊的傳播需要12秒。
? 7個(gè)祖先塊的限制:這樣設(shè)計(jì)的目的是希望只保留少量區(qū)塊,而將更早之前的區(qū)塊清除。已經(jīng)證明7個(gè)區(qū)塊可以提供大部分所需的效果。
? 1個(gè)后裔區(qū)塊的限制:如c(c(p(p(p(head))))) c=child, p = parent,就不合法,因?yàn)樗袃蓚€(gè)后裔區(qū)塊。這樣設(shè)計(jì)的目的是為了簡(jiǎn)單,上面的模擬結(jié)果顯示它并沒(méi)有構(gòu)成大的中心化風(fēng)險(xiǎn)。
? **uncle塊要求具有有效性: **uncle塊必須是有效的header,而不是有效的區(qū)塊。這樣做也是為了簡(jiǎn)化,將區(qū)塊鏈模型保持為線性數(shù)據(jù)結(jié)構(gòu)。不過(guò),要求uncle塊是有效的區(qū)塊也是合法的方法。
? 獎(jiǎng)金分配:7/8的挖礦基礎(chǔ)獎(jiǎng)勵(lì)分配給uncle塊,1/32分給nephew塊,它們交易費(fèi)用都是0%。如果費(fèi)用占多數(shù),從中心化的角度看,這會(huì)使uncle塊激勵(lì)機(jī)制無(wú)效;然而,這也是為什么只要我們繼續(xù)使用PoW,以太坊就會(huì)不斷發(fā)行以太幣的原因。
難度更新算法
目前以太坊通過(guò)以下規(guī)則進(jìn)行難度更新:
diff(genesis) = 2^32
diff(block) = diff.block.parent + floor(diff.block.parent / 1024) *
1 if block.timestamp - block.parent.timestamp 《 9 else
-1 if block.timestamp - block.parent.timestamp 》= 9
難度更新規(guī)則的設(shè)計(jì)目標(biāo)如下:
? 快速更新:區(qū)塊間的時(shí)間應(yīng)該隨著hash算力的增減而快速調(diào)整;
? 低波動(dòng)性:如果Hash算力恒定,那么難度不應(yīng)劇烈波動(dòng);
? 簡(jiǎn)單:算法的實(shí)現(xiàn)應(yīng)相對(duì)簡(jiǎn)單;
? 低內(nèi)存:算法不應(yīng)依賴于過(guò)多的歷史區(qū)塊,要盡可能少的使用”內(nèi)存變量“。假設(shè)有最新的十個(gè)區(qū)塊,將存儲(chǔ)在這十個(gè)區(qū)塊頭部的內(nèi)存變量相加,這些區(qū)塊都可用于算法的計(jì)算;
? 非開(kāi)發(fā)性:算法不應(yīng)讓礦工有過(guò)多篡改時(shí)間戳或者礦池、反復(fù)添加或刪除算力的能力,以使他們的收益最大化。
我們當(dāng)前的算法在低波動(dòng)性和非開(kāi)發(fā)性上并不理想,至少我們計(jì)劃切換時(shí)間戳比較父區(qū)塊和祖父區(qū)塊,所以礦工只有在連續(xù)挖2個(gè)區(qū)塊時(shí),才有動(dòng)力去修改時(shí)間戳。另一個(gè)更強(qiáng)大的模擬公式: https://github.com/ethereum/economic-modeling/blob/master/diffadjust/blkdiff.py
Gas和費(fèi)用
比特幣中所有交易大體相同,因此它們的網(wǎng)絡(luò)成本可以建成一個(gè)模型。以太坊中的交易要更復(fù)雜,所以交易費(fèi)用需要考慮到賬戶的許多方面,包括寬帶費(fèi)用,存儲(chǔ)費(fèi)用和計(jì)算費(fèi)用。尤其重要的是,以太坊編程語(yǔ)言是圖靈完備的,所以交易會(huì)使用任意數(shù)量的寬帶、存儲(chǔ)和計(jì)算成本。這就可能會(huì)導(dǎo)致在計(jì)算成本過(guò)程中,突遭停電而計(jì)算被迫中止。
以太坊交易費(fèi)用的基本機(jī)制如下:
? 每筆交易必須指明一定數(shù)量的gas(即指定startgas的值),以及支付每單元gas所需費(fèi)用(即gasprice),在交易執(zhí)行開(kāi)始時(shí),startgas * gasprice 價(jià)值的以太幣會(huì)從發(fā)送者賬戶中扣除;
? 交易執(zhí)行期間的所有操作,包括讀寫(xiě)數(shù)據(jù)庫(kù)、發(fā)送消息以及每一步的計(jì)算都會(huì)消耗一定數(shù)量的gas;
? 如果交易執(zhí)行完畢,消耗的gas值小于指定的限制值,則交易執(zhí)行正常,并將剩余的gas值賦予變量gas_rem ; 在交易完成后,發(fā)送者會(huì)收到返回的gas_rem * gasprice 價(jià)值的以太幣,而給礦工的獎(jiǎng)勵(lì)是(startgas - gas_rem)* gasprice價(jià)值的以太幣;
? 如果交易執(zhí)行中,gas消耗殆盡,則所有的執(zhí)行恢復(fù)原樣,但交易仍然有效,只是交易的唯一結(jié)果是將 startgas * gasprice 價(jià)值的以太幣支付給礦工,其他不變;
? 當(dāng)一個(gè)合約發(fā)送消息給另一個(gè)合約,可以對(duì)這個(gè)消息引起的子執(zhí)行設(shè)置一個(gè)gas限制。如果子執(zhí)行耗盡了gas,則子執(zhí)行恢復(fù)原樣,但gas仍然消耗。
上述提到的幾點(diǎn)都是必須滿足的,例如:
? 如果交易沒(méi)有指定gas限制,那么惡意用戶就會(huì)發(fā)送一個(gè)有數(shù)十億步循環(huán)的交易。沒(méi)有人能夠處理這樣的交易,因?yàn)樘幚磉@樣的交易花的時(shí)間可能很長(zhǎng)很長(zhǎng),從而無(wú)法預(yù)先告知網(wǎng)絡(luò)上的礦工,這會(huì)導(dǎo)致拒絕服務(wù)的漏洞產(chǎn)生。
? 替代嚴(yán)格的gas計(jì)數(shù)、時(shí)間限制等機(jī)制的方案不起作用,因?yàn)樗鼈兲饔^了
? startgas * gasprice 的整個(gè)值,在開(kāi)始時(shí)就應(yīng)該設(shè)置好,這樣不至于在交易執(zhí)行中因gas不夠而造成交易終止。注意,僅僅檢查賬戶余額是不夠的,因?yàn)橘~戶可以在其他地方發(fā)送余額。
? 如果在gas不夠的情況下,交易執(zhí)行沒(méi)有恢復(fù)操作(回滾),合約必須采用強(qiáng)有力的安全措施來(lái)防止合約發(fā)生變化。
? 如果子限制不存在,則惡意賬戶會(huì)通過(guò)與其他賬戶達(dá)成協(xié)議來(lái)對(duì)它們采取拒絕服務(wù)攻擊。在計(jì)算開(kāi)始時(shí)插入一個(gè)大循環(huán),那么發(fā)送消息給受害合約或者受害合約的任何補(bǔ)救嘗試,都會(huì)使整個(gè)交易死鎖。
? 要求交易發(fā)送者而不是合約來(lái)支付gas,這樣大大增加了開(kāi)發(fā)人員的可操作性。以太坊早期的版本是由合約來(lái)支付gas的,這導(dǎo)致了一個(gè)相當(dāng)嚴(yán)重的問(wèn)題:每個(gè)合約必須實(shí)現(xiàn)“守護(hù)”代碼,確保每個(gè)傳入的消息有足夠的以太幣供其消耗。
gas消耗計(jì)算有以下特點(diǎn):
? 對(duì)于任何交易,都將收取21000gas的基本費(fèi)用。這些費(fèi)用可用于支付運(yùn)行橢圓曲線算法所需的費(fèi)用。該算法旨在從簽名中恢復(fù)發(fā)送者的地址以及存儲(chǔ)交易所花費(fèi)的硬盤(pán)和帶寬空間。
? 交易可以包括無(wú)限量的“數(shù)據(jù)”。虛擬機(jī)中的某些操作碼,可以讓合約允許交易對(duì)這些數(shù)據(jù)的訪問(wèn)。數(shù)據(jù)的固定消耗計(jì)算是:每個(gè)零字節(jié)4gas,非零字節(jié)68gas。這個(gè)公式的產(chǎn)生是因?yàn)楹霞s中大部分的交易數(shù)據(jù)由一些列的32字節(jié)的參數(shù)組成,其中多數(shù)參數(shù)具有許多前導(dǎo)零字節(jié)。該結(jié)構(gòu)看起來(lái)似乎效率不高,但由于壓縮算法的存在,實(shí)際上還是很有效率的。我們希望此結(jié)構(gòu)能夠代替其他更復(fù)雜的機(jī)制:這些機(jī)制根據(jù)預(yù)期字節(jié)數(shù)嚴(yán)格包裝參數(shù),從而導(dǎo)致編譯階段復(fù)雜性大增。這是三明治復(fù)雜模型的一個(gè)例外,但由于成本效益比,這也是合理的模型。
? 用于設(shè)置賬戶存儲(chǔ)器的操作碼SSTORE的消耗是:1.將零值改為非零值時(shí),消耗20000gas;2.將零值變成零值,或非零值變非零值,消耗5000gas;3.將非零值變成零值,消耗5000gas,加上交易執(zhí)行成功后退回的20000gas。退款金額上限是交易消耗gas總額的50%。這樣設(shè)置會(huì)激勵(lì)人們清除存儲(chǔ)器。我們注意到,正因?yàn)槿狈@樣的激勵(lì),許多合約造成了存儲(chǔ)空間沒(méi)有被有效使用,從而導(dǎo)致了存儲(chǔ)快速膨脹;為存儲(chǔ)收取費(fèi)用提供了很多好處,同時(shí)不會(huì)失去合約一旦確立就可以永久存在的保證。延遲退款機(jī)制是必要的,因?yàn)榭梢宰柚咕芙^服務(wù)攻擊。攻擊者發(fā)送一筆含有少量gas的交易,循環(huán)清除大量的存儲(chǔ),直到用光gas,這樣消耗了大量的驗(yàn)證算力,但實(shí)際并沒(méi)有真正清除存儲(chǔ)或消耗大量gas。50%的上限的是為了確保獲得了一定交易gas的曠工依然能夠確定執(zhí)行交易的計(jì)算時(shí)間的上限。
? 合約提供的消息的數(shù)據(jù)是沒(méi)有成本的。因?yàn)樵谙⒄{(diào)用期間不需要實(shí)質(zhì)復(fù)制任何數(shù)據(jù),調(diào)用數(shù)據(jù)可以簡(jiǎn)單地視為指向父合約內(nèi)存的指針,該指針在子進(jìn)程執(zhí)行時(shí)不會(huì)改變。
? 內(nèi)存是一個(gè)可以無(wú)限擴(kuò)展的數(shù)組,然而,每擴(kuò)展32字節(jié)的內(nèi)存就會(huì)消耗1gas的成本,不足32字節(jié)以32字節(jié)計(jì)。
? 某些操作碼的計(jì)算時(shí)間極度依賴參數(shù),gas開(kāi)銷計(jì)算是動(dòng)態(tài)變化的。例如,EXP的的開(kāi)銷是指數(shù)級(jí)別的;復(fù)制操作碼(如:CALLDATACOPY, CODECOPY, EXTCODECOPY)的開(kāi)銷是1+1(每復(fù)制32字節(jié))。內(nèi)存擴(kuò)展的開(kāi)銷不包含在這里,因?yàn)樗|發(fā)了二次攻擊。
? 如果值不是零,操作碼CALL會(huì)額外消耗9000gas。這是因?yàn)槿魏沃祩鬏敹紩?huì)引起歸檔節(jié)點(diǎn)的歷史存儲(chǔ)顯著增大。請(qǐng)注意,實(shí)際消耗是6700,在此基礎(chǔ)上,我們強(qiáng)制增加了一個(gè)自動(dòng)給予接受者的gas值,這個(gè)值最小2300。這樣做是為了讓接受交易的錢(qián)包至少有足夠的gas來(lái)記錄交易。
gas機(jī)制的另一個(gè)重要部分是gas價(jià)格本身體現(xiàn)出的經(jīng)濟(jì)學(xué)原理。比特幣中,默認(rèn)的方法是采取純粹自愿的收費(fèi)方式,礦工扮演守門(mén)人的角色并且動(dòng)態(tài)設(shè)置收費(fèi)的最小值。以太坊中允許交易發(fā)送者設(shè)置任意數(shù)目的gas。這種方式在比特幣社區(qū)非常受歡迎,因?yàn)樗恰笆袌?chǎng)經(jīng)濟(jì)”的體現(xiàn):允許礦工和交易者之間依據(jù)供需關(guān)系來(lái)決定價(jià)格。然而,這種方式的問(wèn)題是,交易處理并不遵循市場(chǎng)原則。盡管可以將交易處理看作是礦工向發(fā)送者提供的服務(wù)(這聽(tīng)起來(lái)很直觀),但實(shí)際上礦工所處理的每個(gè)交易都必須由網(wǎng)絡(luò)中的每個(gè)節(jié)點(diǎn)處理,所以交易處理的大部分成本都由第三方機(jī)構(gòu)承擔(dān),而不是決定是否處理它的礦工。
當(dāng)前,因?yàn)槿狈ΦV工在實(shí)際中的行為的明確信息,所以我們將采取一個(gè)非常簡(jiǎn)單公平的方法:投票系統(tǒng),來(lái)設(shè)定gas限定值。礦工有權(quán)將當(dāng)前區(qū)塊的gas限定值設(shè)定在最后區(qū)塊的gas限定值的0.0975% (1/1024)內(nèi)。所以最終的gas限定值應(yīng)該是礦工們?cè)O(shè)置的中間值。我們希望將來(lái)能夠采用軟分叉的方法來(lái)使用更加精確的算法。
虛擬機(jī)
以太坊虛擬機(jī)是執(zhí)行交易代碼的引擎,也是以太坊與其他系統(tǒng)的核心區(qū)別。請(qǐng)注意,虛擬機(jī)應(yīng)該同“合約與消息模型”分開(kāi)考慮。例如,SIGNEXTEND操作碼是虛擬機(jī)的一個(gè)功能,但實(shí)際上“某個(gè)合約調(diào)用其他合約并指定子調(diào)用的gas限定值”是“合約與消息模型”的一部分。 EVM的設(shè)計(jì)目標(biāo)如下:
? 簡(jiǎn)單:操作碼盡可能的少并且低級(jí);數(shù)據(jù)類型盡可能少;虛擬機(jī)的結(jié)構(gòu)盡可能少;
? 結(jié)果明確:在VM規(guī)范語(yǔ)句中,沒(méi)有任何可能產(chǎn)生歧義的空間,結(jié)果應(yīng)該是完全確定的。此外,計(jì)算步驟應(yīng)該是精確的,以便可以測(cè)量gas的消耗量;
? 節(jié)約空間:EVM組件應(yīng)盡可能緊湊;
? 預(yù)期應(yīng)用應(yīng)具備專業(yè)化能力:在VM上構(gòu)建的應(yīng)用應(yīng)能處理20字節(jié)的地址,以及32位的自定義加密值,擁有用于自定義加密的模數(shù)運(yùn)算、讀取區(qū)塊和交易數(shù)據(jù)與狀態(tài)交互等能力;
? 簡(jiǎn)單安全:為了讓VM不被利用,應(yīng)該能夠容易地讓建立一套gas消耗成本模型的操作;
? 優(yōu)化友好:應(yīng)該易于優(yōu)化,以便即時(shí)編譯(JIT)和VM的加速版本能夠構(gòu)建出來(lái)。
同時(shí)EVM也有如下特殊設(shè)計(jì):
? 臨時(shí)/永久存儲(chǔ)的區(qū)別:
我們先來(lái)看看什么是臨時(shí)存儲(chǔ)和永久存儲(chǔ)。
臨時(shí)存儲(chǔ):存在于VM的每個(gè)實(shí)例中,并在VM執(zhí)行結(jié)束后消失;
永久存儲(chǔ):存在于區(qū)塊鏈狀態(tài)層。
假設(shè)執(zhí)行下面的樹(shù)(S代表永久存儲(chǔ),M代表臨時(shí)存儲(chǔ)):
1.A調(diào)用B;
2.B設(shè)置B.S[0]=5,B.M[0]=9 ;
3.B調(diào)用C;
4.C調(diào)用B。
此時(shí),如果B試圖讀取B.S[0],它將得到B前面存入的數(shù)據(jù),也就是5;但如果B試圖讀取B.M[0],它將得到0,因?yàn)锽.M是臨時(shí)存儲(chǔ),讀取它的時(shí)候是虛擬機(jī)的一個(gè)新的實(shí)例。
在一個(gè)內(nèi)部調(diào)用中,如果設(shè)置B.M[0] = 13和 B.S[0] = 17 ,然后內(nèi)部調(diào)用和C的調(diào)用都終止,再執(zhí)行B的外部調(diào)用,此時(shí)讀取M,將會(huì)看到B.M[0] = 9(此值在上一次同一VM執(zhí)行實(shí)例中設(shè)置的),B.S[0] = 17。如果B的外部調(diào)用結(jié)束,然后A再次調(diào)用B,將看到B.M[0] = 0,B.S[0] = 17。這個(gè)區(qū)別的目的是:1.每個(gè)執(zhí)行實(shí)例都分配有內(nèi)存空間,不會(huì)因?yàn)檠h(huán)調(diào)用而減損,這讓安全編程更加容易。2.提供一個(gè)能夠快速操作的內(nèi)存形式:因?yàn)樾枰薷臉?shù),所以存儲(chǔ)更新必然很慢。
? 棧/內(nèi)存模式
早期,計(jì)算狀態(tài)有三種:棧(stack,一個(gè)32字節(jié)標(biāo)準(zhǔn)的LIFO),內(nèi)存(memory,可無(wú)限擴(kuò)展的臨時(shí)字節(jié)數(shù)組),存儲(chǔ)(storage,永久存儲(chǔ))。在臨時(shí)存儲(chǔ)端,棧和內(nèi)存的替代方案是memory-only范式,或者是寄存器和內(nèi)存的混合體(兩者區(qū)別不大,寄存器本質(zhì)上也是一種內(nèi)存)。在這種情況下,每個(gè)指令都有三個(gè)參數(shù),例如:ADD R1 R2 R3: M[R1] = M[R2] + M[R3] 。選擇棧范式的原因很明顯,它使代碼縮小了4倍。
? 單詞大小32字節(jié)
在大多數(shù)結(jié)構(gòu)中,如比特幣,單詞大小是4或8字節(jié)。4或8字節(jié)對(duì)存儲(chǔ)地址或加密計(jì)算來(lái)說(shuō)局限性太大了。而太大的值又很難建立相應(yīng)安全的gas模型。32字節(jié)是一個(gè)理想大小,因?yàn)樗銐虼鎯?chǔ)下許多加密算法的實(shí)現(xiàn)以及地址,又不會(huì)因?yàn)樘蠖鴮?dǎo)致效率低下。
? 我們有自己的虛擬機(jī)
我們的虛擬機(jī)使用java、Lisp或Lua等語(yǔ)言開(kāi)發(fā)。我們認(rèn)為開(kāi)發(fā)一款專業(yè)的虛擬機(jī)是值得的,因?yàn)椋?/p>
1. 我們的VM規(guī)范比其他許多虛擬機(jī)簡(jiǎn)單的多,因?yàn)槠渌摂M機(jī)為復(fù)雜性付出的代價(jià)更小,也就是說(shuō)它們更容易變得復(fù)雜;然而,在我們的方案中每額外增加一點(diǎn)復(fù)雜性,都會(huì)給集約化發(fā)展帶來(lái)障礙,以及潛在的安全缺陷,比如造成共識(shí)失敗,這就讓我們的復(fù)雜性成本很高,因而不容易造成復(fù)雜;
2. 我們的VM更加專業(yè)化,如支持32字節(jié);
3. 我們不會(huì)有復(fù)雜的外部依賴,復(fù)雜的外部依賴會(huì)導(dǎo)致我們安裝失敗;
4. 完善的審查機(jī)制,可以具體到特殊的安全需求;對(duì)外部VM而言,這一點(diǎn)無(wú)論如何都是必要的。
? 使用了可變、可擴(kuò)展的內(nèi)存大小
固定內(nèi)存的大小是不必要的限制,太小或太大都不合適。如果內(nèi)存大小是固定的,每次訪問(wèn)內(nèi)存都需要檢查訪問(wèn)是否超出邊界,顯然這樣的效率并不高。
? 棧大小沒(méi)有限制
沒(méi)什么特別理由!許多情況下,該設(shè)計(jì)不是絕對(duì)必要的;因?yàn)椋琯as的開(kāi)銷和區(qū)塊層gas的限制總是會(huì)充當(dāng)每種資源消耗的上限。
? 1024調(diào)用深度限制
許多編程語(yǔ)言在棧的深度過(guò)大時(shí)觸發(fā)中斷比在內(nèi)存過(guò)載時(shí)觸發(fā)中斷的策略要快的多。所以區(qū)塊中g(shù)as限制所隱含的限制是不夠的。
? 無(wú)類型
為了簡(jiǎn)單起見(jiàn),可以使用DIV, SDIV, MOD, SMOD的有符號(hào)或無(wú)符號(hào)的操作碼代替(事實(shí)證明,對(duì)于操作碼ADD和MUL,有符號(hào)和無(wú)符號(hào)是對(duì)等的);轉(zhuǎn)換成定點(diǎn)運(yùn)算在所有情況下都很簡(jiǎn)單,例如,在32位深度下,a * b -》 (a * b) / 2^32, a / b -》 a * 2^32 / b ,+, - 和 * 在整數(shù)下不變。
VM中某些操作碼的函數(shù)和作用很容易理解,但也有一些不太好理解,以下是一些特殊的原因:
*? ADDMOD, MULMOD *
大多數(shù)情況下,addmod(a, b, c) = a * b % c,但在橢圓曲線算法中,使用的是32字節(jié)模數(shù)運(yùn)算,直接執(zhí)行a * b % c 實(shí)際上是在執(zhí)行((a * b) % 2^256) % c會(huì)得到完全不同的結(jié)果。計(jì)算公式a * b % c 使用32字節(jié)空間的32字節(jié)值是非常不常見(jiàn)且繁瑣。
? SIGNEXTEND
SIGNEXTEND操作碼的作用是為了方便從大的有符號(hào)整數(shù)到小的有符號(hào)整數(shù)的類型轉(zhuǎn)換。小的有符號(hào)整數(shù)是很有用的,因?yàn)槲磥?lái)的即時(shí)編譯虛擬機(jī)可能會(huì)檢測(cè)長(zhǎng)時(shí)間運(yùn)行的代碼塊,小的有符號(hào)整數(shù)能加快處理。
? SHA3
在以太坊代碼中SHA3作為安全的高強(qiáng)度的hash集合應(yīng)用非常廣泛,通常在使用存儲(chǔ)器時(shí)需要使用Hash函數(shù)來(lái)確保安全,以防止惡意沖突,在驗(yàn)證默克爾樹(shù)和類似以太坊的數(shù)據(jù)結(jié)構(gòu)時(shí)也需要使用到Hash函數(shù)。重要的是,與SHA3的相似的hash函數(shù),如SHA256,ECRECVOR,RIPEM160不是以操作碼的形式包含在里面,而是以偽合約的形式。這樣做的目的是將它們放在一個(gè)單獨(dú)的類別中,如果當(dāng)我們以后提出適當(dāng)?shù)摹氨镜財(cái)U(kuò)展”系統(tǒng)時(shí),可以添加更多這樣的合約,而不需要擴(kuò)展操作碼。
? ORIGIN
ORIGIN操作碼由交易的發(fā)送者提供,主要的作用是允許合約退回支付的gas。
? COINBASE
COINBASE的主要作用是:1.如果使用COINBASE操作碼,則允許子貨幣對(duì)網(wǎng)絡(luò)安全作出貢獻(xiàn);2.開(kāi)放使用礦工作為一個(gè)去中心化的經(jīng)濟(jì)體,來(lái)設(shè)置基于子共識(shí)的應(yīng)用,如Schellingcoin。
? PREVHASH
PREVHASH作為一個(gè)半安全的隨機(jī)來(lái)源,允許合約評(píng)估上一個(gè)區(qū)塊的默克爾樹(shù)狀態(tài)證明,而不需要高度復(fù)雜的遞歸結(jié)構(gòu)“以太坊輕客戶端”。
? EXTCODESIZE, EXTCODECOPY
主要的作用是讓合約依據(jù)模板檢查其他合約的代碼,甚至是在與其他合約交互前,模擬它們。
? JUMPDEST
當(dāng)跳轉(zhuǎn)(jump)目的地限制在幾個(gè)索引時(shí)(尤其是,動(dòng)態(tài)目的跳轉(zhuǎn)的計(jì)算復(fù)雜度是O(log(有效挑戰(zhàn)目的數(shù)量)),而靜態(tài)跳轉(zhuǎn)總是恒定的),JIT虛擬機(jī)實(shí)現(xiàn)起來(lái)更簡(jiǎn)單。于是,我們需要:1.對(duì)有效變量跳轉(zhuǎn)目的地做限制;2.使用靜態(tài)而不是動(dòng)態(tài)跳轉(zhuǎn)的激勵(lì)方式。為了達(dá)到這兩個(gè)目標(biāo),我們定下了以下規(guī)則:1.緊接著push后的跳轉(zhuǎn)可以跳到任何地方,而不僅是另一個(gè)jump;2.其他的jump只能跳轉(zhuǎn)到JUMPDEST。對(duì)跳轉(zhuǎn)的限制是必須的,你可以通過(guò)查看代碼中的先前操作來(lái)決定是靜態(tài)還是動(dòng)態(tài)的跳轉(zhuǎn)。缺乏對(duì)靜態(tài)跳轉(zhuǎn)的需求是激勵(lì)使用它們的原因。禁止跳轉(zhuǎn)進(jìn)入push數(shù)據(jù)也會(huì)加快JIT虛擬機(jī)的編譯和執(zhí)行。
*? LOG *
LOG是事件的日志。
? CALLCODE
該操作碼允許合約使用自己的存儲(chǔ)器,在單獨(dú)的棧空間和內(nèi)存中調(diào)用其他合約的“函數(shù)”。這樣可以在區(qū)塊鏈上靈活實(shí)現(xiàn)標(biāo)準(zhǔn)庫(kù)代碼。
? SELFDESTRUCT
允許合約刪除它自己,前提是它已經(jīng)不需要存在了。SELFDESTRUCT并非立即執(zhí)行,而是在交易執(zhí)行完之后執(zhí)行。這是因?yàn)檫@樣做可以恢復(fù)那些執(zhí)行后大大增加了緩存復(fù)雜度的SELFDESTRUCT操作碼。
? PC
盡管理論上不需要PC操作碼,因?yàn)樗械腜C操作碼都可以根據(jù)將push操作的索引加入實(shí)際程序計(jì)數(shù)器來(lái)代替實(shí)現(xiàn),但使用PC可以創(chuàng)建獨(dú)立代碼的位置(可復(fù)制粘貼到其他合約的編譯函數(shù),如果它們以不同索引結(jié)束,不要打斷)。
注釋:
① UTXO: unspent transaction outputs。字面理解是:有效的交易輸出,它是比特幣協(xié)議中用于存儲(chǔ)交易信息的數(shù)據(jù)結(jié)構(gòu)。
② Nonce,Number used once或Number once的縮寫(xiě),在密碼學(xué)中Nonce是一個(gè)只被使用一次的任意或非重復(fù)的隨機(jī)數(shù)值,在加密技術(shù)中的初始向量和加密散列函數(shù)都發(fā)揮著重要作用,在各類驗(yàn)證協(xié)議的通信應(yīng)用中確保驗(yàn)證信息不被重復(fù)使用以對(duì)抗重放攻擊(Replay Attack)。
③ 嵌套數(shù)組:創(chuàng)建一個(gè)數(shù)組,并使用其他數(shù)組填充該數(shù)組。如數(shù)組pets:
var cats : String[] = [“Cat”,“Beansprout”, “Pumpkin”, “Max”];
var dogs : String[] = [“Dog”,“Oly”,“Sib”];
var pets : String[][] = [cats, dogs];
④ 行程編碼(run-length-encoding):一種統(tǒng)計(jì)編碼。主要技術(shù)是檢測(cè)重復(fù)的比特或字符序列,并用它們的出現(xiàn)次數(shù)取而代之。(百度百科)
⑤ 布隆過(guò)濾器:由 Howard Bloom 在 1970 年提出的二進(jìn)制向量數(shù)據(jù)結(jié)構(gòu),它具有很好的空間和時(shí)間效率,被用來(lái)檢測(cè)一個(gè)元素是不是集合中的一個(gè)成員。(百度百科)
⑥ uncle:A挖出區(qū)塊后廣播途中,B也挖出了區(qū)塊(過(guò)時(shí)區(qū)塊),此時(shí)區(qū)塊鏈會(huì)出現(xiàn)分叉。過(guò)時(shí)分叉上的區(qū)塊就叫uncle區(qū)塊。它不是這個(gè)塊的父區(qū)塊,父區(qū)塊的兄弟區(qū)塊(平級(jí)關(guān)系)。
評(píng)論