赞
踩
优点
缺点
优点
缺点
以下就是这三个共识算法的伪代码
数据结构:model.Block.go
package model type PowBlock struct { Index int64 // 区块号 Timestamp string // 时间戳字符串 Hash string // 区块的hash值 PrevHash string // 上一个区块的hash NodeAddress string // 生成这个区块的节点地址 Data string // 区块数据 Nonce int // 随机值 } type PosBlock struct { Index int64 // 区块号 Timestamp string // 时间戳字符串 Hash string // 区块的hash值 PrevHash string // 上一个区块的hash NodeAddress string // 生成这个区块的节点地址 Data string // 区块数据 Nonce int // 随机值 } type DPosBlock struct { Index int64 // 区块号 Timestamp string // 时间戳字符串 Hash string // 区块的hash值 PrevHash string // 上一个区块的hash NodeAddress string // 生成这个区块的节点地址 Data string // 区块数据 Nonce int // 随机值 } type WitnessNode struct { Name string NodeAddress string Votes int // 投票数 }
全局变量:common/globleValue.go
package common import ( "block_test/model" ) // ************************* PoW ********************************** // GlobleBlocks CandidateBlocks 全局变量 var PowGlobleBlocks []model.PowBlock // 区块链 var PowCandidateBlocks []model.PowBlock // 候选区块数组 // ************************* PoS ********************************** // PosGlobleBlocks GlobleBlocks 全局变量 var PosGlobleBlocks []model.PosBlock // 区块链 var PosCandidateBlocks []model.PosBlock // 候选区块数组 // StackRecord 股权记录表 var StackRecord []string // ************************* DPoS ********************************** // WitnessList 见证者列表 var WitnessList []model.WitnessNode // BeforeTime 上一次更新时间 var BeforeTime int64 // DPosCycle 更新周期为一个小时 var DPosCycle = 60 * 60 // 见证者的数量限制 var WitnessNum = 100
PoW伪代码:server/pow.go
package server import ( "block_test/common" "block_test/model" "encoding/hex" "math/rand" "strconv" "strings" "time" ) // 判断是否要生成区块的函数 func IsBlockHashMatchDifficulty(block model.PowBlock, difficulty int) bool { prefix := strings.Repeat("0", difficulty) // 根据难度值生成对应个数的前缀 0 hash := powCalculateHash(block) return strings.HasPrefix(hash, prefix) // 进行前缀0个数的比较,包含则返回true } // 生成hash函数 func powCalculateHash(block model.PowBlock) string { return "hash" } // 生成区块函数 func PowGenerateBolck(oldBlock model.PowBlock, data string, difficulty int) model.PowBlock { var newBlock model.PowBlock newBlock.Timestamp = strconv.FormatInt(time.Now().Unix(), 10) newBlock.Index = oldBlock.Index + 1 newBlock.Data = data newBlock.PrevHash = oldBlock.Hash for i := 0; ; i++ { newBlock.Nonce = hex.EncodedLen(rand.Intn(255)) // 给一个nonce值,先是给一个随机数吧,0-255 newBlock.Hash = powCalculateHash(newBlock) if IsBlockHashMatchDifficulty(newBlock, difficulty) { common.PowCandidateBlocks = append(common.PowCandidateBlocks, newBlock) break } } return newBlock } // 校验区块函数 func VerifyBlock(difficulty int) { var resultBlock model.PowBlock for i := 0; i < len(common.PowCandidateBlocks); i++ { if IsBlockHashMatchDifficulty(common.PowCandidateBlocks[i], difficulty) { resultBlock = common.PowCandidateBlocks[i] break } continue } // 将候选的区块添加进区块链 common.PowGlobleBlocks = append(common.PowGlobleBlocks, resultBlock) // 广播已经产生新区块的信息 }
PoS伪代码:server/pos.go
package server import ( "block_test/common" "block_test/model" "math/rand" "strconv" "time" ) // 生成hash函数 func posCalculateHash(block model.PosBlock) string { return "hash" } //获取节点的balance func getCoinBlance(nodeAddress string) int { balance := 5 // 通过读取智能合约的上该节点的balance,这里先写死 return balance } // contain func stackRecordContainNodeAddress(stackRecord []string, nodeAddress string) bool { for i := 0; i < len(stackRecord); i++ { if stackRecord[i] == nodeAddress { return true } } return false } // StakeDistribution 股权分配, 方式1 func StakeDistribution() { var stackRecord []string for i := 0; i < len(common.PosCandidateBlocks); i++ { nodeAddress := common.PosCandidateBlocks[i].NodeAddress coinNum := getCoinBlance(nodeAddress) for j := 0; j < coinNum; j++ { if stackRecordContainNodeAddress(stackRecord, nodeAddress) { break } stackRecord = append(stackRecord, nodeAddress) } } common.StackRecord = stackRecord } // StakeDistribution2 股权分配, 我个人认为这样更合理 func StakeDistribution2() { var stackRecord []string for i := 0; i < len(common.PosCandidateBlocks); i++ { nodeAddress := common.PosCandidateBlocks[i].NodeAddress if stackRecordContainNodeAddress(stackRecord, nodeAddress) { continue } coinNum := getCoinBlance(nodeAddress) for j := 0; j < coinNum; j++ { stackRecord = append(stackRecord, nodeAddress) } } common.StackRecord = stackRecord } // PosGenerateBolck 区块生成 func PosGenerateBolck(oldBlack model.PosBlock, data string) { stackNum := len(common.StackRecord) index := rand.Intn(stackNum - 1) // 0 - stackNum(股权数) winner := common.StackRecord[index] // 胜出的 nodeAddress var newBlock model.PosBlock for i := 0; i < len(common.PosCandidateBlocks); i++ { if winner == common.PosCandidateBlocks[i].NodeAddress { newBlock.Timestamp = strconv.FormatInt(time.Now().Unix(), 10) newBlock.Index = oldBlack.Index + 1 newBlock.Data = data newBlock.PrevHash = oldBlack.Hash newBlock.Hash = posCalculateHash(newBlock) // other info common.PosGlobleBlocks = append(common.PosGlobleBlocks, newBlock) } } }
DPoS伪代码:server/dpos.go
package server import ( "block_test/common" "block_test/model" "math/rand" "sort" "time" ) // NeedRestVote DPos 是每过一个周期,进行重新投票排名 func NeedRestVote() bool { now := time.Now().Unix() if (now - common.BeforeTime) > int64(common.DPosCycle) { common.BeforeTime = now return true } return false } // SortByVotes 根据投票数来降序排序 func SortByVotes(witnessList []model.WitnessNode) { sort.Slice(common.WitnessList, func(i, j int) bool { return common.WitnessList[i].Votes > common.WitnessList[j].Votes }) } func SortWitnessList() { // 判断是否重新投票 if NeedRestVote() { for i := 0; i < len(common.WitnessList); i++ { // 进行投票 common.WitnessList[i].Votes = rand.Intn(1000) // 假装进行投票 } } //按投票数进行降序排序 SortByVotes(common.WitnessList) } // 判断是否是无效的见证者 func isBadNode(node model.WitnessNode) bool { // 判断规则 return false } // 检查见证者是否有效 func CheckBadNode(node model.WitnessNode) { for i := 0; i < len(common.WitnessList); i++ { if isBadNode(common.WitnessList[i]) { common.WitnessList = append(common.WitnessList[:i], common.WitnessList[i+1:]...) } } } func getNewNode() *model.WitnessNode { // 通过某种方式获取该新节点的信息 var node model.WitnessNode return &node } // 检测是否有新的节点进来 /* 个人理解: 第一种情况: 假如当前 witnessList 还有空间,即当前见证者的列表长度小于 witnessNum, 且有新的节点被投票,那么就把这个节点放进 witnessList 第二种情况: 假如当前 witnessList 没有空间,即当前见证者的列表长度等于 witnessNum, 且有新的节点被投票,且新的节点的被投票数大于 witnessList 中最小被投票的节点的被投票数 */ func isNewNodeComing() *model.WitnessNode { // 判断是否有新节点 node := getNewNode() if node != nil { return node } else { return nil } } // 把指针类型的节点转换成非指针类型 func getNode(pNode *model.WitnessNode) model.WitnessNode { var node model.WitnessNode node.NodeAddress = pNode.NodeAddress node.Votes = pNode.Votes node.Name = pNode.Name return node } // CheckNewWitnessNode 这个需要不断的检测,这在调用的时候,需要开启一个协程 func CheckNewWitnessNode() { for { num := len(common.WitnessList) if num < common.WitnessNum { newWitness := isNewNodeComing() if newWitness != nil { node := getNode(newWitness) common.WitnessList = append(common.WitnessList, node) } // 延迟0.1秒 time.Sleep(100 * time.Millisecond) } } } func getWitnessByIndex(witnessNode []model.WitnessNode) *model.WitnessNode { for i := 0; i < len(witnessNode); i++ { // 节点检验判断,如果没问题,直接返回该节点 if true { return &witnessNode[i] } } return nil } func generateBlock(node *model.WitnessNode) (model.DPosBlock, bool) { var block model.DPosBlock var timeOut bool timeOut = false // 初始化 timeOut 变量为 false // 区块产生逻辑,并需要对 timeOut 处理 return block, timeOut } func MakeBlock() model.DPosBlock { SortWitnessList() var resultBlock model.DPosBlock for { // 从上到下遍历,选择节点没问题的且票数最多的节点 witness := getWitnessByIndex(common.WitnessList) if witness == nil { break // 所有见证者出块都出了问题 } // 出块 block, timeOut := generateBlock(witness) resultBlock = block if timeOut { // 超时就轮到下一个 continue } // 广播block块出去,然后结束该轮,等待下一次开始 break } return resultBlock }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。