吳夢宇,朱國勝,吳善超
(湖北大學計算機與信息工程學院,武漢430062)
2008 年11 月1 日,一個化名為中本聰的人在網絡上發表了一篇名為《比特幣:一種點對點的電子現金系統》[1]的論文,首次提出了比特幣的概念,并于2009 年1 月3 日創建了第一個創世區塊,獲得了50 枚比特幣的挖礦獎勵,比特幣由此誕生。在比特幣系統中,沒有中心機構,完全開放自治,所有對等的節點組成一個去中心化的分布式賬本,系統內的所有交易信息公開透明,每隔10 min創建一個區塊,并將這10 min內全網的比特幣交易記錄打包并加密[2]存入該區塊中,寫入區塊中的信息不能更改和撤銷,參與競爭的礦工節點需要進行復雜的哈希計算來尋找一個隨機數(Nonce),找到該隨機數的節點獲得打包記賬權,并得到一定數量的比特幣獎勵。這種去中心化、公開透明、不可篡改的底層數據存儲技術稱為區塊鏈[3]。
區塊鏈的誕生引起了社會各界的極大興趣[4],各大區塊鏈平臺應運而生,最為熱門的有以太坊[5]、EOS(Enterprise Operation System)、波場等,不管是哪個區塊鏈平臺,都離不開共識機制,共識機制的作用就是使各節點在沒有中心管理機構的情況下,遵循一定的規則實現自治從而保證區塊鏈的穩定運行。以太坊采用的是工作量證明(Proof of Work,PoW)機制,但由于PoW 需要消耗巨大算力和電力并且效率不高,以太坊正在逐步遷移到其他區塊鏈平臺廣泛采用的權益證明(Proof of Stake,PoS)機制[6],然而PoS 機制由于其無成本權益(nothing-at-stake)的特性,很容易被分叉,并且可能存在富者愈富的問題。
針對PoW 和PoS 共識機制的缺陷,本文提出了一種基于PoW 和PoS 改進的區塊鏈共識機制PoWaS(Proof of Work and Stake):首先降低哈希計算的難度,節點尋找隨機數所花費的時間記為fTime;接著設置最大納入幣齡計算的持幣時間,得到的幣齡記為coinAge;然后引入信用值,節點的信用值記為cPoint;最 后 由fTime、coinAge和cPoint計 算 的 到 的 值 記 為pStake,pStake最大的礦工節點獲得打包記賬權并得到相應的虛擬幣和信用值獎勵。
作為區塊鏈的核心組成部分,共識機制起著保證區塊鏈系統穩定運行的作用,隨著區塊鏈技術的不斷發展,共識機制也成為了當前國內外信息技術領域的一個研究熱點,主流的區塊鏈共識機制主要有PoW、PoS、委托權益證明(Delegated Proof of Stake,DPoS)[7]、實用拜占庭容錯(Practical Byzantine Fault Tolerance,PBFT)[8]以及驗證池(Pool)等。目前對共識機制的研究主要有四個方向:對PoW 的改進、對PoS 的改進、將PoW和PoS相結合以及對分布式一致性算法的改進。
2016 年,英特爾為了改進PoW,提出了消逝時間證明(Proof of Elapsed Time,PoET)[9]機制,該機制下,各參與競爭的節點需要等待一個隨機時間,第一個完成其等待時間的節點獲得記賬權,節點參與競爭的代價較低,擁有較為平等競爭的機會。為了解決PoW 的資源浪費問題,空間證明(Proof of Space,PoSpace)[10]被提出,節點一次性提供一定的硬盤空間,后續的記賬權競爭不需要花費算力,該共識機制目前已經在一些區塊鏈項目中得到應用。2017 年8 月,基于PoS 改進的Ouroboros 共識機制被提出[11],它使用了新的激勵機制,根據權益隨機選出記賬者。行動證明(Proof of Activity,PoA)[12]將PoW 和PoS 相結合,在該機制下礦工節點進行工作量證明后挖出的塊并不包含交易數據,只是區塊頭部,需要將該頭部發送給其他校驗節點進行校驗,校驗者的選取與權益相關,最后一個校驗者將交易數據加入該塊中,完成一個區塊的生成。小蟻共識(delegated BFT,dBFT)對拜占庭容錯機制進行了改進,借鑒PoS 的思想,利用基于權益的投票機制選取參與記賬的節點,將拜占庭容錯機制中的記賬者由靜態參與轉變為動態調整。
PoW 工作量證明機制是比特幣所采用的共識機制[13],礦工節點通過不斷的哈希(hash)計算尋找一個隨機數(Nonce),使得Nonce 拼接上前一個區塊的哈希值再進行哈希計算所得到的哈希值前n位為零,n的大小對應計算難度的大小,在比特幣中,難度值的計算公式為:
其中:newDiff為新區塊的難度值;oldDiff為前一個區塊的難度值;totalTime為創建過去2 016 個區塊所花費的總時長,由于比特幣將出塊速度控制在10 min出一個塊,從式(1)可以看出20 160/totalTime趨近于1,所以新區塊的難度值與前一個區塊的難度值近似相等。如果礦工的算力增強,可能出現不到10 min 就出塊的情況,這樣20 160/totalTime就會大于1,根據式(1),newsDiff將大于oldDiff,難度值變高了,計算時長就會增加;反之,算力減小,難度值會降低,計算時長也會減少。這就是PoW 的難度調整機制,比特幣通過這種機制使得不管在什么算力情況下始終保持10 min左右的出塊速度。
在PoW 機制下,客戶端之間發生交易后,會向全網節點廣播,礦工節點收到交易信息后將其加入到自己創建的區塊中,同時也在不斷地進行哈希計算尋找Nonce,若某個礦工節點找到了Nonce,需要將自己打包的區塊和Nonce 信息向全網節點廣播。其他節點收到消息后,立即驗證Nonce 是否正確以及區塊中的所有交易是否有效,若驗證通過,則認為該區塊有效,然后停止當前的計算,將該區塊作為區塊鏈的最后一個區塊進行新一輪的哈希計算,找到Nonce 的礦工會獲得一定數量的代幣獎勵。
從PoW 的工作流程和其難度調節機制中可以看出,在創建新區塊時,全網礦工節點都處于高負荷的計算中,算力再好的節點找到一個Nonce 也需要10 min 左右的時間,其他沒有找到Nonce 的節點花費了10 min 的算力卻得不到任何獎勵。顯然,產生巨大的算力和電力資源浪費是PoW 機制的重大缺陷。
PoS 權益證明機制在2012 年由Sunny King 在點點幣(Peercoin)白皮書中提出,目的是為了解決比特幣的PoW 機制大量浪費算力、電力資源的問題。Sunny King 希望通過一個可靠的機制來賦予每個節點參與系統中決策的權利,PoS機制中引入了幣齡(coinAge)的概念,每個代幣都有對應的價值來度量持幣者參與決策的權重,叫作權益。幣齡的計算公式為:

其中:coin為代幣數量;coinTime為持幣時間,如果發生交易,這部分幣齡將會被消耗。比如,Bob 從Alice 那里收到了10 個幣,并且持有90 d,那么Bob 就收集到了900 幣天的幣齡。如果Bob使用了從Alice收到的這10個幣,那么Bob從這10個幣上積累的幣齡就被消耗了[14],每消耗一定的幣齡都會產生一定的利息幣。PoS 中是通過權益來獲得記賬權的,權益大的節點獲得記賬權的概率較大。
PoS 機制雖然解決了PoW 大量浪費算力和電力資源的問題,但正因為不需要花費算力,記賬權來源于權益,所以挖礦幾乎是沒有成本的(nothing-at-stake)[15]。一旦惡意節點制造分叉鏈,對于其他節點來說,不管在哪條鏈上挖礦都沒有成本,他們可能會選擇在每一條鏈上都進行挖礦,這樣無論最終哪條鏈被選作主鏈,都會獲得收益。如果大多數的礦工都選擇在所有分叉上挖礦,那么區塊鏈很可能被分叉,并且更容易遭到雙花攻擊,穩定性無法保證。通過幣齡的計算方式可以看出,只要持幣不交易,幣齡是持續增長的,對應的權益也是持續增長的,那么持幣較多的節點可能會選擇大量囤積代幣,一方面持幣吃息,另一方面獲取更大的權益,這樣就會導致某些節點的權益越來越大,帶來富者愈富的問題[16]。
針對PoW 出塊速度慢、交易等待時間長以及算力浪費大等問題,PoWaS作出優化方案:
1)降低哈希計算的難度,減少尋找隨機數所花費的算力。將初始難度設為1,對應難度值為6,即找到的Nonce拼接前一個區塊的hash值再進行哈希計算得到的hash值的前6位為0,這樣礦工節點基本上只花數十秒就能找到Nonce,實驗證明將在3.2節中詳細闡述。工作量證明算法如算法1所示。
算法1 工作量證明算法。
輸入 前一個區塊hash值preHash,難度值n;
輸出 隨機數nonce。
def hash(preHash,nonce):
str = f’{preHash}{nonce}’.encode()
return hashlib.sha256(str).hexdigest()
def proof(preHash,n):
nonce = 0
while hash(preHash,nonce)[:n]!= str(0).zfill(n):
nonce + = 1
return nonce
2)將出塊速度保持在1 min 左右,以獲得更快的交易確認。設置一個競爭等待時間(wTime)為10 s,第一個找到Nonce 的節點立即向全網廣播,此時觸發wTime,此后10 s 內找到的節點都有機會獲得記賬權,10 s 之后還沒有找到的節點則失去獲得本次記賬權的機會,停止計算。找到Nonce 所花費的時間記為fTime,作為確定打包記賬權的一個因素。
3)將難度調整機制改為每創建720 個區塊調整一次,即每12 h左右調整一次難度。難度計算公式改為:

其中:newDiff 為新區塊的難度;oldDiff 為前一個區塊的難度;totalTime 為創建過去720 個區塊所花費的總時長,單位為s。由于出塊速度在1 min 左右,所以43 200/totalTime 趨近于1,newDiff 和oldDiff 近似相等。如果算力增加,totalTime 就會小于 43 200 s,43 200/totalTime 大于 1,newDiff 將大于 oldDiff,難度增加;反之,算力減小,難度減小,以此來動態調整計算難度。
針對PoS 可能會出現的節點權益無限增大的問題,PoWaS 設置了一個有效持幣時間(valueTime),并限制最大值為60 d,幣齡的計算公式為:

若持幣時間超過有效持幣時間最大值,則valueTime 停止增長,由式(4)可以看出超出的時長不會納入幣齡的計算,以此來限制幣齡的無限增長,并設置參與pStake 計算的幣齡最大值為2 000,防止由于幣齡無限增長而帶來權益無限增大問題。
引入信用值來反映節點的信用情況,為每個節點賦予一個信用值(cPoint),作為記賬權的一個參考因素,根據節點的行為增加和扣除信用值:用信用值獎勵來調動礦工節點的挖礦積極性,信用值扣除來減小節點作惡的幾率。
信用值采用1 000 分制,最高為1 000,每個節點的初始信用值為400,成功記賬后會獲得0.1 信用值獎勵,節點如果發生惡意行為,比如惡意分叉,將扣除20 信用值。若信用值較低,則對節點競爭記賬權進行限制,具體規則如下:
1)信用值低于 400 高于 300 時,限制 120 輪,即 2 h 左右無法參與記賬權競爭;
2)信用值低于 300 高于 200 時,限制 720 輪,即 12 h 左右無法參與記賬權競爭;
3)信用值低于200高于100時,限制4 320輪,即72 h左右無法參與記賬權競爭;
4)信用值低于100時,剔除該節點,取消其礦工資格。
限制規則算法如算法2所示。
算法2 根據信用值限制記賬權競爭
輸入 信用值cPoint,當前區塊號begIndex;
輸出 限制狀態limitStatus,解除限制區塊號endIndex。
def limit_behavior(cPoint,begIndex):
if cPoint >= 400:
limitStatus = false
endIndex = begIndex
elif 400 > cPoint >= 300:
limitStatus = true
至此,我終于明白了。她所謂的“怕”,其實是面對弱者的遭遇無力提供幫助而產生的自責,繼而形成的逃避行為。
endIndex = begIndex + 120
elif 300 > cPoint >= 200:
limitStatus = true
endIndex = begIndex + 720
elif 200 > cPoint >= 100:
limitStatus = true
endIndex = begIndex + 4320
else:
limitStatus = true
return{’limitStatus’:limitStatus,’endIndex’:endIndex}
記賬權競爭流程為:各礦工節點根據當前的難度值進行哈希計算尋找隨機數Nonce,使得該Nonce 拼接上前一個區塊的hash 值再進行哈希計算后得到的hash 值的前n 位為0,n 等于難度值。當某礦工找到Nonce 后,立即向全網廣播,此時觸發競爭等待時間wTime(為10 s),其他節點收到廣播后還有10 s 的計算時間,如果10 s 內找到了Nonce,也立即向全網廣播,10 s后仍然沒有找到Nonce的節點失去本輪記賬機會。找到 Nonce 的節點根據 fTime、coinAge 和 cPoint 這三個值計算出所有找到Nonce的節點的pStake值,pStake的計算公式為:
pStake = coinAge/1000 +(cPoint - fTime)/100 (5)
由于這里的coinAge 限制了最大值為2 000,cPoint 為100至1 000,fTime 為60 左右,根據式(5)可知,coinAge/1000 為 0至2,cPoint/100為1至10,fTime/100為0.6左右。這樣就降低了權益和算力的比重,提高了信用值的比重,強化了信用值對記賬權競爭的影響,有利于減少礦工節點作惡行為的發生。
若發現自己的pStake 最大,則將所有的pStake 信息以及自己打包好的區塊廣播至全網,宣布自己獲得打包權,其他節點收到信息后進行驗證,若驗證通過,將收到信息中的區塊作為區塊鏈最后一個區塊進行下一輪的挖礦計算;若發現自己的pStake不是最大的,則競爭失敗,等待獲得打包權節點的廣播信息。沒有找到Nonce 的節點停止計算,收到獲得記賬權的節點的廣播信息后,再進行下一輪的計算。完整的記賬權競爭過程如圖1所示。

圖2 PoW機制下50次工作量證明計算結果Fig. 2 Work proof results of fifty times under PoW mechanism

圖1 記賬權競爭過程示意圖Fig. 1 Schematic diagram of accounting right competition process
使用Python3語言和Python Flask Web 框架編寫實現了一個區塊鏈原型,并使用PoWaS 共識機制搭建了一個測試區塊鏈,實驗室6 臺配置不同的計算機作為區塊鏈節點,從尋找隨機數所花時間、區塊鏈出塊時間以及記賬權競爭等方面進行了實驗。6個節點的配置信息如表1所示。

表1 節點配置信息Tab. 1 Node configuration information
PoWaS 通過調低難度值來降低PoW 部分尋找Nonce 的時間花銷,初始難度值設為6,即Nonce 拼接前一個區塊hash 值再進行計算得出的hash值前6位為0,這樣可以將平均計算時間控制在1 min以內。為了驗證,將測試區塊鏈的共識機制修改為只使用難度值為6 的純PoW 機制,6 個節點分別進行了50 次的工作量證明計算,記錄每次計算所花時間,統計后得到的結果如圖2所示。
從實驗結果可以看出,在配置不同的6 個節點的50 次計算時間里,雖然除節點6以外的5個節點均出現了計算時間超過60 s 的情況,但絕大多數還是集中在小于40 s 的區間內。由于哈希碰撞的不確定性,尋找隨機數所花時間并不一致,配置較低節點存在少數的計算時間超過60 s 的情況在所難免,但從全局來看影響并不大。該實驗可以證明在難度值設為6的情況下,基本可以保證工作量證明的時間花銷控制在1 min以內。
在實驗所搭建的區塊鏈運行一段時間后,在前50 個區塊中,以5 個區塊作為間隔,統計了10 個區塊的出塊時間,結果如圖3 所示。從圖3 中可以看出,曲線有輕微波動,但波動幅度并不大,基本都在60 上下,可以證明PoWaS 共識機制下區塊鏈的出塊速度可以保持在1 min左右。

圖3 前50個區塊的出塊時間統計Fig. 3 Block mining time statistics of top fifty blocks
節點的初始信用值為400,實驗將節點中算力最好的節點6 作為惡意節點,在產生第6 個區塊時,發生了惡意分叉行為,被扣除了20 信用值。統計前120 個區塊中每個節點的記賬次數,得到的結果如圖4 所示。從實驗結果可以看出,雖然節點4的算力最弱,但依然獲得了12次的記賬權;算力最好的節點6 由于惡意分叉行為被扣除20 信用之后,信用值為380.4,低于400,被限制了120 輪的記賬權,所以它的記賬次數僅為4。由此可以說明信用值和競爭等待時間的引入在一定程度上平衡了記賬權的競爭。

圖4 發生惡意分叉行為時各節點記賬次數統計Fig. 4 Statistics of node accounting times of various nodes when malicious bifurcation occurs
PoWaS 通過引入信用值來評估節點信用狀況,節點的作惡行為會被扣除信用值,信用值較低時就會受到限制甚至被剔除。通過2.4 節中對式(5)的分析可知,信用值在pStake值計算中的比重高于權益和算力的比重,這樣就降低了惡意節點獲得記賬權的幾率。通過3.4 節的實驗結果可知,算力最好的節點6 因惡意行為被扣除信用值限制記賬權競爭后,僅獲得了4次記賬權,遠少于其他節點。
目前常見的對區塊鏈的攻擊方式有雙花攻擊、自私挖礦等。雙花攻擊就是同一筆資金多次交易,根據攻擊手段的不同又有51%攻擊、賄賂攻擊和重放攻擊等。
在PoW 機制下,51%攻擊的攻擊者需要擁有全網51%的算力才能制造一個分叉并使之成為主鏈,使得自己支付給其他節點的那筆交易失效。而在PoWaS 機制下,攻擊者不僅需要擁有全網51%的算力,還需要自己的權益足夠大、信用值足夠高才能順利地進行雙花,否則不但會雙花失敗,而且還會受到扣除信用值的處罰,這是很難實現且得不償失的。賄賂攻擊的攻擊者則通過賄賂其他礦工節點來制造分叉,在PoWaS機制下,由于礦工都有信用值,在分叉上挖礦的惡意行為會被扣除信用值影響后續記賬權的競爭,礦工收受賄賂進行惡意挖礦的意愿會比較低,也就增大了攻擊者的賄賂成本,很難實現成功賄賂全網超過51%的節點。當區塊鏈有分叉鏈時,可能會遭受重放攻擊,就是攻擊者將在主鏈上的交易到分叉鏈上重新廣播一次,實現雙花,PoWaS機制對于重放攻擊的防范,就是在分叉前盡可能多地改變分叉鏈的交易結構,使得主鏈和分叉鏈無法互通。
PoW 機制下,自私挖礦的攻擊者挖出區塊后不公開,產生秘密分叉,然后在該分叉上挖礦,待到一定的時機再公開并使該秘密分叉成為主鏈,使得在原主鏈上挖礦的誠實礦工付出算力而得不到收益,自己獲得更高算力比例的收益。在PoWaS機制下,由于記賬權受信用值影響,如果礦工選擇不公開新區塊,并制造分叉,那么自己的信用值也不會增長,再次獲得記賬權的幾率不斷降低,很難攻擊成功,反而還會因惡意分叉行為被扣除信用值。
本文提出的PoWaS 區塊鏈共識機制,針對PoW 和PoS 的缺陷,通過降低哈希計算的難度、限制最大有效持幣時間以及引入節點信用值的方式來作出改進。實驗環境利用Python3語言和Flask Web 框架搭建的測試區塊鏈在擁有6 個算力不同的節點的情況下,得出的實驗結果在一定程度上證明了PoWaS 在減少算力浪費、加快區塊出塊速度和平衡記賬權競爭方面具有一定效果。但PoWaS 仍然存在不足,下一步工作將會在出塊速度穩定性和信用值調節方面加深研究,不斷完善該共識機制,進一步提升其可用性。