PBFT Consensus

PBFT 是共识算法中的一种实现,主要应用在节点较少的情况下。联盟链中使用这样的共识算法居多。下面有图和实现代码:

PBFT 的重点在于:

PBFT 容忍无效或者恶意节点数:f,为了保障整个系统可以正常运转,需要有 2f+1 个正常节点,系统的总节点数为:|R| = 3f + 1。也就是说,PBFT 算法可以容忍小于 1/3 个无效或者恶意节点。也就是说在超过 1/3 | R | 个节点确认之后,就认为是没有问题的。如以下代码 132 行所展现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146

package main

import (
"os"
"fmt"
"net/http"
"io"
)

//声明节点信息,代表各个小国家
type nodeInfo struct {
//标示
id string
//准备访问的方法
path string
//服务器做出的相应
writer http.ResponseWriter

}

//存放四个国家的地址
var nodeTable = make(map[string]string)

//拜占庭在Fabric中的使用
func main() {

//获取执行的参数
userId :=os.Args[1]//获取执行的第一个参数
fmt.Println(userId)

//./main Apple

//创建四个国家的地址
nodeTable = map[string]string {
"Apple":"localhost:1111",
"MS":"localhost:1112",
"Google":"localhost:1113",
"IBM":"localhost:1114",
}

node:=nodeInfo{userId,nodeTable[userId],nil}
fmt.Println(node)

//http协议的回调函数
//http://localhost:1111/req?warTime=8888
http.HandleFunc("/req",node.request)
http.HandleFunc("/prePrepare",node.prePrepare)
http.HandleFunc("/prepare",node.prepare)
http.HandleFunc("/commit",node.commit)

//启动服务器
if err:=http.ListenAndServe(node.path,nil);err!=nil {
fmt.Print(err)
}



}

//此函数是http访问时候req命令的请求回调函数
func (node *nodeInfo)request(writer http.ResponseWriter,request *http.Request){
//设置允许解析参数
request.ParseForm()
//如果有参数值,则继续处理
if (len(request.Form["warTime"])>0){
node.writer = writer
//激活主节点后,广播给其他节点,通过Apple向其他节点做广播
node.broadcast(request.Form["warTime"][0],"/prePrepare")

}


}


//由主节点向其他节点做广播
func (node *nodeInfo)broadcast(msg string ,path string ){
//遍历所有的国家
for nodeId,url:=range nodeTable {

if nodeId == node.id {
continue
}
//调用Get请求
//http.Get("http://localhost:1112/prePrepare?warTime=8888&nodeId=Apple")
http.Get("http://"+url+path+"?warTime="+msg+"&nodeId="+node.id)
}

}

func (node *nodeInfo)prePrepare(writer http.ResponseWriter,request *http.Request) {
request.ParseForm()
//fmt.Println("hello world")
//在做分发
if(len(request.Form["warTime"])>0){
//分发给其他三个人
node.broadcast(request.Form["warTime"][0],"/prepare")
}

}

func (node *nodeInfo)prepare(writer http.ResponseWriter,request *http.Request){

request.ParseForm()
//调用验证
if len(request.Form["warTime"])>0{
fmt.Println(request.Form["warTime"][0])
}
if len(request.Form["nodeId"])>0 {
fmt.Println(request.Form["nodeId"][0])
}

node.authentication(request)
}


var authenticationsuccess = true
var authenticationMap = make(map[string]string)
//获得除了本节点外的其他节点数据
func (node *nodeInfo)authentication(request *http.Request) {

//接收参数
request.ParseForm()

if authenticationsuccess!=false {
if len(request.Form["nodeId"])>0 {
authenticationMap[request.Form["nodeId"][0]]="ok"
}
}

if len(authenticationMap)>len(nodeTable)/3 {
//则拜占庭原理实现,通过commit反馈给浏览器
node.broadcast(request.Form["warTime"][0],"/commit")

}
}


func (node *nodeInfo)commit(writer http.ResponseWriter,request *http.Request){

//给浏览器反馈相应
io.WriteString(node.writer,"ok")

}