PBFT代码实现

本篇文章主要是PBFT共识的简单实现,其中有许多地方都做了简化。PBFT的原理已在上篇文章中描述过,如果对PBFT的原理不太清晰的的可以进行查看。文章地址:共识算法学习总结

代码实现的主要功能有:通过客户端添加区块,使用libp2p的mdns进行节点发现,动态的添加节点。

客户端

在启动客户端时,首先根据端口号创建一个客户端,然后启动客户端。

var clientCmd = &cobra.Command{
	Use: "client",
	Short: "client manage",
	Run: func(cmd *cobra.Command, args []string) {
		// 获取客户端的端口
		port, err := cmd.Flags().GetInt("port")
		if err != nil {
			log.Println("get param error: ", err)
		}
		// 客户端传递的数据
		data, err := cmd.Flags().GetString("data")
		if err != nil{
			log.Println("get param error: ", err)
		}
		client := NewClient(port)
		client.Start(data)
	},
}

创建客户端

创建的客户端为libp2p节点,并设置节点的私钥。这里的加密算法使用的是Ed25519算法,不但效率更高并且可以在别的节点获取当前节点的公钥。

// 创建客户端
func NewClient(listenPort int) *Client {
	// 生成密钥对
	r := rand.Reader
	prvKey, _, err := crypto.GenerateKeyPairWithReader(crypto.Ed25519, 2048, r)
	if err != nil{
		log.Println(err)
	}
	pubKey := prvKey.GetPublic()
	sourceMultiAddr, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", "127.0.0.1", listenPort))

	// 创建libp2p节点
	h, err := libp2p.New(
		libp2p.ListenAddrs(sourceMultiAddr),
		libp2p.Identity(prvKey),
	)
	if err != nil {
		 log.Println("创建的客户端节点失败:", err)
	}

	h.SetStreamHandler(protocol.ID(protocolID), handleStream)

	fmt.Printf(">>> 创建客户端p2p节点成功,客户端多路地址是: /ip4/%s/tcp/%v/p2p/%s\n", "0.0.0.0", listenPort, h.ID().Pretty())

	keyPair := Keypair{
		privkey: prvKey,
		pubkey: pubKey,
	}

	// 创建客户端
	client := &Client{
		h,
		keyPair,
		[]KnownNode{},
		sync.Mutex{},
		make(map[string]*common.ReplyMsg),
	}
	
	fmt.Println(">>> 创建客户端成功...")
	return client
}

启动客户端

客户端启动时,首先不断获取网络中的节点,然后发送request请求,并等待回应。
这里做了简化,在客户端启动时就直接发送request请求。

func (c *Client) Start (data string)  {
	fmt.Println(">>> 开始启动客户端...")
	ctx := context.Background()
	// 通过协程获取网络中的节点,使用libp2p的mdns节点发现
	go c.getAllKonwons(c.client)
	// 发送客户端请求
	c.sendRequest(ctx, data)
	// 处理响应
	go c.handleConnection()

	select {}
}

客户端发送请求

客户端首先创建request消息,消息格式为<REQUEST, o, t, c>。o: 请求的具体操作,t: 请求时客户端追加的时间戳,c:客户端标识。REQUEST: 包含消息内容m,以及消息摘要d(m)。客户端对请求进行签名。

客户端创建完request请求后就可以向主节点发送该请求。

func (c *Client) sendRequest(ctx context.Context, data string)  {
	fmt.Println(">>> 客户端准备request消息...")
	// 构建request
	req := common.Request{
		data,
		hex.EncodeToString(common.GenerateDigest(data)),
	}

	// 序列化pubKey
	marshalPubkey, err := crypto.MarshalPublicKey(c.keypair.pubkey)
	sendClient := common.SendClient{
		c.client.ID().Pretty(),
		marshalPubkey,
	}
	// 构建request消息
	reqMsg := common.RequestMsg{
		"solve",
		int(time.Now().Unix()),
		sendClient,
		req,
	}

	// 对发送的消息进行签名
	sig, err := c.signMessage(reqMsg)
	if err != nil{
		fmt.Printf("%v\n", err)
	}

	// 组合并发送消息
	c.send(ctx, common.ComposeMsg(common.HRequest, reqMsg, sig), c.findPrimaryNode())
	fmt.Println(">>> 客户端发送消息完成...")
}

数据发送

客户端发送数据时,首先连接到主节点,然后打开与主节点的stream。再打开数据发送的通道,最后序列化数据并发数据添加到发送数据的通道中。

func (c *Client) send(ctx context.Context, msg []byte, node KnownNode) {
	// 开始连接到主节点
	if err := c.client.Connect(ctx, node.h); err != nil{
		log.Println(">>> 连接到主节点失败")
	}

	// 打开stream
	s, err := c.client.NewStream(context.Background(), node.h.ID, protocol.ID(protocolID))
	if err != nil {
		fmt.Println(">>> 打开stream失败", err)
	}
	fmt.Println(">>> 开始连接到: ", node.h)

	rw := bufio.NewReadWriter(bufio.NewReader(s), bufio.NewWriter(s))

	// 准备发送数据的通道
	go sendData(rw)

	// 序列化数据
	data, err := json.Marshal(msg)
	if err != nil{
		fmt.Println("序列化数据错误", err)
	}

	sendDataChan <- data
	close(sendDataChan)
}

服务端命令行

服务端启动启动时,首先创建一个server,然后启动server。

var serverCmd = &cobra.Command{
	Use: "server",
	Short: "server manage",
	Run: func(cmd *cobra.Command, args []string) {
		port, err := cmd.Flags().GetInt("port")
		if err != nil {
			log.Println("get param error: ", err)
		}
		// 创建server
		server := NewServer(port)
		// 开始server
		server.start()
	},
}

创建新的节点

创建服务端与创建客户端类似。

func NewNode(port int) *Node {
	// 生成密钥对
	r := rand.Reader
	prvKey, _, err := crypto.GenerateKeyPairWithReader(crypto.Ed25519, 2048, r)
	if err != nil{
		log.Println(err)
	}
	pubKey := prvKey.GetPublic()
	sourceMultiAddr, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", "127.0.0.1", port))

	// 创建libp2p节点
	h, err := libp2p.New(
		libp2p.ListenAddrs(sourceMultiAddr),
		libp2p.Identity(prvKey),
	)
	if err != nil {
		log.Println(err)
	}

	h.SetStreamHandler(protocol.ID(protocolID), handleStream)
	fmt.Printf(">>> 创建客户端p2p节点成功,客户端多路地址是: /ip4/%s/tcp/%v/p2p/%s\n", "0.0.0.0", port, h.ID().Pretty())

	keyPair := Keypair{
		privkey: prvKey,
		pubkey: pubKey,
	}

	// 创建node
	return &Node{
		[]KnownNode{},
		ClientNode{},
		0,
		h,
		ViewID,
		make(chan []byte),
		keyPair,
		&MsgLog{
			make(map[string]map[string]bool),
			make(map[string]map[string]bool),
			make(map[string]map[string]bool),
			make(map[string]bool),
		},
		make(map[string]*common.RequestMsg),
		sync.Mutex{},
	}
}

启动节点

服务端的启动仅仅开启一个消息处理协程。 通过消息处理协程,会把服务端接收到的消息分配到对应的逻辑中进行处理。

func (node *Node)Start()  {
	// 处理消息
	go node.handleMsg()
}

func (node *Node) handleMsg() {
	fmt.Println(">>> 启动节点,等待接收消息...")
	for  {

		//  待改进 todo
		rawData := <- receiveChan

		// 反序列得到的数据
		var data []byte
		err := json.Unmarshal([]byte(rawData), &data)
		if err != nil {
			fmt.Println("反序列消息化失败:", err)
			return
		}

		// 分割消息,分别处理不同的消息
		header, payload, sign:= common.SplitMsg(data)
		switch header {
		case common.HRequest:
			node.handleRequest(payload, sign)
		case common.HPrePrepare:
			node.handlePrePrepare(payload, sign)
		case common.HPrepare:
			node.handlePrepare(payload, sign)
		case common.HCommit:
			node.handleCommit(payload, sign)
		default:
			fmt.Println("===============无法处理对应的消息============")
		}
	}
}

request处理

节点接收到消息后,首先反序列化request消息,然后设置客户端。接着校验request消息的摘要及签名。通过验证后放入请求池,接着创建pre-prepare消息并进行签名。最组合消息进行发送。剩下的三个函数类似,这里就不再叙述。

func (node *Node) handleRequest(payload []byte, sig []byte)  {
	fmt.Println(">>> 主节点接收request消息...")
	var request common.RequestMsg
	var prePrepareMsg common.PrePrepareMsg

	// 反序列化请求消息
	err := json.Unmarshal(payload, &request)
	if err != nil{
		log.Println("反序列化request错误: ", err)
		return
	}

	// 设置节点的客户端
	clientPubKey, err := crypto.UnmarshalPublicKey(request.Client.PubKey)
	if err != nil{
		fmt.Println(">>> 反序列化客户端公钥失败", err)
	}
	clientNode := ClientNode{
		request.Client.ID,
		clientPubKey,
	}
	node.clientNode = clientNode


	// 校验request的摘要
	vdig := common.VerifyDigest(request.CRequest.Message, request.CRequest.Digest)
	if vdig == false {
		fmt.Printf("验证摘要错误\n")
		return
	}

	// 校验request的签名
	_, err  = common.VerifySignatrue(request, sig, clientPubKey)
	if err != nil  {
		fmt.Printf("验证签名错误:%v\n", err)
		return
	}

	// 添加进请求池
	node.mutex.Lock()
	node.requestPool[request.CRequest.Digest] = &request
	seqID := node.getSequenceID()
	node.mutex.Unlock()

	// 构建pre-Prepare消息
	prePrepareMsg = common.PrePrepareMsg{
		request,
		request.CRequest.Digest,
		ViewID,
		seqID,
	}

	// 消息签名
	msgSig, err:= node.signMessage(prePrepareMsg)
	if err != nil{
		fmt.Printf("%v\n", err)
		return
	}

	// 消息组合
	msg := common.ComposeMsg(common.HPrePrepare, prePrepareMsg, msgSig)

	// 日志处理
	node.mutex.Lock()
	if node.msgLog.preprepareLog[prePrepareMsg.Digest] == nil {
		node.msgLog.preprepareLog[prePrepareMsg.Digest] = make(map[string]bool)
	}
	node.msgLog.preprepareLog[prePrepareMsg.Digest][node.node.ID().String()] = true
	node.mutex.Unlock()

	// 序列化消息
	data, err := json.Marshal(msg)
	if err != nil{
		fmt.Println("序列化request消息出错", err)
		return
	}

	fmt.Println(">>> 主节点广播prePrepare消息...")
	// 广播消息
	node.broadcast(data)
}

pre-prepare消息处理

func (node *Node) handlePrePrepare(payload []byte, sig []byte) {
	fmt.Println(">>> 副节点开始接收prePrepare消息...")
	// 反序列化prePrepare消息
	var prePrepareMsg common.PrePrepareMsg
	err := json.Unmarshal(payload,&prePrepareMsg)
	if err != nil {
		fmt.Printf("error happened:%v", err)
		return
	}

	// 找到主节点的公钥
	pnodeId := node.findPrimaryNode()
	pubKey, err := pnodeId.h.ID.ExtractPublicKey()
	if err != nil {
		fmt.Println("获取主节点的公钥失败", err)
		return
	}

	// 校验消息签名
	_, err = common.VerifySignatrue(prePrepareMsg, sig, pubKey)
	if err != nil  {
		fmt.Printf("验证主节点签名错误:%v\n", err)
		return
	}

	// 校验消息的摘要
	if prePrepareMsg.Digest != prePrepareMsg.Request.CRequest.Digest {
		fmt.Printf("校验摘要错误\n")
		return
	}

	node.mutex.Lock()
	node.requestPool[prePrepareMsg.Request.CRequest.Digest] = &prePrepareMsg.Request
	node.mutex.Unlock()

	// 校验request的摘要
	err = node.verifyRequestDigest(prePrepareMsg.Digest)
	if err != nil{
		fmt.Printf("%v\n", err)
		return
	}

	node.mutex.Lock()
	node.requestPool[prePrepareMsg.Request.CRequest.Digest] = &prePrepareMsg.Request
	node.mutex.Unlock()

	err = node.verifyRequestDigest(prePrepareMsg.Digest)
	if err != nil{
		fmt.Printf("%v\n", err)
		return
	}

	node.mutex.Lock()
	if node.msgLog.preprepareLog[prePrepareMsg.Digest] == nil {
		node.msgLog.preprepareLog[prePrepareMsg.Digest] = make(map[string]bool)
	}
	node.msgLog.preprepareLog[prePrepareMsg.Digest][node.node.ID().String()] = true
	node.mutex.Unlock()

	// 构建prePare消息
	prepareMsg := common.PrepareMsg{
		prePrepareMsg.Digest,
		ViewID,
		prePrepareMsg.SequenceID,
		node.node.ID(),
	}

	// 签名
	msgSig, err := common.SignMessage(prepareMsg, node.keypair.privkey)
	if err != nil{
		fmt.Printf("%v\n", err)
		return
	}
	// 消息组合
	sendMsg := common.ComposeMsg(common.HPrepare,prepareMsg,msgSig)

	// 序列化消息
	data, err := json.Marshal(sendMsg)
	if err != nil{
		fmt.Println("序列化prepare消息出错", err)
		return
	}

	fmt.Println(">>> 副节点广播prepare消息...")
	node.broadcast(data)
}

prepare消息处理

func (node *Node) handlePrepare(payload []byte, sig []byte) {
	fmt.Println(">>> 副节点开始接收prepare消息...")

	// 反序列化prepare消息
	var prepareMsg common.PrepareMsg
	err := json.Unmarshal(payload,&prepareMsg)
	if err != nil {
		fmt.Printf("error happened:%v", err)
		return
	}

	// 得到节点的公钥
	pnodeID := prepareMsg.NodeID
	pubKey, err:= findNodePubkey(pnodeID)
	if err != nil {
		fmt.Println("获取主节点的公钥失败", err)
		return
	}

	_, err = common.VerifySignatrue(prepareMsg, sig, pubKey)
	if err != nil  {
		fmt.Printf("校验签名prepare消息错误:%v\n", err)
		return
	}

	err = node.verifyRequestDigest(prepareMsg.Digest)
	if err != nil{
		fmt.Printf("%v\n", err)
		return
	}

	// 日记记录
	node.mutex.Lock()
	if node.msgLog.prepareLog[prepareMsg.Digest] == nil {
		node.msgLog.prepareLog[prepareMsg.Digest] = make(map[string]bool)
	}
	node.msgLog.prepareLog[prepareMsg.Digest][prepareMsg.NodeID.String()] = true
	node.mutex.Unlock()

	// if receive prepare msg >= 2f +1, then broadcast commit msg
	limit := node.countNeedReceiveMsgAmount()
	sum, err  := node.findVerifiedPrepareMsgCount(prepareMsg.Digest)
	if err != nil {
		fmt.Printf("error happened:%v", err)
		return
	}
	if sum >= limit {
		//send commit msg
		commitMsg := common.CommitMsg{
			prepareMsg.Digest,
			prepareMsg.ViewID,
			prepareMsg.SequenceID,
			node.node.ID(),
		}
		sig, err := node.signMessage(commitMsg)
		if err != nil{
			fmt.Printf("sign message happened error:%v\n", err)
		}
		sendMsg := common.ComposeMsg(common.HCommit,commitMsg,sig)

		data, err := json.Marshal(sendMsg)
		if err != nil{
			fmt.Println("序列化commit消息出错", err)
		}

		node.broadcast(data)
		fmt.Println(">>> 副节点广播commit消息成功")
	}
}

commit 消息处理

func (node *Node) handleCommit(payload []byte, sig []byte) {
	fmt.Println(">>> 副节点开始接收commit消息")

	// 反序列化消息
	var commitMsg common.CommitMsg
	err := json.Unmarshal(payload,&commitMsg)
	if err != nil {
		fmt.Printf("error happened:%v", err)
	}

	msgPubKey, err := findNodePubkey(commitMsg.NodeID)
	if err != nil{
		fmt.Println(err)
		return
	}

	verify, err := common.VerifySignatrue(commitMsg, sig, msgPubKey)
	if err != nil  {
		fmt.Printf("verify signature failed:%v\n", err)
		return
	}
	if verify == false {
		fmt.Printf("verify signature failed\n")
		return
	}

	err = node.verifyRequestDigest(commitMsg.Digest)
	if err != nil{
		fmt.Printf("%v\n", err)
		return
	}

	node.mutex.Lock()
	if node.msgLog.commitLog[commitMsg.Digest] == nil {
		node.msgLog.commitLog[commitMsg.Digest] = make(map[string]bool)
	}
	node.msgLog.commitLog[commitMsg.Digest][commitMsg.NodeID.String()] = true
	node.mutex.Unlock()
	// if receive commit msg >= 2f +1, then send reply msg to client
	limit := node.countNeedReceiveMsgAmount()
	sum, err := node.findVerifiedCommitMsgCount(commitMsg.Digest)
	if err != nil{
		fmt.Printf("error happened:%v", err)
		return
	}

	if sum >= limit {
		// if already send reply msg, then do nothing
		node.mutex.Lock()
		exist := node.msgLog.replyLog[commitMsg.Digest]
		node.mutex.Unlock()
		if exist == true {
			return
		}
		// send reply msg
		node.mutex.Lock()
		requestMsg := node.requestPool[commitMsg.Digest]
		node.mutex.Unlock()
		fmt.Printf("operstion:%s  message:%s executed... \n",requestMsg.Operation, requestMsg.CRequest.Message)
		done := fmt.Sprintf("operstion:%s  message:%s done ",requestMsg.Operation, requestMsg.CRequest.Message)
		replyMsg := common.ReplyMsg{
			node.View,
			int(time.Now().Unix()),
			requestMsg.Client.ID,
			node.node.ID().String(),
			done,
		}
		
		hostAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", requestMsg.Client.ID))
		clientNode, err := peer.AddrInfoFromString(hostAddr.String())
		fmt.Println(">>> 客户端地址:", clientNode.ID.Pretty())
		if err != nil{
			fmt.Println(err)
			return
		}

		fmt.Println(">>> 开始向客户端回复数据...")
		sendMsg := common.ComposeMsg(common.HReply,replyMsg,[]byte{})
		data, err := json.Marshal(sendMsg)
		if err != nil{
			fmt.Println("序列化commit消息出错", err)
		}
		node.reply(context.Background(), data, *clientNode)
		node.mutex.Lock()
		node.msgLog.replyLog[commitMsg.Digest] = true
		node.mutex.Unlock()
		fmt.Println(">>> 回复客户端成功...")
	}
}

运行结果

在这里插入图片描述

最后

项目中做了很多简化并且有很多设计不合理的地方,以后会继续进行改进。源码:https://github.com/blockchainGuide/Consensus_Algorithm

  • 8
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
PBFT(Practical Byzantine Fault Tolerance)是一种拜占庭容错的共识算法,适用于有限个节点的分布式系统。下面是一个简单的PBFT共识机制的实现示例: 1. 代码框架 ```python # 导入相关库 # 定义节点类 class Node: def __init__(self, id, address): self.id = id self.address = address self.peers = [] self.state = "INIT" self.view = 0 self.sequence_number = 0 self.message_buffer = [] self.message_queue = [] self.processed_message = {} self.current_request = None self.current_view = None self.current_pre_prepare = None self.current_prepare = {} self.current_commit = {} self.last_stable_checkpoint = 0 self.last_executed_sequence_number = -1 # 处理消息 def process_message(self, message): pass # 发送消息 def send_message(self, address, message): pass # 切换视图 def change_view(self, view): pass # 发送消息给其他节点 def broadcast_message(self, message): pass # 处理请求 def handle_request(self, request): pass # 执行请求 def execute_request(self, request): pass # 记录检查点 def record_checkpoint(self, sequence_number): pass # 处理检查点 def handle_checkpoint(self, sequence_number): pass # 定义消息类 class Message: def __init__(self, sender, receiver, type, content): self.sender = sender self.receiver = receiver self.type = type self.content = content # 定义请求类 class Request: def __init__(self, client_id, client_request_id, content): self.client_id = client_id self.client_request_id = client_request_id self.content = content ``` 2. 实现PBFT共识机制 具体实现过程如下: - 节点状态 节点状态有以下几种: - INIT:初始状态。 - PRE_PREPARE:节点收到客户端请求后,发送PRE-PREPARE消息给其他节点。 - PREPARE:节点收到PRE-PREPARE消息后,发送PREPARE消息给其他节点。 - COMMIT:节点收到PREPARE消息后,发送COMMIT消息给其他节点。 - EXECUTE:节点收到COMMIT消息后,执行请求,并发送REPLY消息给客户端。 - 消息类型 消息类型有以下几种: - PRE-PREPARE:包含请求内容和序列号等信息,用于请求的第一阶段。 - PREPARE:包含节点的ID和序列号等信息,用于请求的第二阶段。 - COMMIT:包含节点的ID和序列号等信息,用于请求的第三阶段。 - CHECKPOINT:包含检查点的序列号等信息。 - REPLY:包含执行结果等信息,用于向客户端发送请求的结果。 - PBFT算法步骤 PBFT算法的步骤分为以下五个阶段: 1. 客户端发送请求。 客户端向节点发送请求,包含客户端ID和请求ID等信息。 2. 节点收到请求,发送PRE-PREPARE消息。 节点收到客户端请求后,将请求内容和序列号等信息打包成PRE-PREPARE消息,发送给其他节点,并进入PRE_PREPARE状态。 3. 节点收到PRE-PREPARE消息,发送PREPARE消息。 节点收到其他节点发送的PRE-PREPARE消息后,验证消息的合法性,并发送PREPARE消息给其他节点,并进入PREPARE状态。 4. 节点收到PREPARE消息,发送COMMIT消息。 节点收到其他节点发送的PREPARE消息后,验证消息的合法性,并发送COMMIT消息给其他节点,并进入COMMIT状态。 5. 节点收到COMMIT消息,执行请求,发送REPLY消息。 节点收到其他节点发送的COMMIT消息后,验证消息的合法性,并执行请求。执行完成后,节点将执行结果打包成REPLY消息,发送给客户端,并进入INIT状态。 ```python # PBFT共识机制实现 class PBFT(Node): # 定义消息类型 PRE_PREPARE = "PRE_PREPARE" PREPARE = "PREPARE" COMMIT = "COMMIT" CHECKPOINT = "CHECKPOINT" REPLY = "REPLY" def __init__(self, id, address): super().__init__(id, address) # 处理消息 def process_message(self, message): if message.type == self.PRE_PREPARE: self.handle_pre_prepare(message) elif message.type == self.PREPARE: self.handle_prepare(message) elif message.type == self.COMMIT: self.handle_commit(message) elif message.type == self.CHECKPOINT: self.handle_checkpoint(message) elif message.type == self.REPLY: self.handle_reply(message) # 发送消息 def send_message(self, address, message): pass # 切换视图 def change_view(self, view): pass # 发送消息给其他节点 def broadcast_message(self, message): pass # 处理请求 def handle_request(self, request): self.current_request = request self.current_view = self.view self.current_pre_prepare = Message(self.id, None, self.PRE_PREPARE, { "client_id": request.client_id, "client_request_id": request.client_request_id, "request_content": request.content, "sequence_number": self.sequence_number, "digest": None }) self.message_buffer.append(self.current_pre_prepare) self.broadcast_message(self.current_pre_prepare) # 处理PRE-PREPARE消息 def handle_pre_prepare(self, message): if message.sender not in self.peers: return if not self.current_request: return if self.current_pre_prepare and (message.content["digest"] != self.current_pre_prepare.content["digest"]): return if message.content["sequence_number"] <= self.last_stable_checkpoint: return self.current_pre_prepare = message self.current_pre_prepare.sender = message.sender self.current_pre_prepare.receiver = self.id self.current_prepare = {self.id: Message(self.id, None, self.PREPARE, { "sequence_number": message.content["sequence_number"], "digest": message.content["digest"] })} self.message_buffer.append(self.current_prepare[self.id]) self.broadcast_message(self.current_prepare[self.id]) # 处理PREPARE消息 def handle_prepare(self, message): if message.sender not in self.peers: return if not self.current_pre_prepare: return if message.content["sequence_number"] != self.current_pre_prepare.content["sequence_number"]: return if message.content["digest"] != self.current_pre_prepare.content["digest"]: return self.current_prepare[message.sender] = message if len(self.current_prepare) > (2 * len(self.peers) // 3): self.current_commit = {self.id: Message(self.id, None, self.COMMIT, { "sequence_number": self.current_pre_prepare.content["sequence_number"], "digest": self.current_pre_prepare.content["digest"] })} self.message_buffer.append(self.current_commit[self.id]) self.broadcast_message(self.current_commit[self.id]) # 处理COMMIT消息 def handle_commit(self, message): if message.sender not in self.peers: return if message.content["sequence_number"] != self.current_pre_prepare.content["sequence_number"]: return if message.content["digest"] != self.current_pre_prepare.content["digest"]: return self.current_commit[message.sender] = message if len(self.current_commit) > (2 * len(self.peers) // 3): self.execute_request(self.current_request) self.record_checkpoint(self.current_pre_prepare.content["sequence_number"]) reply_message = Message(self.id, self.current_request.client_id, self.REPLY, { "client_request_id": self.current_request.client_request_id, "result": "success" }) self.message_buffer.append(reply_message) self.send_message(self.current_request.client_id, reply_message) # 处理检查点 def handle_checkpoint(self, message): pass # 处理回复 def handle_reply(self, message): pass # 执行请求 def execute_request(self, request): pass # 记录检查点 def record_checkpoint(self, sequence_number): pass ``` 3. 测试 测试代码如下: ```python # 创建节点 node1 = PBFT(1, "127.0.0.1:8001") node2 = PBFT(2, "127.0.0.1:8002") node3 = PBFT(3, "127.0.0.1:8003") # 建立节点关系 node1.peers = [node2.address, node3.address] node2.peers = [node1.address, node3.address] node3.peers = [node1.address, node2.address] # 处理请求 request = Request(1, 1, "request_content") node1.handle_request(request) # 处理消息 for node in [node1, node2, node3]: while node.message_buffer: message = node.message_buffer.pop(0) for peer in node.peers: if peer != message.sender: node.send_message(peer, message) ``` 4. 总结 以上是一个简单的PBFT共识机制的实现示例,主要包括节点类、消息类、请求类和PBFT类等。具体实现过程分为节点状态、消息类型和PBFT算法步骤三个部分。在测试过程中,我们创建了三个节点,并建立节点之间的关系,然后处理请求和消息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值