精华内容
下载资源
问答
  • DPoS算法
    2021-09-13 18:53:34


    前言


    提示:以下是本篇文章正文内容,下面案例可供参考

    一、DPoS——股份授权证明

    DPoS 基本原理
    ⚫ PoS 机制的加密货币,每个节点都可以操作区块,并按照个人的持股比例获得“利
    息”
    ⚫ DPoS 是由被社区选举的可信帐户(受托人,得票数排行前 101 位)来创建区块,
    为了成为正式受托人,用户要去社区拉票,获得足够多用户的信任,用户根据自己
    持有的加密货币数量占总量的百分比来投票
    ⚫ DPoS 机制类似于股份制公司,普通股民进不了董事会,要投票选举代表(受托人)
    代他们做决策
    ⚫ 这 101 个受托人可以理解为 101 个矿池,而这 101 个矿池彼此的权利是完全相等的
    ⚫ 那些握着加密货币的用户可以随时通过投票更换这些代表(矿池),只要他们提供
    的算力不稳定,计算机宕机、或者试图利用手中的权力作恶,他们将会立刻被愤怒
    的选民门踢出整个系统,而后备代表可以随时顶上去

    二、go语言简单实现

    package main
    
    import (
    	"time"
    	"strconv"
    	"encoding/hex"
    	"crypto/sha256"
    	"fmt"
    	"math/rand"
    )
    
    //实现投票的功能
    
    //定义全节点
    type Node struct {
    	//节点名称
    	Name string
    	//被选举的票数
    	Votes int
    }
    
    //区块
    type Block struct {
    	Index     int
    	Timestamp string
    	Prehash   string
    	Hash      string
    	Data      []byte
    	//代理人
    	delegate *Node
    }
    
    func firstBlock() Block {
    	gene := Block{0, time.Now().String(),
    		"", "", []byte("first block"), nil}
    	gene.Hash = string(blockHash(gene))
    	return gene
    }
    
    //计算哈希
    func blockHash(block Block) []byte {
    	hash := strconv.Itoa(block.Index) + block.Timestamp +
    		block.Prehash + hex.EncodeToString(block.Data)
    	h := sha256.New()
    	h.Write([]byte(hash))
    	hashed := h.Sum(nil)
    	return hashed
    }
    
    //生成新的区块
    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
    }
    
    //创建10个节点
    var NodeAddr = make([]Node, 10)
    
    //创建节点
    func CreateNode() {
    	for i := 0; i < 10; i++ {
    		name := fmt.Sprintf("节点 %d 票数", i)
    		//初始化时票数为0
    		NodeAddr[i] = Node{name, 0}
    	}
    }
    
    //简单模拟投票
    func Vote() {
    	for i := 0; i < 10; i++ {
    		rand.Seed(time.Now().UnixNano())
    		time.Sleep(100000)
    		vote := rand.Intn(10000)
    		//为10个节点投票
    		//每个节点的票数,就是随机出来的值,0~9999
    		NodeAddr[i].Votes = vote
    		fmt.Printf("节点 [%d] 票数 [%d]\n", i, vote)
    	}
    }
    
    //一共10个节点,选出票数最多的前三名
    func SortNodes() []Node {
    	//10个节点
    	n := NodeAddr
    	//外层遍历节点个数
    	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() {
    	//初始化10个全节点
    	CreateNode()
    	fmt.Printf("创建的节点列表: \n")
    	fmt.Println(NodeAddr)
    	fmt.Print("节点票数: \n")
    	//投票
    	Vote()
    	//选出前三名
    	nodes := SortNodes()
    	fmt.Print("获胜者: \n")
    	fmt.Println(nodes)
    	//创世区块
    	first := firstBlock()
    	lastBlock := first
    	fmt.Print("开始生成区块: \n")
    	for i := 0; i < len(nodes); i++ {
    		fmt.Printf("[%s %d] 生成新的区块\n", nodes[i].Name, nodes[i].Votes)
    		lastBlock = nodes[i].GenerateNewBlock(lastBlock, []byte(fmt.Sprintf("new Block %d", i)))
    	}
    }
    
    
    更多相关内容
  • DPOS共识算法白皮书

    2018-04-22 14:28:01
    DPOS共识算法白皮书,即石墨烯技术,第三代共识算法,依然有缺点(DPOS共识算法--缺失的白皮书 英文 )
  • 一个简单的dpos(委托权益证明)共识算法的实现
  • 基于以太坊实现EOS的dpos共识算法,实现go版本EOS的dpos公链
  • 区块链中最重要的便是共识算法,比特币使用的是POW(Proof of Work,工作量证明),以太币使用的POS(Proof of Stake,股权证明)而EOS使用的是BFT-DPOS。 什么是BFT-DPOS呢?即拜占庭容错式的委任权益证明。 要想...
  • 委任权益证明Delegated Proof of Stake(简称DPoS)是比特股BitShares采用的区块链公识算法。在加密货币技术中,使用共识算法来保证整个区块链网络的安全可靠,著名的共识算法包括比特币网络使用的工作量证明PoW,...
  • dpos 委托状态证明示例 共识算法的DPoS最少4个委托 如何开始? $去建立main.go $ ./main 3000 $打开新终端,cp chain_3000.dbblockchain_3001.db,./main 3001 $打开新终端,cp chain_3000.dbblockchain_3002.db,....
  • 美图基于以太坊DPoS算法技术实现.pptx
  • POSDAO智能合约 在POSDAO共识算法的实现。 关于 POSDAO是一种权益证明(POS)算法,实现为分散的自治组织(DAO)。 它旨在为公共链提供分散,公平和节能的共识。 该算法可作为以Solidity编写的一组智能合约来工作。...
  • #资源达人分享计划#
  • 基于改进的DPoS区块链共识机制的研究与应用计算机分析.docx
  • 双钴 下一代区块链=) 材料 一般的 智能合约 基准 问题 坚固性 模组 坚固性
  • DPOS代码实现

    千次阅读 2022-02-07 16:25:44
    本篇文章主要是DPOS共识的简单实现,其中有许多地方都做了简化。DPOS的原理已在上篇文章中描述过,如果对DPOS的原理不太清晰的可以进行查看。文章地址:共识算法学习总结。 代码实现的功能比简单,主要有:添加区块...

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

    代码实现的功能比简单,主要有:添加区块,代理者的投票以及查看所有的代理者。代码中使用bolt数据库进行数据的持久化,p2p模块主要使用了libp2p。

    创建一个区块链

    在系统开始时,要创建一条区块链。该函数首先初始化数据库,然后生成创世块并保存在数据中。

    func NewBlockchain()  {
    	// 初始化数据库
    	setupDB()
    	db := common.GetDB()
    	defer db.Close()
    		// 生成创世区块
    	block := genGenesisBlock()
    	err := db.Update(func(tx *bolt.Tx) error {
    		bucket := tx.Bucket([]byte(common.BlocksBucket))
    		err = bucket.Put([]byte("lastHash"), []byte(block.Hash))
    		err = bucket.Put([]byte(block.Hash), serializeBlock(block))
    		if err != nil {
    			log.Panic(err)
    		}
    		return nil
    	})
    	log.Println(">>> 创建区块链成功")
    }
    

    添加一个区块

    初始化区块链后就可以进行区块的添加。该函数首先启动共识模块和p2p模块,接着打包区块。为了简化代码,这里直接创建了区块,实际上应该由特定的代理者进行打包创建区块。接着把创建的区块添加到候选区块通道中,等待共识模块的确认。

    func add(data string, port int, target string)  {
    	log.Println(">>> 开始添加区块链")
    	// 启动共识
    	go consensus.Start()
    	log.Println(">>> 启动共识...")
    
    	// 启动p2p节点
    	go p2p.Start(port, target, 0)
    	log.Println(">>> 启动p2p网络...")
    
    
    	// 打包区块
    	newBlock := common.Block{}
    	newBlock.Height = getLastHeight() + 1
    	newBlock.Data = data
    	newBlock.Timestamp = time.Now().String()
    	newBlock.PrevHash = getLastBlockHash()
    	newBlock.Hash = calculateBlockHash(newBlock)
    	
    	// 新生成的区块添加到候选区块通道中,等待共识确认
    	common.CandidateBlokcs <- newBlock
    }
    

    DPOS共识

    该函数主要做了两件事:循环读取候选区块通道并追加到临时区块切片中,另一件是读取临时区块切片中的数据,并选择代理人打包区块。

    func Start() {
    
    	// 循环读取候选区块通道中的区块信息
    	go func() {
    		for{
    			for candidate := range common.CandidateBlokcs{
    				common.TempBlocks = append(common.TempBlocks, candidate)
    			}
    		}
    	}()
    	// 开始共识
    	for  {
    		if len(common.TempBlocks) > 0{
    			for _, block := range common.TempBlocks{
    				// 挑选验证者
    				delegate := getDelegate()
    				block.Validator = delegate.Address
    				// 序列化
    				result, err := json.Marshal(block)
    				if err != nil{
    					log.Fatal("marshal block error: ", err)
    				}
    				//添加到数据库
    				db := common.GetDB()
    
    				db.Update(func(tx *bolt.Tx) error {
    					bucket := tx.Bucket([]byte(common.BlocksBucket))
    					bucket.Put([]byte(block.Hash), result)
    					err = bucket.Put([]byte("lastHash"),[]byte(block.Hash))
    					return nil
    				})
    				log.Println(">>> 添加区块链成功!")
    				db.Close()
    				
    				common.TempBlocks = nil
    			}
    		}
    	}
    }
    

    获取代理人

    这里假设得票数最高的两个代理人进行随机出块。

    func getDelegate() common.Delegate {
    	// 从数据库中查出所有的代理人
    	var delegates []common.Delegate
    
    	db := common.GetDB()
    	defer db.Close()
    
    	db.View(func(tx *bolt.Tx) error {
    		bucket := tx.Bucket([]byte(common.PeerBucket))
    		cursor := bucket.Cursor()
    		for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
    			delegate := unmarshalDelegate(v)
    			delegates = append(delegates, delegate)
    		}
    		return nil
    	})
    
    	// 挑选候选人,假设取得票数最高的两个代理人
    	quickSort(0, len(delegates) - 1, delegates)
    	rand.Seed(time.Now().Unix())
    	randNumber := rand.Intn(2)
    
    	// 返回指定的代理人
    	return delegates[randNumber]
    }
    

    启动P2P网络

    该函数首先创建一个libp2p节点,端口可以自己指定。如果不指定目标地址target,创建节点完毕后就等待新的连接。如果指定目标地址target,创建完节点后会连接到目标地址。seed为随机数种子。

    func Start(port int, target string, seed int64) {
    
    	// 创建一个libp2p节点
    	ha, err := makeBasicHost(port, seed)
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	// 判断是否有目标地址
    	if target == "" {
    		log.Println(">>> 等待新的连接")
    		// 设置stream
    		ha.SetStreamHandler("/p2p/1.0.0", handleStream)
    		select {}
    	}else{
    
    		// 设置stream
    		ha.SetStreamHandler("/p2p/1.0.0", handleStream)
    
    		// 获取peer ID
    		ipfsaddr, err := ma.NewMultiaddr(target)
    		if err != nil {
    			log.Fatalln(err)
    		}
    		info, err := peer.AddrInfoFromP2pAddr(ipfsaddr)
    		if err != nil {
    			log.Println(err)
    		}
    
    		// 把节点添加到peer store中,以便libp2p连接这个节点
    		ha.Peerstore().AddAddr(info.ID, info.Addrs[0], peerstore.PermanentAddrTTL)
    
    		// 创建当前节点与目标节点的stream
    		s, err := ha.NewStream(context.Background(), info.ID, "/p2p/1.0.0")
    		if err != nil {
    			log.Fatalln(err)
    		}
    		
    		// 读写stream中的数据
    		rw := bufio.NewReadWriter(bufio.NewReader(s), bufio.NewWriter(s))
    		go writeData(rw)
    		go readData(rw)
    
    		select {}
    	}
    	return
    }
    

    查看网络中的节点

    查看网络中的节点比较简单,只是查询数据库并进行打印。

    func view()  {
    	var delegates []common.Delegate
    
    	db := common.GetDB()
    	defer db.Close()
    	db.View(func(tx *bolt.Tx) error {
    		bucket := tx.Bucket([]byte(common.PeerBucket))
    		cursor := bucket.Cursor()
    		for k, v := cursor.First(); k != nil; k, v = cursor.Next(){
    			delegate := unmarshalDelegate(v)
    			delegates = append(delegates, delegate)
    		}
    		return nil
    	})
    	spew.Dump(delegates)
    }
    

    投票

    进行投票时,首选输入代理人的地址,然后输入投票的数量。

    func Vote( address string, voteNum int)  {
    	if address == "" {
    		log.Fatal("节点名称不能为空")
    		return
    	}
    	if voteNum < 0 {
    		log.Fatal("最小投票数为1")
    		return
    	}
    	
    	var delegate common.Delegate
    	db := common.GetDB()
    	defer db.Close()
    	db.Update(func(tx *bolt.Tx) error {
    		bucket := tx.Bucket([]byte(common.PeerBucket))
    		result := bucket.Get([]byte(address))
    		err := json.Unmarshal(result, &delegate)
    		if err != nil{
    			log.Fatal("反序列化代理人错误: ", err)
    		}
    		log.Println(delegate)
    		delegate.Number += voteNum
    		mashalResult, err := json.Marshal(delegate)
    		if err != nil{
    			log.Fatal("序列化代理人错误: ", err)
    		}
    		err = bucket.Put([]byte(address), mashalResult)
    		if err != nil{
    			log.Fatal("更新代理人票数错误: ", err)
    		}
    		return nil
    	})
    }
    

    运行截图

    在这里插入图片描述

    最后

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

    展开全文
  • 区块链核心技术:DPoS共识机制

    千次阅读 2021-08-23 14:47:08
    DPoS 全称是 Delegated Proof of Stake,中文翻译过来是代理权益证明。 从 BM 开始聊起的故事 我们聊 DPoS 时,为什么要从 BM 聊起呢,其实,这和聊比特币绕不开中本聪一样,DPoS 是 BM 一手创造的。DPoS 不是独立...

    DPoS 全称是 Delegated Proof of Stake,中文翻译过来是代理权益证明。

    从 BM 开始聊起的故事

    我们聊 DPoS 时,为什么要从 BM 聊起呢,其实,这和聊比特币绕不开中本聪一样,DPoS 是 BM 一手创造的。DPoS 不是独立提出的共识算法,而是直接被 BM 应用到比特股项目中,在稳定运行了 3 年多后,又接着被 BM 构造成可复用的区块链工具箱:石墨烯。

    虽然应用得很早,但 DPoS 算法直到 2017 年才被 BM 单独拎出来作了一篇“DPoS 技术白皮书”,这期间伴随着比特股、Steemit、EOS 三个项目的依次发布。那么到底 BM 是谁,市场上对这个人的评价为什么富有争议呢?或许我们从了解 BM 开始,才能体会到 DPoS 的精髓。

    我们在前面的文章中曾简单提过 BM,BM 的本名是 Daniel Larimer,由于他的 GitHub 昵称是 ByteMaster,所以才被称作 BM。BM 是比特股、Steemit、EOS 项目的创始人。与年少成名 V 神的辍学经历不同,BM 2003 年毕业于弗吉尼亚理工学院,获得计算机学士学位,算是正经的科班出身。

    BM 曾直言不讳地说到:“我的人生目标就是找到自由市场的方案来保护生命、自由和财产”。他认为要达成这个目标,就必须要从货币开始。我们在数字货币一节提到过,无论是贵金属还是信用货币,都是历史的必然,所以在选择使用什么货币上,BM 认为不一定是美元,他希望的是:构造一种自由安全的数字货币。

    2009 年,他怀揣梦想开始了数字货币的事业,他先发现了比特币,于是不遗余力地推广着这个项目。然而在 2010 年,BM 指出中本聪 10 分钟一次的交易确认时间太长了,这样的话,性能会是一个瓶颈,然而这样的想法却遭到了中本聪的暴击:看不懂就算了,我没时间搭理你。

    于是,BM 觉得比特币不是希望,便着手开发第一个项目——比特股,同时创造出 DPoS,把自己的高性能共识算法形成了实践。在这里,我们可以看出 DPoS 与其他共识机制的第一个区别,就是交易确认时间短。

    2014 年,当 V 神还在到处奔走,开始发起以太坊项目的众筹时,当很多项目还是基于比特币的微创新时,比特股就已经横空出世了。所以比特股一跃成为了当时的明星项目,它的口号是“Beyond Bitcoin”,在这里我们可以感受到极强的攻击性和目的性,也正因为如此,日益强大的比特币社区被树在了它的对立面。

    比特股一共有 2 个版本,比特股在 1.0 版本之前,某些版本甚至都没有提供向下兼容。虽然后来正式发布了 1.0 版本,似乎并没有改善多少。糟糕的使用体验,庞大的系统资源开销,还是让尝鲜的用户逐渐流失了。这时候 BM 利用了自己手里超过 1/3 的记账节点,在没有达成社区共识的情况下,强行增发了比特股总量。这一招几乎就是比特股项目的灭顶之灾,社区人就此纷纷退出。

    虽然社区萎靡,BM 还是继续了开发工作,将比特股升级到了 2.0,它的易用性和稳定性勉强可以满足正常使用。随着比特股 2.0 的发布,BM 也同时发布了石墨烯工具箱。尽管在技术上提供了改进,但比特股社区最终选择让 BM 离开比特股项目,比特股回到了另一位币圈大佬——巨蟹的手里。随后比特股的发展陷入了长期的低迷,长期在 2 分,最多到 2 角钱左右,直到去年的牛市,比特股涨到过 2 元人民币。

    虽然最终离开了比特股,但是 BM 依然会参与 BTS 紧急 Bug 修复工作。与此同时,BM 又开发了一款旨在颠覆传统互联网媒体行业的项目——Steemit,这也是开辟了基于区块链 Token 内容社区的先例。Steemit 也是基于石墨烯技术的,它非常流行。2017 年,随着 Steemit 的成熟,BM 宣布退出了 Steemit,开展了下一个项目 EOS。

    EOS 的目的是要做出区块链行业的操作系统,为开发者提供底层功能,包括并行运算、数据库、账户系统等等。EOS 一经发布,就广受关注,短短五天内,EOS 便筹集到了数亿美金,它的代币销售规模在目前为止是最大的。

    现阶段的 EOS 超级节点竞选也体现出了 BM 强大的影响力。 EOS 项目影响力也越来越大,BM 因为与 V 神在区块链上的理念不合,也经常互怼,他们争论的重点是二人对于去中心化的前提假设不同,这也造就了两个不同的设计逻辑,所以,两人的争论过程可以说是非常地吸引眼球了。

    我们从 BM 的个人经历、项目经验、影响力都可以看出 BM 是一个很懂金融的天才式程序员,同时也是一个有点刚愎自用导致与社区矛盾不断的意见领袖。

    DPoS 详解

    讲完了 BM 的故事,我们再来讲讲 DPoS。简单来理解,DPoS 共识算法就是将 PoS 共识算法中的记账者转换为指定节点数组成的小圈子,而不是所有人都可以参与记账,这个圈子可能是 21 个节点,也有可能是 101 个节点,这一点取决于设计,只有这个圈子中的节点才能获得记账权。

    这将极大地提高系统的吞吐量,因为更少的节点也就意味着网络和节点的可控。

    1.DPoS 共识的目标

    从名称上,我们也可以判断出 DPoS 与 PoS 共识是直接关联的。DPoS 算法是 BM 根据当时 PoW、PoS 的不足而改进的共识算法,它的目的就是为了提高性能,也就是交易确认时间短。在 PoS 共识中,人们使用财产证明来“挖矿”,也就是说,这是任何人都可以参与的,只要你持有币,你就可以参与挖矿。

    但是我们可以看出,PoS 并没有解决性能问题,在这里我们直接认为提高性能就是提高 TPS,我们可以构造一个等式,:

    TPS = transactions / block_time

    TPS 表示区块链每秒能确认的交易数, transactions 是由区块大小 block_size 和平均每笔交易大小决定的,而区块大小受全网网络状态 network_bandwidth 限制,也是由记账节点之间处理性能 witness_performance 决定的。记账节点的个数 witness_count 直接决定了物理带宽的上限,因为记账节点数量越多,则对物理带宽要求越高,对网络的稳定性要求也越高。要注意的一点是在 DPoS 中,记账节点不叫做矿工,而是改称为见证人Witness。所以这个公式变成了下面的样子。TPS = (block_size * network_bandwidth * witness_performance) / (block_time * witness_count)

    我们可以看到,要提高 TPS,可以提升分子项,降低分母项,也就是增大区块大小 block_size、提升记账节点网络带宽 network_bandwidth、提升记账节点处理性能 witness_performance,减小区块时间 block_time、减小记账节点数量 witness_count。

    分子项我们可以看到,它基本受限于物理资源的上限,目前工业水平制造的物理资源的使用上限基本就是整个项的上限了,所以可操作性不大。而分母项是由共识算法决定的,所以我们从区块时间,以及记账节点数入手,DPoS 算法便正是从这两项着手的。首先改动的便是限制记账节点的数量,也就是见证人的数量。

    我们在 PoW 和 PoS 中可以看到,成为记账节点是无需门槛的,你可以随时参与挖矿,随时退出。那这会带来什么问题呢,首先无法确定记账节点的数量,其次无法确定记账节点之间的网络环境,记账节点数越多网络环境越复杂,这些不确定性会增大网络分区的概率,从而导致区块链分叉。

    如果我们事先规定好记账节点的数量,接着让全网所有节点可以投票决定哪些节点可以成为记账节点,这样就限制并减小了分母项 witness_count,这个过程我们也称作投票选举。

    因为记账节点数量不多,那么我们可以在共识算法中可以规定出块时间为一个固定值,这个值可以很小,通过轮流出块的方式来进行记账。以上思路基本就是 DPoS 的基本设计思路,BM 还为 DPoS 算法确立两个原则:

    1. 投票选举过程一定要保证最大权益所有者最终能控制全网,因为一旦出了问题,他们的损失最大;
    2. 与 PoW、PoS 一样,所有节点仅承认“最长”链。

    这两个原则确立了 DPoS 共识的基本特性,第一条放大了 PoS 共识使用者就是记账者的优点,第二点则规定了分叉时系统应该表现的行为。

    2.DPoS 共识算法分析

    在 DPoS 共识算法中,区块链的正常运转依赖于见证人 (Delegates),见证人是由全网节点投票产生的,见证人也是记账节点的实际控制人,相当于咱们选课代表,课代表帮我们整理作业。

    见证人在完成打包交易的同时可以领取区块奖励和交易的手续费,并且可以执行社区投票的提案,所以 DPoS 共识算法不仅仅是算法,而是一个包含了协作治理关系的共识机制。我们可以引用“DPoS 算法白皮书”中的内容,来看看 BM 设计 DPoS 算法是怎样的思路。

    BM 认为所有区块链实际是建立交易之上的确定性状态机。共识是在确定交易顺序,过滤无效交易的一个达成一致意见的流程。DPoS为了尽快确定交易顺序,过滤无效交易,所以规定了在正常情况下,所有记账节点轮流每 3 秒产生一个区块,轮到了某个记账节点出块时,必须在 3 秒内提交区块,否则就会错块。

    假设一直没有记账节点错过自己顺序,那么他们生产的链条势必是最长的链条,如果记账节点在非指定时间生产区块被认为是无效的,每经过一轮,所有节点轮流出块的顺序就会发生重新洗牌。

    下图就是一个理想的轮流记账状态。

    DPoS 算法白皮书介绍了 7 种异常的情况会打破上面的正常情况。例如少数记账节点发起恶意分叉或者发生故障,如下图。

    在这种情形下,B 节点只能在 9 秒内生产 1 个块,而大多数分支,由于数量多一倍,将预期能在 9 秒内生产 2 个块,诚实的 2/3 的大多数可以比小的那一部分创建一个更长的链条,由于原则二,DPoS 可以抵御这种攻击。在 DPoS 白皮书中介绍了少数记账节点恶意或故障造成的分叉、网络分区情况下重复出块、少数记账节点重复出块、记账节点数量不足、多数记账节点的联合腐败等各种情况。

    遗憾的是白皮书中的内容没有经过严格证明,以定性分析为主,所以我们无法确定 DPoS 算法是否有设计缺陷。在实际应用中,比特股中见证人是 101 人,EOS 里是 21 人。比特股中见证人们赚取手续费,EOS 里见证人们分享 EOS 的通胀收益。他们都是通过公开选举选出来的,选票就是大家手里的比特股或 EOS。

    3. 有关 DPoS 的一个争论:中心化问题。

    我们之前文章中提过的 FLP 和 CAP 定理,如果为了提升性能,即一致性的效率,势必会牺牲其他两项。这也会引出有关 DPoS 的一个争论:中心化问题。

    我们以比特股社区为例,每个人都可以尝试成为 101 个见证人节点中的一个,他们可以在社区里拉票,为社区做事,或者干脆用钱买很多 bts。平时大家象征性地开个会,因为是轮流记账,各个节点之间竞争不大。

    但是不要忘记,区块链的发展非常依靠社区,这种方式势必会带来社区的中心化。虽然比特股中 101 个见证人负责记账,但总得有人指定发展方针,于是又设计出了 11 人理事会,这同样是通过选票选出来的。

    11 人理事会有很高的权力,他们相当于 11 个超级节点,通过举手表决,甚至可以决定修改代码,而这 11 人理事会是比特股系统里的中心,也是规则的制定者。这是 DPoS 算法的优势,也是 DPoS 算法的劣势。在 PoW 中,矿工、开发者、用户三权分立。而 DPoS 似乎将这三权合并到了见证人和理事会手中。在 EOS 中,BM 还制定了区块链宪法,要求所有记账节点必须遵守,所以也有人抨击这是具备了 BM 特色的去中心化。

    从某种角度来看,DPoS 是社区治理加上共识算法,不再是单纯的技术共识,这是与 PoW、PoS 算法最大的不同。DPoS 的基本假设是相信节点是好的,所以尽可能快速选择记账节点,而把问题发生后的修复过程推迟到投票中,可以说 DPoS 并不考虑拜占庭容错问题,把拜占庭容错推给了社区治理,而在社区治理上可归纳为一切皆投票。

    而现实生活中,很多情况下,投票并不能解决问题,比如投票人都是有惰性的,集齐所有人投票成本是很高的,如果记账节点没有上限,所有节点的投票都投给自己,DPoS 系统就会退化成 PoS 系统。

    展开全文
  • 基于DPoS算法、P2P对等网络的简易区块链Go语言实现
  • DPOS机制

    万次阅读 2018-02-15 13:45:26
    如果还不能深刻理解这其中的奥妙,下面,就让我们通过阅读亿书源码,来研究DPOS(授权股权证明)机制的具体实现,去直观感受一下吧。 亿书DPOS机制概述 [亿书白皮书][] 描述了DPOS(授权股权证明)机制基本原理和...

    前言

    共识机制是分布式应用软件特有的算法机制。在中心化的软件里,再复杂的问题都可以避开使用复杂的算法逻辑(当然,如果能用算法统领,代码会更加简洁、高效),在开发设计上可以省却一定的麻烦。但在分布式软件开发中,节点间的互操作,节点行为的统一管理,没有算法理论作为支撑,根本无法实现。所以,要想开发基于分布式网络的加密货币,共识机制无法回避。

    在第一个部分,专门用一篇文章《共识机制,可编程的“利益”转移规则》来介绍共识机制的作用,也对比了当前加密货币领域常用的三种共识算法原理和优越点,但是并没有对共识算法进行深入讨论。这一篇我们就从解释“拜占庭将军问题”开始,来探讨加密货币的算法问题,并通过代码学习和研究亿书共识机制的具体实现。

    源码

    主要源码地址:

    delegates.js https://github.com/Ebookcoin/ebookcoin/blob/v0.1.3/modules/delegates.js

    round.js https://github.com/Ebookcoin/ebookcoin/blob/v0.1.3/modules/round.js

    accounts.js https://github.com/Ebookcoin/ebookcoin/blob/v0.1.3/modules/accounts.js

    slots.js: https://github.com/Ebookcoin/ebookcoin/blob/v0.1.3/helpers/slots.js

    类图

    dpos-class.png

    数据库表

    整个数据库表应该都在该机制的管理之下,不过与用户相关的是与之直接关联的,特别是 mem_round 表。

    dpos-database.png

    解读

    在币圈如果不知道“拜占庭将军问题”,那说明您还没有发现问题的本质。但是要想理解这个问题,如果没有点高等数学和计算机编程基础,也不是非常简单的事情。我们这里就从八卦讲起,扒扒这个概念的由来,然后对照比特币的解决办法,引出亿书机制的实现。

    拜占庭将军问题

    (1)比特币是怎么来的?

    这里咱也八卦一下,猜猜比特币如何诞生的。在学习一门新技术的时候,我们通常会好奇,发明这项新技术的人,他是怎么想到要进行这项发明的呢?同样,对于比特币,我也曾经好奇,中本聪怎么想到要发明比特币的呢?这大量高科技的应用,可不是个小工程,一定要有明确的目的才行。这种好奇,始终督促我不断研究下去。

    算法是解决问题的理论基础,拜占庭将军问题就是针对分布式共识算法提出来的,而这个问题也是比特币等加密货币的核心问题。根据比特币白皮书(更像一篇科技论文吧)内容描述,大量篇幅提到诚实节点、攻击者等问题,类似于古代战场攻防对战,很多人猜测中本聪或许就是一位专门研究这个方向的大学老师或研究人员,他解决了这个问题,推出了相关论文,并根据研究成果写出了产品原型——比特币。所以,才会说比特币仅仅是一项实验。

    显然,这种猜测,纯属马后炮,由结果找原因,毫无历史根据。网上搜索了一下,各种猜测还真不少。姑且避开八卦内容,其中比较有价值的,是一篇比特金(Bit Gold)白皮书,因为它与比特币有惊人的相似之处,因此其开发者尼克·萨博(Nick Szabo)被认为最有可能是中本聪本人。比特金比比特币要早,它的目标就是实现一种不需要(只需极小的)信用中介的电子支付系统,与比特币的目标基本一致。

    可见,通过使用点对点网络、加密解密等技术实现加密货币的研究由来已久,可以肯定的是,比特币的初衷绝非单纯为了解决拜占庭将军问题那么简单。相反,为了实现没有中介的电子支付系统而设计倒是更加合情合理,只不过附带完美的解决了拜占庭将军问题而已。事实上,比特币算是解决拜占庭将军问题的一个完美实现。

    (2)什么是拜占庭将军问题?

    但不管怎么说,拜占庭将军问题是比特币无法逾越的问题。该问题最早是由Leslie Lamport解决,为了提高宣传效果,老先生在研究论文里编造了这么一个故事,事实证明非常成功,这个故事被广泛传播。故事内容是这样的:拜占庭是东罗马帝国的首都,为了防御外敌入侵,周边驻扎了军队,而且每个军队都分隔很远,相互独立,将军与将军之间只能靠信差传递消息。在战争的时候,拜占庭军队内所有将军必需达成一致的共识(进攻或撤退),才有胜算把握。但是,在军队内部有可能存在叛徒,左右将军们的决定。这时候,在已知有成员叛变的情况下,其余忠诚的将军如何达成一致的协议,拜占庭问题就此形成。Lamport 证明了在理想状态下,背叛者为m或者更少时,将军总数只要大于3m,忠诚的将军就可以达成一致。

    从技术上理解,拜占庭将军问题是分布式系统容错性问题。加密货币建立在P2P网络之上,是典型的分布式系统,类比一下,将军就是P2P网络中的节点,信使就是节点之间的通信,进攻还是撤退的决定就是需要达成的共识。如果某台独立的节点计算机拓机、掉线或攻击网络搞破坏,整个系统就要停止运行,那这样的系统将非常脆弱,所以容许部分节点出错或搞破坏而不影响整个系统运行是必要的,这就需要算法理论上的支撑,保证分布式系统在一定量的错误节点存在的情况下,仍然保持一致性和可用性。

    我非常赞同把拜占庭将军问题与两军问题分开,两个问题的本质不同,后者重在研究信差的通信问题,类似于TCP协议的握手操作,原则上是没有解的。而拜占庭将军问题是假定信差没有问题,只是将军出现了叛变等问题,所以二者本质有区别。不过,在实际的加密货币系统里,信差的问题,比如通信中断、被劫持等,都可以归为将军(节点)出了问题,理解到这一点就可以了,因此可以说比特币是完美解决了这两个问题。关于两者的区别,请看这篇文章《拜占庭将军问题深入探讨》(见附件),作者下了不少功夫,值得一读。

    (3)比特币是如何解决拜占庭将军问题的?

    Lamport 给出了理想状态下的答案,但现实是复杂的,比特币是如何解决的呢?事实上,比特币通过“工作量证明”(PoW)机制,简单的规范了节点(将军)的动作,从而轻松解决这个问题:

    首先,维持周期循环,保证节点步调一致。这个世界上,最容易达成的就是时间上的共识,至少“几点见面”、“什么时候谈判”这样的问题很好解决吧,不然其他的都不用谈了。比特币有一个算法难度,会根据全网算力自动调整,以保证网络一直需要花费10分钟来找到一个有效的哈希值,并产生一个新区块。在这10分钟以内,网络上的参与者发送交易信息并完成交易,最后才会广播区块信息。拜占庭将军问题复杂在将军步调不一致,比特币杜绝了节点(将军们)无限制、无规律的发送命令的状态。

    其次,通过算力竞赛,确保网络单点广播。将军们如果有个“带头大哥”,事情就好办了。这里的“带头大哥”可以简单的竞争得来,举个极端的例子,说好的8点钟谈判,那么先到的就是“带头大哥”,可以拟定草稿,等其他人到了签字画押就行了。 “工作量证明”就是一种竞赛机制,算力好的节点,会最先完成一个新区块,在那一刻成为“带头大哥”。它把区块信息立即广播到网络,其他节点确认验证就是了。比特币通过时间戳和电子签名,实现了这样的功能,确保在某一个时间点只有一个(或几个,属于分叉行为)节点传输区块信息,改变了将军们互相传送的混乱。

    最后,通过区块链,使用一个共同账本。对于单个区块,上述两条已经可以达成共识了。但现在的问题是,有一个叛徒(不诚实节点)修改了前面区块的信息,计划把钱全部划归自己所有,当它广播新区块的时候,其他节点如何通过验证?如果大家手里没有一份相同的账本,肯定无法验证,问题就会陷入僵局。基于P2P网络的BT技术是成熟的,同步一个总帐是很简单的事情。网络中的节点,在每个循环周期内都是同步的,这让每个节点(将军)做决策的时候就有了共同的基础。如果每个节点都独立维护自己的账本,问题的复杂性将无法想象,这是更广泛基础上的共识。

    上述三点内容是比特币“工作量证明”(PoW)机制解决拜占庭将军问题的答案,也为其他竞争币提供了重要参考。事实上,无论你采取什么样的方式,只要保证时间统一、步调一致、单点广播、一个链条就能解决加密货币这种分布式系统的拜占庭将军问题。如果还不能深刻理解这其中的奥妙,下面,就让我们通过阅读亿书源码,来研究DPOS(授权股权证明)机制的具体实现,去直观感受一下吧。

    亿书DPOS机制概述

    [亿书白皮书][] 描述了DPOS(授权股权证明)机制基本原理和改进方法,这里不再重复。亿书由受托人来创建区块,受托人来自于普通用户节点,需要首先进行注册,然后通过宣传推广,寻求社区信任并投票,获得足够排行到前101名的时候,才可以被系统接纳为真正可以处理区块的节点,并获得铸币奖励。比特币是通过计算机算力来投票,算力高的自然得票较多,容易获胜。DPOS机制是通过资产占比(股权)来投票,更多的加入了社区人的力量,人们为了自身利益的最大化会投票选择相对可靠的节点,相比更加安全和去中心化。整个机制需要完成如下过程:

    (1)注册受托人,并接受投票

    • 用户注册为受托人;
    • 接受投票(得票数排行前101位);

    (2)维持循环,调整受托人

    • 块周期:也称为时段周期(Slot),每个块需要10秒,为一个时段(Slot);
    • 受托人周期:或叫循环周期(Round),每101个区块为一个循环周期(Round)。这些块均由101个代表随机生成,每个代表生成1个块。一个完整循环周期大概需要1010秒(101x10),约16分钟;每个周期结束,前101名的代表都要重新调整一次;
    • 奖励周期:根据区块链高度,设置里程碑时间(Milestone),在某个时间点调整区块奖励。

    上述循环,块周期最小(10秒钟),受托人周期其次(16分钟),奖励周期最大(347天)。

    (3)循环产生新区块,广播

    产生新区块和处理分叉等内容,上一章《区块链》已经讲过,这里不再赘述。

    下面,我们通过源码逐个查看其实现方法。

    1.注册受托人

    注册受托人必须使用客户端软件(币圈俗称钱包),因此这项功能需要与节点进行交互,也就是说客户端要调用节点Api。管理受托人的模块是 modules/delegates.js ,根据前面篇章的经验,我们很容易找到该模块提供的Api:

    "put /": "addDelegate"
    

    最终的Api信息如下:

    put /api/delegates
    

    对应的方法是,modules/delegates.js模块的addDelegate()方法。该方法与注册用户别名地址等功能性交易没有区别,注册受托人也是一种交易,类型为“DELEGATE”(受托人),详细过程请自行查看modules/delegates.js文件1017行的源码,逻辑分析请参考《交易》等相关章节内容。

    2.投票

    我们在《交易》一章提到过,有一种交易叫VOTE,是投票交易类型。所有这类功能性交易的逻辑都很类似,就不再详细描述。这里要提示的是,该功能是普通用户具备的功能,任何普通用户都有投票权利,所以放在帐号管理模块,即“modules/accounts.js”文件里,是符合逻辑的,请参阅该文件729行的“addDelegates()”方法。当然,从代码实现上来说,放在modules/delegates.js文件里,或其他地方也都可以实现相同功能,只是逻辑上稍显混乱而已。

    3.块(时段)周期(Slots)

    (1)时间处理

    比特币的块周期是10分钟,由工作量证明机制来智能控制,亿书的为10秒钟,仅仅是时间上的设置而已,源码在helpers/slots.js里。这个文件非常简单,时间处理统一使用UTC标准时间(请参考开发实践部分《关于时间戳及相关问题》一章),创世时间beginEpochTime()和getEpochTime(time)两个私有方法定义了首尾两个时间点,其他的方法都是基于这两个方法计算出来的时间段,所以不会出现时间上不统一的错误。

    (2)编码风险

    但是,唯一可能出现错误的地方,就是getEpochTime(time)方法,看下面代码的16行,new Date() 方法获得的是操作系统的时间,这个是可以人为改变的,一般情况下不会有什么影响,但个别情况也可能引起分叉行为(上一篇文章《区块链》分析过分叉的原因,其中一个就发生在这里)

    // helpers/slots.js
    function getEpochTime(time) {
        if (time === undefined) {
          // 16行
          time = (new Date()).getTime();
        }
        var d = beginEpochTime();
        var t = d.getTime();
        return Math.floor((time - t) / 1000);
    }
    

    (3)周期实现

    从现在时间点到创世时间,有一个时间段,大小假设为 t,那么 t/10 取整,就是当前时段数(getSlotNumber())),这里的10是由 constants.slots.interval 设定的,见文件 helpers/constants.js 25行。

    具体到一个受托人,它处理的区块时段值相差应该是受托人总数,这里是101, 这个值由 constants.delegates 设定,见文件 helpers/constants.js 22行。因此,getLastSlot()方法(helpers/slots.js文件 54行)返回的是受托人最新时段值。

    (4)如何使用?

    块周期,是其他周期的基础,但是这里的代码并不包含任何区块、交易等关键信息。这里隐含的关联关系,就是区块、交易等信息的时间戳。只要知道任何一个时间戳,其他信息就可以使用这里的方法简单计算出来。典型的使用就是 modules/delegates.js 文件里的方法 privated.getBlockSlotData() 方法(470行),代码已在《区块链》一章贴出过,该方法为新区块提供了密钥对和时间戳。

    另外,在《区块链》一章,我们也指出,程序设定每秒钟(744行1000毫秒)调用一次“privated.loop()”方法用来产生新区块,但是因为loop()方法并非每次都能成功运行,所以实际运行起来是在10秒内找到需要的受托人并产生一个区块。

    (5)参数可调整吗?

    很多小伙伴问,为什么一定是10秒,其他的值可以吗?为什么要101个受托人,201个可以吗?回答都是可以。我认为这个块周期如果提高到20或30或许更好(需要验证),可能更有利于SQLite数据库,也自然降低了通胀比率(后面分析)。对于计算机而言,数据库IO操作是耗时大户,10秒间隔可以提高处理交易的数量,但也会造成数据库IO无法正确完成,所以这个值是压力测试的经验值。

    至于受托人的数量,也是如此。使用极限思维的方法,让受托人数量减少到1,效率高了,但是单点系统很容易受到攻击,安全性受到威胁;增加到无限大,那么查找受托人的方法将一直运行下去,结果是系统性能降到了0。所以,这个数字也是一个经验值,可以根据实际情况做适当调整。特别是那些要做DApp市场的应用,更应该考虑适当变更。

    4.受托人(循环)周期(Round)

    为了安全,亿书规定受托人每轮都要变更,确保那些不稳定或者做坏事的节点被及时剔除出去。另外,尽管系统会随机找寻受托人产生新块,但是在一个轮次内,每个受托人都有机会产生一个新区块(并获得奖励)并广播,这一点与比特币每个节点都要通过工作量证明机制(PoW)竞争获得广播权相比,要简化很多。

    这样,亿书每个区块都会与特定的受托人关联起来,其高度(height)和产生器公钥(generatorPublicKey)必是严格对应的。块高度可以轻松找到当前块的受托人周期(modules/round.js 文件51行的calc()方法),generatorPublicKey代表的就是受托人。而单点广播的权限也自然确定,具体代码见 modules/round.js 文件。

    这里,需要重点关注的是该文件的 tick() 和 backwardTick() 方法。tick,英文意思是“滴答声或做标记”,如果大家开发过股票分析软件,在金融领域,tick还有数据快照的涵义,意思是某个时段的交易数据。我个人觉得,这里就是这个意思,是指在一个受托人周期内某个受托人的数据快照。相关数据存储在 mem_round 表里,程序退出时就会被清空。具体代码如下:

    // modules/round.js
    // 224行
    Round.prototype.tick = function (block, cb) {
        ...
      // 229行
        modules.accounts.mergeAccountAndGet({
            publicKey: block.generatorPublicKey,
            producedblocks: 1,
            blockId: block.id,
            round: modules.round.calc(block.height)
        }, function (err) {
            ...
            if (round !== nextRound || block.height == 1) {
                if (privated.delegatesByRound[round].length == constants.delegates || block.height == 1 || block.height == 101) {
                    var outsiders = [];
            // 255行
                    async.series([
              // 256行 找到那些没在当前轮次里的节点
                        function (cb) {
                            if (block.height != 1) {
                  // 258行 generateDelegateList()方法可以查询数据库里投票排行前101的节点,不过当前可能已经改变,这里把它们找出来
                                modules.delegates.generateDelegateList(block.height, function (err, roundDelegates) {
                                    ...
                                    for (var i = 0; i < roundDelegates.length; i++) {
                                        if (privated.delegatesByRound[round].indexOf(roundDelegates[i]) == -1) {
                                            outsiders.push(modules.accounts.generateAddressByPublicKey(roundDelegates[i]));
                                        }
                                    }
                                    ...
                        },
    
              // 把缺失的块暂时保存到 mem_accounts 表里
                        function (cb) {
                            if (!outsiders.length) {
                                return cb();
                            }
                            var escaped = outsiders.map(function (item) {
                                return "'" + item + "'";
                            });
                            library.dbLite.query('update mem_accounts set missedblocks = missedblocks + 1 where address in (' + escaped.join(',') + ')', function (err, data) {
                                cb(err);
                            });
                        },
    
              // 一开始就通过merge()方法向 mem_round 表添加了记录,这里 getVotes() 方法查询出来,并依次更新到 mem_accounts 表里。
                        function (cb) {
                            self.getVotes(round, function (err, votes) {
                                ...
                                async.eachSeries(votes, function (vote, cb) {
                                    library.dbLite.query('update mem_accounts set vote = vote + $amount where address = $address', {
                                        address: modules.accounts.generateAddressByPublicKey(vote.delegate),
                                        amount: vote.amount
                                    }, cb);
                    ...
                            });
                        },
    
              // 上述变化处理完毕,接着处理余额、费用和奖励变化
                        function (cb) {
                            var roundChanges = new RoundChanges(round);
    
                            async.forEachOfSeries(privated.delegatesByRound[round], function (delegate, index, cb) {
                                var changes = roundChanges.at(index);
    
                                modules.accounts.mergeAccountAndGet({
                                    publicKey: delegate,
                                    balance: changes.balance,
                                    u_balance: changes.balance,
                                    blockId: block.id,
                                    round: modules.round.calc(block.height),
                                    fees: changes.fees,
                                    rewards: changes.rewards
                                }, function (err) {
                                    ...
                        },
    
              // 最后,再一次更新 mem_accounts 的投票数据,没有问题就结束本轮循环(推送客户端改变),并清除 mem_round 记录的信息
                        function (cb) {
                            self.getVotes(round, function (err, votes) {
                                ...
                                async.eachSeries(votes, function (vote, cb) {
                                    library.dbLite.query('update mem_accounts set vote = vote + $amount where address = $address', {
                                        address: modules.accounts.generateAddressByPublicKey(vote.delegate),
                                        amount: vote.amount
                                    }, cb);
                                }, function (err) {
                                    library.bus.message('finishRound', round);
                                    self.flush(round, function (err2) {
                                        cb(err || err2);
                                    });
                                })
                            });
                        }
                    ], function (err) {
                        ...
    

    229行,modules.accounts.mergeAccountAndGet() 方法实际上是调用 logic/account.merge() 方法(见文件logic/account.js 请自行查阅),把这里的数据插入到 “mem-”开头的数据库表里,用于处理与账户相关的一些数据,该方法比较混乱,系统需要频繁处理,对性能有较大影响,亿书将在以后的版本里做进一步优化。

    255行,使用async.series方法,顺序执行了一些函数,具体情况请看代码中的注释,不再赘述。

    backwardTick() 方法是反方向处理,属于回退操作,请自行查阅分析。

    5.奖励周期(Milestones)

    该周期主要针对块奖励进行设置,与比特币的块奖励每4年减半类似,亿书的块奖励也会遵循一定规则。大致的情况是这样的,第一阶段(大概1年)奖励5EBC(亿书币)/块,第二年奖励4EBC(亿书币)/块,4年之后降到1EBC(亿书币)/块,以后永远保持1EBC/块,所以总量始终在少量增发。(亿书正式上线的产品可能会做适当调整,这里仅作测试参考

    具体增发量很容易计算,第一阶段时间长度 = rewards.distance 10秒 / (24 60 60) = 347.2天,增发量 = rewards.distance 5 = 3000000 * 5 = 1500万。第二阶段1200万,第三阶段900万,第四阶段600万,以后每阶段300万。这种适当通胀的情况是DPoS机制的一个特点,也是为了给节点提供奖励,争取更多用户为网络做贡献。

    很多小伙伴担心这种通胀,会降低代币的价值,影响代币的价格。事实上,对于拥有大量侧链应用(下一篇介绍)的平台产品来说,一定要保证有足够代币供各侧链产品使用,不然会造成主链和侧链绑定紧密,互相掣肘,对整个生态系统都不是好事情。这种情况可以通过最近以太坊的运行情况体会出来,特别是侧链应用使用主链代币众筹时更不必说,此消彼长,价格波动剧烈。

    具体代码见文件 helpers/milestones.js,该文件编码很简单,都是一些算术运算,请自行浏览。这里简单给出流程图:

    milestones-activity.png

    唯一需要提醒的是,代码有一处非常隐晦的Bug,就是涉及到parseInt()方法的使用(请参考开发实践部分《Js对数据计算处理的各种问题》一章),特别是第26行。不过对系统的影响非常细微,仅仅在某个别区块高度的时候才会出现几次,比如:出现类似 parseInt(2/300000000) = 6 的情况。(亿书将在后面的版本中修改)

    总结

    本人介绍了拜占庭将军问题及比特币解决思路,也沿着这个思路阅读了亿书相关源码,内容涉及到多个源文件。其中,大量的细节因为篇幅所限没有详细提供,需要小伙伴们自己查阅。从源码设计上来说,这一部分的源码还需要更多的优化设计。从文章内容来说,也远远没有达到预期目的,还需要更进一步的探索和讨论。

    实际上,从软件工程角度考虑,任何一个软件产品都有一个统领全局的算法机制,如果事先设计好,也会为系统开发和维护带来很大的便利,在设计的时候会有更加清晰的思路和编码方法。但是就本书而言,过多的讨论,反而偏离主线,前后繁复,所以我们暂且把更多的思考放在以后去研究。接下来,让我们把目光投向《侧链》,这也是当前极为火爆的领域。

    参考

    比特币白皮书:一种点对点的电子现金系统

    尼克·萨博《比特金(BitGold)》白皮书

    百度百科关于拜占庭将军问题描述(混淆了两军问题)

    分布式共识难题(英文))

    拜占庭将军问题深入探讨


    http://bitcoin-on-nodejs.ebookchain.org/3-%E6%BA%90%E7%A0%81%E8%A7%A3%E8%AF%BB/9-DPOS%E6%9C%BA%E5%88%B6.html

    展开全文
  • 在委托权益证明 (DPoS) 区块链中,区块生产者 (BP) 通过权益加权投票选出。 如果绝大多数 BP 同意,他们就可以分叉区块链,即可以改变区块链的规则。 因此,防止选票集中很重要。 一些 DPoS 区块链允许用户投票给多...
  • DPOS EOS.IO软件架构中采用的共识算法。根据这种算法,全网持有代币的人可以通过投票系统来选择区块生产者,一旦当选任何人都可以参与区块的生产。 出块机制 超级节点轮流出块,每轮每个节点连续出12个块 EOS.IO架构...
  • 我们需要将节点最大验证器数修改一下,这样便于我们进行简单测试 修改consensus/dpos/dpos.go文件的maxValidator // 新值 maxValidatorSize = 21 // 旧值 maxValidatorSize = 3 构建 make geth 构建成功后将bin文件...
  • 相信刚开始接触区块链的朋友们,经常会听到POW、POS和DPOS,对于这几个高度相似的字母组合时常会感到一头雾水,不知道是什么东西。 其实上述名词就是区块链中一个重要的概念——“共识机制”。 所谓“共识机制”,是...
  • 股份授权证明机制(DPOS)是什么:股份授权证明机制,简称DPOS。类似于董事会投票,持币者投出一定数量的节点,代理他们进行验证和记帐。为了激励更多人参与竞选,系统会生成少量代币作为奖励。DPOS有点像议会制度或...
  • consensus/dpos/dpos.go maxValidatorSize = 3 2、构建美图以太坊docker镜像 cd $GOPATH/src/github.com/meitu/go-ethereum docker build . -t meitugeth 3、建立节点数据目录 mkdir meitu cd meitu mkdir ...
  • Ethereum DPOS源码分析

    2018-12-25 06:02:42
    1 导语 ...出块又叫挖矿,有各种挖矿的方式,比如POW、DPOS,本文主要分析DPOS共识源码。 以太坊存在多种共识: PoW (etash)在主网使用 PoA(clique) 在测试网使用 FakePow 在单元测试使用 DPO...
  •   共识机制是区块链的核心技术,比如PBFT(Practical Byzantine Fault Tolerance,实用拜占庭容错算法)、PoW(Proof of Work,工作量证明)、PoS(Proof of Stake,权益证明)、DPoS(Delegate Proof of Stake,...
  • 一个基于DPoS共识算法的区块链案例解析 一、前言 前面我们介绍了PoW以及PoS的案例,我们会发现它们都有一些缺点,比如PoW耗费能源比较多,而PoS是持有的币越多,成功挖矿的几率越大,这会造成贫富差距越来越大,并且...
  • 共识机制——POS与DPOS探究 共识机制是分布式应用软件特有的算法机制。通过特殊节点的投票,在很短的时间内完成对交易的验证和确认;对一笔交易,如果利益不相干的若干个分布式节点能够达成共识,我们就可以认为...
  • 具有公共和私人交易,自定义DPOS共识以及不久的侧链的独特区块链网络。 :warning: 我们正在从CryptoNight PoW共识算法切换到我们自己的委托私有权益证明(DPOPS)! :backhand_index_pointing_right: 跟随存储库...
  • 首先,我们来了解一下什么是 DPoS 算法,DPoS 主要分为两个部分: (1)由利益相关者投票选举出一组区块生产者; (2)区块生产者按轮次调度生产。 同 PoW 一样,在 DPoS 中,最终胜出的规则仍然是最长链胜出。任何...
  • DPoS共识(consensus)算法

    千次阅读 2021-06-09 17:35:01
    1、solo算法 2、dpos 3、BPFT拜占庭算法
  • DPOS共识算法 - 缺失的白皮书

    千次阅读 2018-04-25 00:11:17
    steemit上原文链接:...关于BitShares的DPoS共识的概述请参考:股份授权证明(DPOS)概述 关于BitShares的DPoS共识的详细介绍请参考:BitShares的DPoS共识 关于BitShare...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,337
精华内容 2,134
关键字:

dpos

友情链接: pmsm1.rar