EOS 共识算法 DPOS3.0 的改进

   BP : Block producer, 块产生者。

   

      本文描述了一个DPoS的改进,它更强地保证了遵守DPoS3.0协议下的结点不会共识失败。我们定义共识失败为: 两个结点包括了两个不同的不可逆的链.

       背景:

       PoW , 如Bitcoin, 定义了一个 “最长链”规则的共识。使用这个规则,任何Block都不会被认为是不可逆的确认状态。 在任何时候,一个人可以从一个更老的块生产一个更长的链,结点就会转换(分叉)。由此我们可以得出这样的结论: 比特币仅仅提供了一个基于的尝试去分叉产所需要的经济成本的高概率的不可逆性。

       BitShares介绍DPoS. 在这个算法下,股权持有人选举产生BP。BP被伪随机的打散并分配了一个绝对的时间段。在这个时间段里,他们会产生或者不产生一个块。拥有大多数BP的链它会以更快的速度增加它的链高度。如果两个链以不同的速度增长,那么更快的链最终将成为最长的链。因此,最初委托证明的股份算法为比特币提供了类似的保证,就是说,随着块的增加,另一个较慢的链越来越不可能发生逆转。

       DPoS调度算法的本质是将大量的信息传递给一个观察者。例如,基于缺失块的出现频率,一个观察者可以发现他们可能处于一个少数派的链上。在21个BP的情况下,在仅仅2个连续的缺失块出现时(6秒), 一个节点可以准确地检测到他们可能是在一个少数的分叉上。同样地,如果BP在连续21个块中都没有缺失一个块,那么你可以确定你的块不会被反转。

     罕见的共识失败(DPoS2.0)

       DPoS2.0我们引入了最后一个不可逆块的概念。这个块最近有2/3+1的BP基于它来产生新块的。理论是,如果2/3+1的生产者建立在一个确定一个区块的链条上,那么就不可能有其他的分叉了。

       就是说,在真实用户已经构造了一个网络被分成两条链的人为的场景。常情况下,这只会导致一个或两个链停止前进的最后一个不可逆块,直到一个链被重新连接到2/3+1的生产者。

      在这个正常的行为中,一切都很好,一旦连接建立,所有的节点就会集中在一个真链上。

      然而,在这个有一个竞争条件,就是两个分叉的链有可能同时得到2/3+1生产者。当这种情况发生时,分叉两条链的节点无法同步,因为它们都不会回卷到最后一个不可逆转的块。需要手动干预。

      在这种情况下,一个或两个分叉将会停止前进的不可逆性,这取决于哪个分叉最终会得到2/3+1的生产者。少数派链的增长速度可能仍为1/2,但等待不可逆转的节点将不再接受最终确定的少数派链上的任何交易。

      这种故障模式产生了一个单块,如果它回退了,一些服务可能会经历损失。根据我们的估计,发生这种情况的概率要比一个比特币块的概率要小得多。在实际测试中,BitShares和Steem在运行了超过3年并没有发这种情况。

       DPOS 3.0 + BFT

      随着EOSIO我们引入了区块链通信(IBC),它允许一个链高效地向另一个链证明交易是最终的。Finality对IBC至关重要,因为一旦区块链接受了来自另一个的消息,就不容易,也不希望回卷两个链来纠正错误。

       想象一下区块链正试图接受比特币存款。一个用户在他引用的块的6块后,提交了全部的比特币。基于这个证明这个是不可逆的动作。 想像一下,如果BTC分叉了,这6个块给撤销了,这时候怎么办? 这个区块链不可能逆转和拒绝先前接受的比特币交易。这样的事件需要人工干预和(或)硬分叉。这样的硬分叉/干预将会波及所有连接的链。这不是一个可行的选择。

      为了确保IBC在所有非复杂情况下的安全可靠,DPOS 3.0 + BFT引入了一个小的更改, 是关于最后一个不可逆块(LIB)是如何计算的。有了这个更改,我们可以证明两个节点不可能在没有至少1/3的块产生节点故意恶意的情况下得出不同的结论。此外,我们还可以证明哪怕是一个节点的恶意行为。

       DPOS背后的核心理念是,每个产品块都是对所有之前区块的投票。有了这个模型,2/3+的生产者建立在一个特定的区块上,它有2/3+投票。这在理论上听起来很不错,但在不同的时间,非拜占庭式的区块生产者可以在不同的分叉上生产区块。当它们产生这些块时,它们最终会对每个链上出现的块编号产生间接的相互冲突的投票。

       假设有A,B和C三个BP, 它们之间因为故碍网络一段时间内无法通讯。  这时,A在时间T产生了 块N, B在时间点T+1时产生了块N. 这时,假设C恢复通讯了,它在T+2这个时间点,基于B产生的块N的顶部,产生了块N+1。 在这个之后,A也恢复通讯了,知道了C的块N+1,  A会切换到最长的分叉上。下一次 产生个一块时,它会间接的确认了 B的块N,这个块是和A之前产生的块N冲突的。

       在DPoS2.0 的规则下,A’s block N会有来自A,B和C的投票,并且,因为有(2/3+1)的确认成为不可逆的。在DPOS的规则下,我们要求A披露他之前确认的另一个block N,由于这个信息披露,网络将不会计算A的block,因为它已经投票给B的block N,这就使得B的block N只有2个投票,这还不足以达到不可逆性。

        DPOS 3.0 B的block N永远不会实现直接的不可逆性,因为它要求A、B和C的投票结果是2/3+1,而A在另一个块N上投下一票,如果N+2和B产生N+3,那么N+1就不可逆了。这将会给block N+1的3张支持票,达到2/3+1。一旦C的block N+1是不可逆转的,B的block N也被认为是不可逆的。

        为了实现这个算法,每个块生成器包括最高的块号(H),它在任何一个分叉上都得到了确认。当块 N被应用时,仅在于range (H+1, N)这个范围内的块会得到不可逆性的投票。

       任何在重叠区域对一个块进行签名的BP都被认为是拜占庭式的,并将生成错误行为的密码学证明。

 

       有了这些信息,我们现在可以生成一个简单的证明,即对于任何给定的块高度,在相同高度的两个不同块上获得2/3+1的投票,同时至少1/3的BP必须对冲突范围内的块进行签名。

       

       如果有一个诚实的网络分裂,那么就会发生这样的情况: 两个好的组(1/3 *2)产生各自的选择,一个坏的组(1/3*1)在两个分叉上都进行签名。 而实际上一个连接良好的网络,至少需要2/3+1的成员是恶意的,才有可能去产生两个不同的不可逆块。

      在这些规则下,现在有两种方式让生产者签署拜占庭式的声明:

 

 

1. 用相同的块号直接或间接地签署两个区块。

 

             2. 用相同的时间块签两个块。

 

      运行默认软件的诚实节点永远不会做这些事情。因此,我们有可能对所有的不良行为进行惩罚,即使只是失败的尝试的行为。     

 

 感谢

 

这个问题的解决方案是由Bart, Arhag,以及我和B1团队的其他成员共同发现的。

https://github.com/EOSIO/eos/issues/2718

 

由于DPoS是区块链技术中的一种共识算法,实现DPoS需要涉及区块链的一些基础概念和相关操作。这里提供一个简单的DPoS共识算法的实现,包括以下步骤: 1. 定义区块链节点的数据结构 节点包括ID、地址、投票数等信息,使用Python的类来定义节点的结构。 ``` class Node: def __init__(self, id, addr): self.id = id self.addr = addr self.vote_count = 0 ``` 2. 初始化区块链节点 在初始化区块链节点时,需要创建一些节点,并对节点进行一定的初始化操作,如设置超级节点和初始化投票数。 ``` def init_nodes(): nodes = [] super_nodes = [] node_num = 10 total_voter_count = 100 voter_count_per_node = total_voter_count // node_num for i in range(node_num): node_id = i + 1 node_addr = 'node_' + str(i) node = Node(node_id, node_addr) node.vote_count = voter_count_per_node nodes.append(node) if node_id <= 3: super_nodes.append(node) return nodes, super_nodes ``` 3. 实现投票功能 对每个节点进行投票操作,使用Python的字典来记录节点的投票情况。 ``` def vote(node_id, voted_node_id, nodes_dict): if node_id not in nodes_dict: raise Exception('Node not found') if voted_node_id not in nodes_dict: raise Exception('Voted node not found') if nodes_dict[node_id].vote_count <= 0: raise Exception('No vote count') nodes_dict[node_id].vote_count -= 1 if 'votes' not in nodes_dict[voted_node_id]: nodes_dict[voted_node_id]['votes'] = 1 else: nodes_dict[voted_node_id]['votes'] += 1 ``` 4. 计算出票结果 通过对投票结果进行统计,计算出每个节点获得的票数,选出得票最多的前N个节点作为超级节点。 ``` def calculate_vote_result(nodes_dict, super_node_num): sorted_nodes = sorted(nodes_dict.items(), key=lambda x:x[1].get('votes', 0), reverse=True) super_nodes = [x[1] for x in sorted_nodes[:super_node_num]] return super_nodes ``` 5. 实现DPoS共识算法 将节点进行分组,每个节点可以随机被分组到不同的组中,计算出每个组的超级节点,并用超级节点来验证区块的合法性。 ``` def dpos_consensus(nodes, super_nodes_num): nodes_dict = dict(zip([node.id for node in nodes], nodes)) for i in range(20): # 模拟节点投票操作 for node_id in nodes_dict: voted_node_id = random.choice(list(nodes_dict.keys())) vote(node_id, voted_node_id, nodes_dict) # 计算出票结果 super_nodes = calculate_vote_result(nodes_dict, super_nodes_num) # 将节点分组,每个组由前super_nodes_num个超级节点组成 groups = [] group_size = super_nodes_num for i in range(0, len(super_nodes), group_size): groups.append(super_nodes[i:i+group_size]) # 随机分组 random.shuffle(groups) # 对于每个分组,随机选择一个超级节点来验证区块的合法性 for group in groups: validator_id = random.choice([node.id for node in group]) validate_block(validator_id) def validate_block(validator_id): # TODO: 区块验证逻辑 pass ``` 这是一个简单的DPoS共识算法的实现,实际应用中还需要考虑更多因素,如节点的可信度、选举周期、超级节点奖励等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值