共识算法

共识算法

POW 工作量证明

  • 暴力破解的方式

实现原理

  • 关键字:
    • 难度系数 Difficulty
    • 随机值 Nonce
  • 将新生成的区块信息(包含上一个hash,nonce,difficulty)等信息通过Sha256计算hash值,再对hash值进行判断,判断前缀是否符合难度系数,如难度系数为5,代表生成的hash值前面有5个0,则代表这个区块是一个合法区块,如果区块不合校验规则,则Nonce++ 的方式不停的重试

区块校验

  • 区块结构语法有效
  • 验证pow,区块头的hash满足难度系数
  • 区块时间戳在2小时内
  • 验证区块大小
  • 验证区块内交易的合法性
package main

import (
    "strconv"
    "time"
    "crypto/sha256"
    "strings"
    "encoding/hex"
    "fmt"
)

//pow 挖矿算法

//定义难度系数
const difiiculty = 4

type Block struct {
    Index      int // 区块高度
    TimeStamp  int64
    Data       string //交易记录
    Hash       string
    Prehash    string
    Nonce      int
    Difficulty int //难度系数
}

//创建区块链
var BlockChain []Block

//创世区块
func GenesisBlock() *Block {

    var geneBlock = Block{0, time.Now().Unix(), "", "", "", 0, difiiculty}
    geneBlock.Hash = hex.EncodeToString(BlockHash(geneBlock))

    return &geneBlock

}



func BlockHash(block Block) []byte {
    re := strconv.Itoa(block.Index) + strconv.Itoa(int(block.TimeStamp)) + block.Data + block.Prehash +
        strconv.Itoa(block.Nonce) + strconv.Itoa(block.Difficulty)

    h := sha256.New()
    h.Write([]byte(re))
    hashed := h.Sum(nil)

    return hashed


}

func isBlockValid(block Block) bool  {
    prefix := strings.Repeat("0", block.Difficulty)
    return strings.HasPrefix(block.Hash, prefix)
}

//创建新区块 pow挖矿
func CreateNewBlock(lastBlock *Block, data string) *Block {
    var newBlock Block
    newBlock.Index = lastBlock.Index + 1
    newBlock.TimeStamp = time.Now().Unix()
    newBlock.Data = data
    newBlock.Prehash = lastBlock.Hash
    newBlock.Difficulty = difiiculty
    newBlock.Nonce = 0
    //开挖-当前区块的hash值的前面的0的个数与难度系数值相同
    for {
        //计算hash
        cuhash := hex.EncodeToString(BlockHash(newBlock))
        fmt.Println("挖矿中",cuhash)
        newBlock.Hash = cuhash
        if isBlockValid(newBlock) {

            //校验区块
            if VerflyBlock(newBlock, *lastBlock) {
                fmt.Println("挖矿成功")
                return  &newBlock
            }
        }
        
        newBlock.Nonce ++

    }
}


//校验新的区块是否合法
func VerflyBlock(newblock Block, lastBlock Block) bool  {
    if lastBlock.Index +1 !=newblock.Index {
        return false
    }
    if newblock.Prehash !=lastBlock.Hash {
        return false
    }
    return true

}

func main()  {

    var genBlock = GenesisBlock()
    
    newBlock := CreateNewBlock(genBlock,"新区块")
    fmt.Println(newBlock)

}

优点:

  • 去中心化
  • 算法简单

缺点

  • 浪费资源(算力)
  • 散列算法固定(Sha256),后续会遭到破解

POS 权益证明

  • 核心是通过币龄,铸造区块来获取币同时也会减小币龄
  • 持币有利息
  • 累积币龄最大的为主链

实现原理

  • 关键字:

    • 币龄: 每个币每天产生1币龄, 拥有m个币,持有n天,则CoinAge为 m*n ,币龄越大出块的概率越高
  • 不同的旷工拥有的币龄不同,币龄越大的人,在整个区块链网络中所占的百分比也就越大,因此随机筛选一位作为旷工的概率也就越大

  • 当某个旷工挖取到区块之后,会得到奖励 n个币 ,同时会减少币龄,既 获取币,减少了币龄

package main

import (
    "time"
    "strconv"
    "crypto/sha256"
    "math/rand"
    "fmt"
    "encoding/hex"
)

//实现pos挖矿的原理

type Block struct {
    Index int
    Data string //
    PreHash string
    Hash string
    Timestamp string
    //记录挖矿节点
    Validator *Node

}

func genesisBlock() Block  {

    var genesBlock  = Block{0, "Genesis block","","",time.Now().String(),&Node{0, 0, "dd"}}
    genesBlock.Hash = hex.EncodeToString(BlockHash(&genesBlock))
    return genesBlock
}

func BlockHash(block *Block) []byte  {
    record := strconv.Itoa(block.Index) + block.Data + block.PreHash + block.Timestamp + block.Validator.Address
    h := sha256.New()
    h.Write([]byte(record))
    hashed := h.Sum(nil)

    return hashed
}

//创建全节点类型
type Node struct {
    Tokens int //持币数量
    Days int //持币时间
    Address string //地址
}


//创建5个节点
//算法的实现要满足 持币越多的节点越容易出块
var nodes = make([]Node, 5)
//存放节点的地址
var addr = make([]*Node, 15)


func InitNodes()  {

    nodes[0] = Node{1, 1, "0x12341"}
    nodes[1] = Node{2, 1, "0x12342"}
    nodes[2] = Node{3, 1, "0x12343"}
    nodes[3] = Node{4, 1, "0x12344"}
    nodes[4] = Node{5, 1, "0x12345"}

    cnt :=0
    for i:=0;i<5;i++ {
        for j:=0;j<nodes[i].Tokens * nodes[i].Days;j++{
            addr[cnt] = &nodes[i]
            cnt++
        }
    }

}

//采用Pos共识算法进行挖矿
func CreateNewBlock(lastBlock *Block, data string) Block{

    var newBlock Block
    newBlock.Index = lastBlock.Index + 1
    newBlock.Timestamp = time.Now().String()
    newBlock.PreHash = lastBlock.Hash
    newBlock.Data = data


    //通过pos计算由那个村民挖矿
    //设置随机种子
    rand.Seed(time.Now().Unix())
    //[0,15)产生0-15的随机值
    // FIXME 随机的方式不正确,正确的应该是范围命中的方式
    var rd =rand.Intn(15)

    //选出挖矿的旷工
    node := addr[rd]
    //设置当前区块挖矿地址为旷工
    newBlock.Validator = node
    //简单模拟 挖矿所得奖励
    node.Tokens += 1
    newBlock.Hash = hex.EncodeToString(BlockHash(&newBlock))
    return newBlock
}

func main()  {

    InitNodes()

    //创建创世区块
    var genesisBlock = genesisBlock()

    //创建新区快
    var newBlock = CreateNewBlock(&genesisBlock, "new block")

    //打印新区快信息
    fmt.Println(newBlock)
    fmt.Println(newBlock.Validator.Address)
    fmt.Println(newBlock.Validator.Tokens)

}

优点

  • 相比pow 共识缩短
  • 资源不浪费

缺点


DPOS Delegated Proof of Stake 委托权益证明

  • 让每个持有币的人进行委托选举,选举投票最多的n个人将会成为代表(矿池),生成区块,类似于人大代表,若未生产出区块,则会被除名,重新投票选举新的超级节点

原理

  • 每个持币节点具有选择权,对网络中的节点进行投票选举,前n个节点会作为超级节点行使POS的权利,生成区块
  • Q: 超级节点具有什么功能:
    • A: 超级节点可以配置网络中的利息,出块时间等
  • Q: 超级节点什么时候剔除
    • A: 当超级节点无法履行其职责的,如无法生成区块时,会被剔除,重新选举
package main

import (
    "fmt"
    "math/rand"
    "time"
    "strconv"
    "crypto/sha256"
    "encoding/hex"
)

type Block struct {
    Index int
    Timestamp string
    Prehash string
    Hash string
    Data []byte

    delegate *Node// 代理 区块由哪个节点挖出
}


func GenesisBlock()  Block {
    gene := Block{0, time.Now().String(),"", "", []byte("genesis block"), nil}

    gene.Hash = string(blockHash(gene))

    return Block{}
}

func blockHash(block Block) []byte  {

    record := strconv.Itoa(block.Index) + block.Timestamp + block.Prehash + hex.EncodeToString(block.Data)

    h := sha256.New()
    h.Write([]byte(record))
    hashed := h.Sum(nil)
    return hashed
}


//节点类型
type Node struct {
    Name  string //节点名称
    Votes int    // 被选举的票数
}

func (node *Node)GenerateNewBlock(lastBlock Block, data []byte) Block  {

    var newBlock = Block{lastBlock.Index+1, time.Now().String(), lastBlock.Hash, "", data, nil}

    newBlock.Hash = hex.EncodeToString(blockHash(newBlock))
    newBlock.delegate = node
    return newBlock

}

//创建节点
var NodeArr = make([]Node,10)
func CreateNode() {

    for i := 0; i < 10; i++ {
        name := fmt.Sprintf("NODE %d num", i+1)
        NodeArr[i] = Node{name, 0}
    }

}

//简单模拟投票
func Vote()  {
    for i := 0; i < 10; i++ {
        rand.Seed(time.Now().UnixNano())
        vote := rand.Intn(10) + 1
        NodeArr[i].Votes = vote
    }
}


//选出票数最多的前3位
func SortNodes() []Node  {
    n:= NodeArr
    for i := 0; i<len(n) ;i++  {
        for j := 0; j < len(n)-1 ;j++  {
            if n[j].Votes < n[j+1].Votes {
                n[j],n[j+1] = n[j+1],n[j]
            }
        }
    }

    return n[:3]
}


func main() {

    CreateNode()
    fmt.Println(NodeArr)
    Vote()
    nodes := SortNodes()

    fmt.Println(nodes)


    //创建创世区块
    gene := GenesisBlock()

    lastBlock := gene
    for i:= 0; i< len(nodes) ;i++  {
        lastBlock =  nodes[i].GenerateNewBlock(lastBlock,[]byte(fmt.Sprintf("new block %d",i)))

    }
}

优点

  • 提升共识效率,处理效率

缺点

  • 权利集中在超级节点,不合公链的理念,并且某些节点可以一直成为超级节点

BFT

  • 既拜占庭容错,用于解决分布式对等网络节点间通信容错问题
  • Q: 什么是拜占庭容错:
    • A: 由于硬件错误、网络拥塞或断开以及遭到恶意攻击,计算机和网络可能出现不可预料的行为 ;可以认为是叛徒节点伪造请求

PBFT

  • 用于解决BFT性能低下问题而出现

Raft

  • 与PBFT的区别在于,RAFT不支持 作恶节点,只支持故障节点,并且可支持的故障节点数为 (N-1)/2 N为集群节点总量,既可用节点需要为半数以上

  • 而PBFT不仅支持故障节点,也支持作恶节点,最大容错节点数为 (N-1)/3

  • 白话讲RAFT和PBFT的区别为:

    • RAFT 遵循领导的话,领导的话维诺不从,当领导任期到了,重新选一个新的领导作为发言人
      
    • PBFT 认为一切都不可信,领导的命令会征询旗下的其他节点,当超过2f+1个节点认可,则会认为该命令可信
      f指的是故障节点,故障节点数<= (N-1)/3
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值