# 2，区块链共识算法

## 2.2 权益证明（PoS，Proof of Stake）

go的demo代码实现:

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 //持币时间
}

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

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++{
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的随机值
var rd =rand.Intn(15)

//选出挖矿的旷工
//设置当前区块挖矿地址为旷工
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.Tokens)

}


{1 new block 72e8838ad3bb761c7d3ba42c4e6bad86409dd3f4ce958c890409c4b9ddf44171 e4f9575cfb14ee146810862c9e5cc78ebff185f5888f428dbb945bd9060b31f7 2018-06-29 19:29:04.827332898 +0800 CST m=+0.000837770 0xc42007e0a0}
0x12341
2


## 2.3 委任权益证明（DPOS，Delegated Proof-of-Stake）

GO DEMO简单实现：

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))

var delegate *Node = new(Node)
delegate.Name = "Genis Block"
gene.delegate = delegate

return gene
}

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 //节点名称
}

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
}
}

//选出票数最多的前3位
func SortNodes() []Node  {
n:= NodeArr
for i := 0; i<len(n) ;i++  {
for j := 0; j < len(n)-1 ;j++  {
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++  {
//打印新区块信息
// var node *Node
node := lastBlock.delegate

lastBlock =  nodes[i].GenerateNewBlock(lastBlock,[]byte(fmt.Sprintf("new block %d",i)))
}

}


[{NODE 1 num 0} {NODE 2 num 0} {NODE 3 num 0} {NODE 4 num 0} {NODE 5 num 0} {NODE 6 num 0} {NODE 7 num 0} {NODE 8
num 0} {NODE 9 num 0} {NODE 10 num 0}]
[{NODE 1 num 3} {NODE 2 num 3} {NODE 3 num 3}]



## 2.4 拜占庭容错（PBFT，Practical Byzantine Fault Tolerance）

[1] 实用拜占庭容错（PBFT，Practical Byzantine Fault Tolerance）：首个提出的该问题解决方案称为“实用拜占庭容错”（PBFT），当前已被 Hyperledger Fabric 采用。PBFT 使用了较少（少于 20 个，之后会稍有增加）的预选定将军数，因此运行非常高效。它的优点是高交易通量和吞吐量，但是不足之处在于是中心化的，并用于许可网络。

[2] 联邦拜占庭协议（FBA，Federated Byzantine Agreement）：另一类拜占庭将军问题的解决方案是 FBA，已被 Stellar 和 Ripple 等代币使用。FBA 的通用理念是每个拜占庭将军负责自身的链、消息一旦到来，通过排序建立事实。在 Ripple 中，将军（验证者）是 Ripple 基金会预先选定的。在 Stellar 中，任何人都可以成为验证者，需要用户选择去相信哪个验证者。

PBFT基于拜占庭将军问题，一致性的确保主要分为这三个阶段：预准备（pre-prepare）、准备(prepare)和确认(commit)。流程如下图所示：

1.Request：请求端C发送请求到任意一节点，这里是0
2.Pre-Prepare：服务端0收到C的请求后进行广播，扩散至123
3.Prepare：123,收到后记录并再次广播，1->023，2->013，3因为宕机无法广播
4.Commit：0123节点在Prepare阶段，若收到超过一定数量的相同请求，则进入Commit阶段，广播Commit请求；
GO demo代码样例：

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",
"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
//激活主节点后，广播给其他节点,通过Ａpple向其他节点做广播

}

}

//由主节点向其他节点做广播
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){
//分发给其他三个人
}

}

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反馈给浏览器

}
}

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

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

}


./pbft Apple
./pbft IBM
./pbft MS

okokok

## 2.5 分布式一致性协议- RAFT算法

Raft 的解决方案大概可以理解成 先在所有将军中选出一个大将军，所有的决定由大将军来做。选举环节：比如说现在一共有3个将军 A, B, C，每个将军都有一个随机时间的倒计时器，倒计时一结束，这个将军就会把自己当成大将军候选人，然后派信使去问其他几个将军，能不能选我为总将军？假设现在将军A倒计时结束了，他派信使传递选举投票的信息给将军B和C，如果将军B和C还没把自己当成候选人（倒计时还没有结束），并且没有把选举票投给其他，他们把票投给将军A，信使在回到将军A时，将军A知道自己收到了足够的票数，成为了大将军。在这之后，是否要进攻就由大将军决定，然后派信使去通知另外两个将军，如果在一段时间后还没有收到回复（可能信使被暗杀），那就再重派一个信使，直到收到回复。

（1）Raft 节点状态

（1）收到选举的请求

（2）复制日志 Log Replication

1）正常情况下选主
[图片上传失败...(image-8988e9-1595654507761)]

（3）2.3 多个 Candidate 情况下的选主

Leader 进行 Heartbeat， Candidate 收到后状态自动转为 Follower，完成选主。

## 2.6 有向无环图（DAG，Directed Acyclic Graphs）

DAG 存在多种变体，取决于：
· 如何选取前期区块验证的算法，也称为“Tip 选择算法”。
· 交易完成的顺序。
· 如何抵达完成状态。

1 Tangle（IOTA）

image

2 Hashgraph

3 Holochain

4 Block-Nano

5 SPECTRE

6 ByteBall

MC 允许在交易间定义全序关系，即更早加入（直接或间接）MC 的交易，必定更早出现在全序中。如果存在“双重支付”问题，那么将视较早出现在全序中的交易版本为有效的，而其它所有的交易均被视为是无效的。

· MC 上相邻交易的证人列表要么完全相同，要么只存在一个突变。

· 与其它链相比，MC 中为经过最多数量的由见证人认证的交易。

ByteBall 也是首个在系统中包含 Oracle 的平台。Oracle 是在 DAG 中添加智能合约功能所必需的。

## 2.7 容量证明（PoC，Proof of Capacity）

PoSpace 非常类似于 PoW，只是使用存储替代了 Pow 中的计算。PoSpace 与 MHF 和可回收性证明（PoR，Proof of Retrievability）有关，但也在很大程度上存在着差异。

PoSpace 是由证明者 （Prover） 发送给验证者 （Verifier） 的一小块数据，该数据确认了证明者已经保留了一定量的空间。出于实用性上的考虑，验证过程需要尽量高效，即消耗尽可能少的空间和时间。出于公平性上的考虑，如果验证者没有保留所声明数量的空间，那么它应该难以通过验证。PoSpace 的一种实现方式是通过使用一个难以实现 Pebbling 的图。验证者请求证明者构建对一个“非 Pebbling 图”标记。证明者提交标记，进而验证者请求证明者在提交中开放多个随机位置。

## 2.8 延迟工作量证明（dPoW，Delayed Proof-of-Work）、

image.png

dPoW 系统中有两种类型的节点：公证人节点和正常节点。64 个公证人节点是由 dPoW 区块链的权益持有者（stakeholder）选举产生的，它们可从 dPoW 区块链向所附加的 PoW 区块链添加经公证确认的块。一旦添加了一个块，该块的哈希值将被添加到由 33 个公证人节点签署的 Bitcoin 交易中，并创建一个哈希到 Bitcoin 区块链的 dPow 块记录。该记录已被网络中的大多数公证人节点公证。

image.png

dPoW 系统在设计上支持区块链在没有公证人节点的情况下继续运行。在这种情况下，dPoW 区块链可以基于初始的共识方法继续运行，但将不再具有所附着区块链增添的安全。

## 2.9 权威证明（PoA，Proof-of-Authority）

1. 其身份必须在链上得到正式验证，信息可在公有可用域中交叉验证。
2. 其资格必须难以获得，这样所得到的验证块的权利才弥足珍贵（例如，潜在的验证者需要获得公证书）。
3. 建立权威的检查和程序必须完全统一。

## 2.11. 声誉证明（PoR，Proof of Reputation）

PoR 共识模型依赖参与者在保持网络安全中的声誉。参与者（区块签名者）必须具有足够重要的声誉。一旦他们尝试欺骗系统，那么他们将要面对严重的财政上的和自己名声上的后果。这是一个相对的概念，如果他们被抓到试图欺骗，那么几乎所有的业务将会受到严重的影响。规模越大的企业，通常将会失去更多。这样，相比使用更少的企业（即更小规模的商业），规模更大的企业更易于被选定。

## 2.12. 所用时间证明（PoET，Proof of Elapsed Time）

PoET 的工作机制如下：网络中的每位参与节点都必须等待一个随机选取的时期，首个完成设定等待时间的节点将获得一个新区块。区块链网络中的每个节点会生成一个随机的等待时间，并休眠一个设定的时间。最先醒来的节点，即具有最短等待时间的节点，唤醒并向区块链提交一个新区块，然后广播必要的信息到整个对等网络中。同一过程将会重复，以发现下一个区块。

PoET 理念是由著名的芯片制造巨头 Intel于 2016 年早期提出的。Intel 为解决“随机领导者选举”的计算问题，实现了一个可用的高科技工具。

PoET 通过控制代价实现了共识过程，该代价依然是与从过程中获得的价值成正比。这是保证加密货币经济持续繁荣的一个关键需求。

## 2.13 历史证明（PoHistory，Proof of History）

PoHistory 是一种高频可验证延迟函数（VDF，Verifiable Delay Function）。VDF 求值需要完成特定数量的顺序步骤，然后生成一个唯一的输出。该输出可被高效地和公开地验证。

VDF 的一个特定实现使用了持续运行于其上的顺序抗预映射哈希（Pre-image Resistant Hash），其中前一次循环生成的输出将用于下一次循环的输入。计数和当前输出形成周期性记录。

## 2.16 烧毁证明（PoBurn，Proof of Burn）

PoBurn 有多种实现方式，矿工可以烧毁原生的货币，或者烧毁一些其它区块链的货币，例如比特币等。烧毁的代币越多，用户就越有机会被选中去挖掘下一个区块。

## 2.23. 授权拜占庭容错算法（dBFT，Delegated Byzantine Fault Tolerance）

dBFT 可为具有个共识节点的共识系统提供\（f = {{n-1} \over 3}\）容错。这种容错也涵盖了安全性和可用性、不受将军和拜占庭错误影响，并且适合任何网络环境。dBFT 具有很好的最终性（finality），这意味着一旦最终确认，区块将不可分叉，交易将不可再撤销或是回滚。

Neo 的 dBFT 机制生成一个区块需 15 到 20 秒钟。交易吞吐量测定约为 1000 TPS。这对于公共区块链而言，这是很好的性能。通过一定优化，dBFT 具有达到一万 TPSS 的潜力，这样就可支持大规模的商业应用。

dBFT 中加入了数字身份技术，这意味着 bookkeeper 可以是真实的个人，也可以是某些机构。因此，dBFT 根据存在于其本身之中的司法判决，可以冻结、撤销、继承、检索和拥有代币兑换权。它有利于实现合规金融资产在 Neo 网络中的注册。Neo 网络从设计上，就是在必要时为此提供支持。

## 2.25 置信度证明（PoB，Proof of Believability）

PoB 共识协议使用一种分片内“可信度优先”的方法。该协议将所有的验证者分为两组，一组是可信的联盟，另一组是正常的联盟。在第一阶段，可信的验证者快速地处理交易。之后在第二阶段，普通验证者对交易做抽样并验证，提供最终结果，确保可验证性。节点被选入可信联盟的机会是由可信度分值确定的。可信度分值由多个因素计算，包括令牌余额、对社区的贡献、评论等。具有较高可信度分值的人，更有可能被选入可信联盟。可信验证者遵循一定的程序，决定已提交的交易及其订单的集合，并按顺序处理它们。可信验证者也会构成一些较小的组，甚至可以每组一名验证者。交易将在这些可信验证者之间随机分配。因此，PoB 会产生具有极低延迟的较小区块。

# 3，参考

（1）分布式共识算法专栏 - 汇集各种共识算法
https://recomm.cnblogs.com/blogpost/11284374?page=1

（2）区块链共识算法全面详解
http://www.elecfans.com/blockchain/843819.html

（3）共识算法DPOS原理及实现
https://www.meiwen.com.cn/subject/hxqzyftx.html

（4）拜占庭PBFT简单实现
https://www.meiwen.com.cn/subject/prvjuftx.html