您好,登錄后才能下訂單哦!
怎么進行PBFT共識算法分析及Java實現,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
最近研究了區塊鏈相關的一些東西,其實就三大塊:
分布式存儲(去中心)
共識機制
安全加密 分布式存儲,就是一個分布式數據庫,每個節點都保存一份副本。通過非對稱秘鑰,hash等技術對操作數據進行簽名,驗證摘要,可追溯,以鏈式結構存儲,互相以hash摘要校驗數據,防篡改。以拜占庭容錯共識算法解決節點間的通信,達成一致協議。
分布式共識算法是分布式系統的核心,常見的有Paxos、pbft、bft、raft、pow等。區塊鏈中常見的是POW、POS、DPOS、pbft等。 其中:
POW、POS、DPOS是開放式的共識協議
PBFT為半開放式的共識協議
Paxos、raft等是封閉式共識協議
區別:
開放式,無法確切的知道節點的多少及連接狀態,每個節點都可能是惡意的,但是大多數是非惡意的
半開放式,可以確定節點的多少及連接狀態,每個節點都可能是惡意的,但是有滿足一定條件的非惡意節點
封閉式,每個節點都是非惡意的,只不過可能斷開連接或crash。
性能: 從上往下越來越高
總結:
私有鏈是封閉生態的存儲系統,采用Paxos、raft最佳
聯盟鏈有半公開半開放特性,因此拜占庭容錯的PBFT算法比較合適
公有鏈來說,POW、POS、DPOS是比較適合的高安全性的協議
那么,下面我們要說的就是聯盟鏈性質的共識協議:PBFT算法協議。 協議誕生已經很久了,網上的文章也不少,然而基本都是翻譯原論文,稍加一些個人的閱讀心得,細致的分析還是比較少,一些關鍵的銜接點沒有說清楚,粗看好像都懂,但是真正要實現起來,還是有比較多坑。于是本人采用demo的方式,以多線程模擬多節點,實現完整的PBFT算法,其中有一些問題,記錄下來,供各位參考,討論。
主要有三個階段:預準備(pre-prepare)、準備(prepare)、和確認(commit)
從全網節點選舉出一個主節點(Leader),新區塊由主節點負責生成。
其中一個節點的客戶端向主節點發起請求。
Pre-Prepare:主節點分配一個序列號n給收到的請求(順序的保證!),并向全網廣播<<PRE-PREPARE,v,n,d>,m>
。
Prepare:每個節點接收到交易請求后,模擬執行這些交易,驗證交易報文的正確性。驗證通過后,存入預備列表,并向全網廣播<PREPARE,v,n,d,i>
Commit:如果一個節點收到的2f(f為可容忍的拜占庭節點數)個其它節點發來的PREPARE消息摘要都和自己相等,就向全網廣播一條commit消息<COMMIT,v,n,D(m),i>
Reply:如果一個節點收到2f+1條commit消息,即可提交新區塊及其交易到本地的區塊鏈和狀態數據庫(操作確認完成)。
整個協議理解起來還算比較簡單,但是這里面有好些問題,需要一一的剖析。
主節點怎么產生?
主節點失效了怎么辦?
主節點造假怎么辦?
數據怎么重傳?
因為節點的操作都需要通過主節點,所以每個節點啟動后的第一件事,找主節點。 主節點由公式p = v mod |R|計算得到,這里v是視圖編號,p是副本編號,|R|是副本集合的個數。 所以其實找主節點就是初始化視圖view。
全網廣播獲取視圖協議:
public static final int VIEW = -1;
超過2f+1的節點回復的view作為初始化的view(q1:如果無法滿足怎么辦?)
if(this.viewOk)return; long count = vnumAggreCount.incrementAndGet(msg.getVnum()); if(count >= 2*maxf+1){ vnumAggreCount.clear(); this.view = msg.getVnum(); viewOk = true; System.out.println("視圖初始化完成["+index+"]:"+ view); }
誰先發現主節點失效了,當然,這里是不能通過連接斷開來看,因為即使tcp連接正常,也不一定業務處理正常。答案是,超時控制。 當發起請求的節點在超時時間內沒有完成操作確認,則可以懷疑主節點失效,于是:
客戶端全網廣播超時的請求報文,為什么不用一個專門的包來發起失效提議?主要是防止發起請求的節點作惡,比如循環發起提議。導致不斷產生提議檢驗,導致網絡擁堵
副本節點檢查,如果處理過(說明可能是網絡問題),重新將處理結果返回即可,如果未處理,則可能主節點宕機,將請求重新轉發給主節點,且增加超時校驗。這時,如果主節點是正常的,那么就會走正常流程,最終會確認操作請求。如果主節點真的有問題,則設置的超時將觸發
超時后全網廣播主節點切換提議
if(!this.viewOk) return; // 已經開始選舉視圖,不用重復發起 this.viewOk = false; // 作為副本節點,廣播視圖變更投票 PbftMsg cv = new PbftMsg(CV, this.index); cv.setVnum(this.view+1); PbftMain.publish(cv);
當每個節點都收到2f+1個對同一個view的提議后,則切換成新的view。且檢查是否有請求待發送,一切恢復正常邏輯:
long count = vnumAggreCount.incrementAndGet(msg.getVnum()); if(count >= 2*maxf+1){ vnumAggreCount.clear(); this.view = msg.getVnum(); viewOk = true; System.out.println("視圖變更完成["+index+"]:"+ view); // 可以繼續發請求 if(curMsg != null){ curMsg.setVnum(this.view); System.out.println("請求重傳["+index+"]:"+ curMsg); doSendCurMsg(); } }
提議時,如果有惡意節點重復多次發起,需要檢測每個節點只能投票一次。
String vkey = msg.getNode()+"@"+msg.getVnum(); if(votes_vnum.contains(vkey)){ return; } votes_vnum.add(vkey);
當commit通過后,即確認了操作,則可以對該消息相關的狀態進行清理:
// 清理請求相關狀態 private void remove(String it) { votes_pre.remove(it); votes_pare.removeIf((vp)->{ return StringUtils.startsWith(vp, it); }); votes_comm.removeIf((vp)->{ return StringUtils.startsWith(vp, it); }); aggre_pare.remove(it); aggre_comm.remove(it); timeOuts.remove(it); }
PbftMsg消息的DataKey必須是唯一的,可以通過uuid或者其他方式定義
private int type; // 消息類型 private int node; // 節點 private int onode; // 發起請求的節點 private int vnum; // 視圖編號 private int no; // 序列號 private long time; // 時間戳 private String data; // 數據,表示數據的hash,必須唯一
關于怎么進行PBFT共識算法分析及Java實現問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。