以太坊白皮書
以太坊的目標(biāo)
以太坊的目標(biāo)就是提供一個(gè)帶有內(nèi)置的成熟的
圖靈完備語言
的區(qū)塊鏈,用這種語言可以創(chuàng)建合約來編碼任意狀態(tài)轉(zhuǎn)換功能,用戶只要簡單地用幾行代碼來實(shí)現(xiàn)邏輯,就能夠創(chuàng)建以上提及的所有系統(tǒng)以及許多我們還想象不到的的其它系統(tǒng)。
歷史
因?yàn)樨泿攀且粋€(gè)先申請應(yīng)用,交易的順序至關(guān)重要,所以去中心化的貨幣需要找到實(shí)現(xiàn)去中心化共識的方法。
中本聰?shù)膭?chuàng)新是引入這樣一個(gè)理念:將一個(gè)非常簡單的基于節(jié)點(diǎn)的去中心化共識協(xié)議與
工作量證明(POW)機(jī)制
結(jié)合在一起。節(jié)點(diǎn)通過工作量證明機(jī)制獲得參與到系統(tǒng)的權(quán)利,每十分鐘將交易打包到“區(qū)塊”中,從而創(chuàng)建出不斷增長的區(qū)塊鏈。擁有大量算力的節(jié)點(diǎn)有更大的影響力,但獲得比整個(gè)網(wǎng)絡(luò)更多的算力比創(chuàng)建一百萬個(gè)節(jié)點(diǎn)困難得多。盡管比特幣區(qū)塊鏈模型非常簡陋,但是實(shí)踐證明它已經(jīng)足夠好用了,在未來五年,它將成為全世界兩百個(gè)以上的貨幣和協(xié)議的基石。
UTXO :unspent transaction outputs ,未花費(fèi)的交易輸出
在比特幣系統(tǒng)中,狀態(tài)轉(zhuǎn)換函數(shù)
APPLY(S,TX)->S’
大體上可以如下定義:
-
交易的每個(gè)輸入:
-
如果引用的UTXO不存在于現(xiàn)在的狀態(tài)中(
S),返回錯(cuò)誤提示
如果簽名與UTXO所有者的簽名不一致,返回錯(cuò)誤提示
-
如果所有的UTXO輸入面值總額小于所有的UTXO輸出面值總額,返回錯(cuò)誤提示
-
返回新狀態(tài)
S’,新狀態(tài)
S中移除了所有的輸入U(xiǎn)TXO,增加了所有的輸出UTXO。
第一步的第一部分防止交易的發(fā)送者花費(fèi)不存在的比特幣,第二部分防止交易的發(fā)送者花費(fèi)其他人的比特幣。第二步確保價(jià)值守恒。比特幣的支付協(xié)議如下。假設(shè)Alice想給Bob發(fā)送11.7BTC。事實(shí)上,Alice不可能正好有11.7BTC。假設(shè),她能得到的最小數(shù)額比特幣的方式是:6+4+2=12。所以,她可以創(chuàng)建一筆有3個(gè)輸入,2個(gè)輸出的交易。第一個(gè)輸出的面值是11.7BTC,所有者是Bob(Bob的比特幣地址),第二個(gè)輸出的面值是0.3BTC,所有者是Alice自己,也就是找零。
挖礦
[圖片上傳中...(image-690ef9-1512553916325-1)]
比特幣的去中心化共識進(jìn)程要求網(wǎng)絡(luò)中的節(jié)點(diǎn)不斷嘗試將交易打包成“區(qū)塊”。網(wǎng)絡(luò)被設(shè)計(jì)為大約每十分鐘產(chǎn)生一個(gè)區(qū)塊,每個(gè)區(qū)塊包含一個(gè)時(shí)間戳、一個(gè)隨機(jī)數(shù)、一個(gè)對上一個(gè)區(qū)塊的引用(即哈希)和上一區(qū)塊生成以來發(fā)生的所有交易列表。這樣,隨著時(shí)間流逝就創(chuàng)建出了一個(gè)持續(xù)增長的區(qū)塊鏈,它不斷更新,從而代表賬本的最新狀態(tài)。
依照上面的范式, 檢查一個(gè)區(qū)塊是否有效的算法如下:
檢查區(qū)塊引用的上一個(gè)區(qū)塊是否存在且有效
檢查區(qū)塊的時(shí)間戳是否晚于以前的區(qū)塊的時(shí)間戳,而且早于未來2小時(shí)
檢查區(qū)塊的工作量證明是否有效
-
將上一個(gè)區(qū)塊的最終狀態(tài)賦值于
?
-
建設(shè)TX是區(qū)塊的交易列表,包含N筆交易,都滿滿足與狀態(tài)轉(zhuǎn)換:
?
, 如果任一
?
不滿足上面的等式,則拋出一個(gè)error。
-
如果上面 step 5 全部滿足,則
?
為區(qū)塊練得最終狀態(tài)
區(qū)塊鏈中的每一個(gè)區(qū)塊,都是可以從創(chuàng)世塊中通過交易順序按照狀態(tài)轉(zhuǎn)換計(jì)算出當(dāng)前的狀態(tài)的。通俗的說一點(diǎn),就是對于任意區(qū)塊,從創(chuàng)世區(qū)塊開始,加上鏈上的(按照循序)每一筆交易,計(jì)算出當(dāng)前狀態(tài)。假設(shè):現(xiàn)在有A和B兩個(gè)交易,B交易花費(fèi)了A的UTXO, 如果A交易在B交易之前。那么這個(gè)交易就是有效的。否則就是無效的。
工作量證明(挖礦):
對每個(gè)區(qū)塊進(jìn)行SHA256 哈希處理,生成一個(gè)哈希視長為256bit 的哈希值。這個(gè)哈希值必須小于不斷調(diào)整的目標(biāo)數(shù)值。工作量證明的目的是使區(qū)塊的創(chuàng)建變得困難,從而阻止女巫攻擊者惡意重新生成區(qū)塊鏈。因?yàn)镾HA256是完全不可預(yù)測的偽隨機(jī)函數(shù),創(chuàng)建有效區(qū)塊的唯一方法就是簡單地不斷試錯(cuò),不斷地增加隨機(jī)數(shù)的數(shù)值,查看新的哈希數(shù)值是否小于目標(biāo)數(shù)值。如果當(dāng)前的目標(biāo)數(shù)值是
?
那就意味著要嘗試
?
次才能生成有效的區(qū)塊。一般而言,比特幣網(wǎng)絡(luò)每隔2016個(gè)區(qū)塊重新設(shè)定目標(biāo)數(shù)值,保證平均每十分鐘生成一個(gè)區(qū)塊。為了對礦工的計(jì)算工作進(jìn)行獎勵(lì),每一個(gè)成功生成區(qū)塊的礦工有權(quán)在區(qū)塊中包含一筆憑空發(fā)給他們自己25BTC的交易。
另外,如果交易的輸入大于輸出,差額部分就作為“交易費(fèi)用”付給礦工。順便提一下,對礦工的獎勵(lì)是比特幣發(fā)行的唯一機(jī)制,創(chuàng)世狀態(tài)中并沒有比特幣
案例
為了更好地理解挖礦的目的,讓我們分析比特幣網(wǎng)絡(luò)出現(xiàn)惡意攻擊者時(shí)會發(fā)生什么。因?yàn)楸忍貛诺拿艽a學(xué)基礎(chǔ)是非常安全的,所以攻擊者會選擇攻擊沒有被密碼學(xué)直接保護(hù)的部分:交易順序。攻擊者的策略非常簡單:
向賣家發(fā)送100BTC購買商品(尤其是無需郵寄的電子商品)。
等待直至商品發(fā)出。
創(chuàng)建另一筆交易,將相同的100BTC發(fā)送給自己的賬戶。
使比特幣網(wǎng)絡(luò)相信發(fā)送給自己賬戶的交易是最先發(fā)出的。
一旦步驟(1)發(fā)生,幾分鐘后礦工將把這筆交易打包到區(qū)塊,假設(shè)是第270000個(gè)區(qū)塊。大約一個(gè)小時(shí)以后,在此區(qū)塊后面將會有五個(gè)區(qū)塊,每個(gè)區(qū)塊間接地指向這筆交易,從而確認(rèn)這筆交易。這時(shí)賣家收到貨款,并向買家發(fā)貨。因?yàn)槲覀兗僭O(shè)這是數(shù)字商品,攻擊者可以即時(shí)收到貨?,F(xiàn)在,攻擊者創(chuàng)建另一筆交易,將相同的100BTC發(fā)送到自己的賬戶。如果攻擊者只是向全網(wǎng)廣播這一消息,這一筆交易不會被處理。礦工會運(yùn)行狀態(tài)轉(zhuǎn)換函數(shù)
APPLY(S,TX)
,發(fā)現(xiàn)這筆交易將花費(fèi)已經(jīng)不在狀態(tài)中的UTXO。所以,攻擊者會對區(qū)塊鏈進(jìn)行分叉,將第269999個(gè)區(qū)塊作為父區(qū)塊重新生成第270000個(gè)區(qū)塊,在此區(qū)塊中用新的交易取代舊的交易。因?yàn)閰^(qū)塊數(shù)據(jù)是不同的,這要求重新進(jìn)行工作量證明。另外,因?yàn)楣粽呱傻男碌牡?70000個(gè)區(qū)塊有不同的哈希,所以原來的第270001到第270005的區(qū)塊不指向它,因此原有的區(qū)塊鏈和攻擊者的新區(qū)塊是完全分離的。在發(fā)生區(qū)塊鏈分叉時(shí),區(qū)塊鏈長的分支被認(rèn)為是誠實(shí)的區(qū)塊鏈,合法的的礦工將會沿著原有的第270005區(qū)塊后挖礦,只有攻擊者一人在新的第270000區(qū)塊后挖礦。攻擊者為了使得他的區(qū)塊鏈最長,他需要擁有比除了他以外的全網(wǎng)更多的算力來追趕(即51%攻擊)。
默克爾樹
[圖片上傳中...(image-28622d-1512553916325-0)]
默克爾樹在數(shù)據(jù)結(jié)構(gòu)上講是一個(gè)二叉樹,默克爾樹包括根節(jié)點(diǎn)中間節(jié)點(diǎn)和葉子節(jié)點(diǎn)。其中,根節(jié)點(diǎn)和中間節(jié)點(diǎn)每個(gè)節(jié)點(diǎn)的值是兩個(gè)子節(jié)點(diǎn)的Hash值。私用默克爾樹的目的在于區(qū)塊可以零散的傳播,節(jié)點(diǎn)可以從一個(gè)源下載區(qū)塊頭,從另外的源下載與其有關(guān)的樹的其它部分,而依然能夠確認(rèn)所有的數(shù)據(jù)都是正確的。之所以如此是因?yàn)楣O蛏系臄U(kuò)散:如果一個(gè)惡意用戶嘗試在樹的下部加入一個(gè)偽造的交易,所引起的改動將導(dǎo)致樹的上層節(jié)點(diǎn)的改動,以及更上層節(jié)點(diǎn)的改動,最終導(dǎo)致根節(jié)點(diǎn)的改動以及區(qū)塊哈希的改動,這樣協(xié)議就會將其記錄為一個(gè)完全不同的區(qū)塊(幾乎可以肯定是帶著不正確的工作量證明的)。
比特幣存在的缺陷:
缺少圖靈完備性 : 這就是說,盡管比特幣腳本語言可以支持多種計(jì)算,但是它不能支持所有的計(jì)算。最主要的缺失是循環(huán)語句。不支持循環(huán)語句的目的是避免交易確認(rèn)時(shí)出現(xiàn)無限循環(huán)。理論上,對于腳本程序員來說,這是可以克服的障礙,因?yàn)槿魏窝h(huán)都可以用多次重復(fù)if 語句的方式來模擬,但是這樣做會導(dǎo)致腳本空間利用上的低效率,例如,實(shí)施一個(gè)替代的橢圓曲線簽名算法可能將需要256次重復(fù)的乘法,而每次都需要單獨(dú)編碼。
-
價(jià)值盲(Value-blindness)
。UTXO腳本不能為賬戶的取款額度提供精細(xì)的的控制。例如,預(yù)言機(jī)合約(oracle contract)的一個(gè)強(qiáng)大應(yīng)用是對沖合約,A和B各自向?qū)_合約中發(fā)送價(jià)值1000美元的比特幣,30天以后,腳本向A發(fā)送價(jià)值1000美元的比特幣,向B發(fā)送剩余的比特幣。雖然實(shí)現(xiàn)對沖合約需要一個(gè)預(yù)言機(jī)(oracle)決定一比特幣值多少美元,但是與現(xiàn)在完全中心化的解決方案相比,這一機(jī)制已經(jīng)在減少信任和基礎(chǔ)設(shè)施方面有了巨大的進(jìn)步。然而,因?yàn)閁TXO是不可分割的,為實(shí)現(xiàn)此合約,唯一的方法是非常低效地采用許多有不同面值的UTXO(例如對應(yīng)于最大為30的每個(gè)k,有一個(gè)
?
的UTXO)并使預(yù)言機(jī)挑出正確的UTXO發(fā)送給A和B。
-
缺少狀態(tài)
– UTXO只能是已花費(fèi)或者未花費(fèi)狀態(tài),這就沒有給需要任何其它內(nèi)部狀態(tài)的多階段合約或者腳本留出生存空間。這使得實(shí)現(xiàn)多階段期權(quán)合約、去中心化的交換要約或者兩階段加密承諾協(xié)議(對確保計(jì)算獎勵(lì)非常必要)非常困難。這也意味著UTXO只能用于建立簡單的、一次性的合約,而不是例如去中心化組織這樣的有著更加復(fù)雜的狀態(tài)的合約,使得元協(xié)議難以實(shí)現(xiàn)。二元狀態(tài)與價(jià)值盲結(jié)合在一起意味著另一個(gè)重要的應(yīng)用-取款限額-是不可能實(shí)現(xiàn)的。
-
區(qū)塊鏈盲(Blockchain-blindness)
- UTXO看不到區(qū)塊鏈的數(shù)據(jù),例如隨機(jī)數(shù)和上一個(gè)區(qū)塊的哈希。這一缺陷剝奪了腳本語言所擁有的基于隨機(jī)性的潛在價(jià)值,嚴(yán)重地限制了博彩等其它領(lǐng)域應(yīng)用。
以太坊
以太坊賬戶
在以太坊系統(tǒng)中,狀態(tài)是由被稱為“賬戶”(每個(gè)賬戶由一個(gè)20字節(jié)的地址)的對象和在兩個(gè)賬戶之間轉(zhuǎn)移價(jià)值和信息的狀態(tài)轉(zhuǎn)換構(gòu)成的。以太坊的賬戶包含四個(gè)部分:
-
nonce
用來保證每個(gè)交易只被處理一次
賬戶的以太幣余額
賬戶的智能合約,如果有的話
賬戶的存儲,默認(rèn)為空
消息和交易
交易指的即為從外部賬戶過來的包含有消息的數(shù)據(jù)包,一個(gè)“交易”的組成包括
消息的接受者
發(fā)送者的簽名
從發(fā)送者轉(zhuǎn)到接收者的以太幣數(shù)量
其他可選的數(shù)據(jù)列
要發(fā)送的數(shù)據(jù)和兩個(gè)被稱為STARTGAS和GASPRICE的數(shù)值
STARTGAS
: 代表交易執(zhí)行最多被允許的次數(shù)
GASPRICE
: 發(fā)送者到交易者每個(gè)交易執(zhí)行步奏的價(jià)格
對于第4條中的可選數(shù)據(jù)列,智能合約代碼是可以訪問這些數(shù)據(jù)的。舉例來說,如果要在區(qū)塊鏈上進(jìn)行一個(gè)域名注冊服務(wù),數(shù)據(jù)要包含有要注冊的域名和IP兩條數(shù)據(jù)。
對于Gas price 來說,每一個(gè)交易步奏被收費(fèi)1 gas或更高, 傳輸?shù)慕灰讛?shù)據(jù)中每 1 字節(jié)收費(fèi)5gas
以太坊的狀態(tài)轉(zhuǎn)換函數(shù):
APPLY(S,TX) -> S'
,可以定義如下:
檢查交易的格式是否正確(即有正確數(shù)值)、簽名是否有效和隨機(jī)數(shù)是否與發(fā)送者賬戶的隨機(jī)數(shù)匹配。如否,返回錯(cuò)誤。
-
計(jì)算交易費(fèi)用:
fee=STARTGAS * GASPRICE,并從簽名中確定發(fā)送者的地址。從發(fā)送者的賬戶中減去交易費(fèi)用和增加發(fā)送者的隨機(jī)數(shù)。如果賬戶余額不足,返回錯(cuò)誤。
-
設(shè)定初值
GAS = STARTGAS,并根據(jù)交易中的字節(jié)數(shù)減去一定量的瓦斯值。
從發(fā)送者的賬戶轉(zhuǎn)移價(jià)值到接收者賬戶。如果接收賬戶還不存在,創(chuàng)建此賬戶。如果接收賬戶是一個(gè)合約,運(yùn)行合約的代碼,直到代碼運(yùn)行結(jié)束或者瓦斯用完。
如果因?yàn)榘l(fā)送者賬戶沒有足夠的錢或者代碼執(zhí)行耗盡瓦斯導(dǎo)致價(jià)值轉(zhuǎn)移失敗,恢復(fù)原來的狀態(tài),但是還需要支付交易費(fèi)用,交易費(fèi)用加至礦工賬戶。
否則,將所有剩余的瓦斯歸還給發(fā)送者,消耗掉的瓦斯作為交易費(fèi)用發(fā)送給礦工。 例如,假設(shè)合約的代碼如下: