一、EOS的奖励制度
??对记账节点的经济激励机制是区块链项目不可缺少的重要组成部分,EOS则是通过增发的方式来给予节点奖励,支付其工资。每年增发的EOS比率为5%左右,按照总供应量10亿来计算,就是五千万EOS。
通胀的EOS用途:
??如上图,通胀的EOS币先发行到系统账户eosio中,其中的20%, 用于节点奖励;另外80%,用于EOS基金池,会在未来用于社区福利应用或者对EOS系统有所帮助的项目。该部分资金存入eosio.saving系统账户中。
??EOS节点分为两类:出块节点(Block Producer,常缩写为BP),备用节点(Block Producer Candidate)。EOS主网之中,设定得票为前21个节点为出块节点,其他的节点为备用节点。
??通胀作为节点奖励的那20%EOS,又分为两部分发放:
???? 25%用作出块奖励,按照一定的分配原则平均分配给21个出块节点。
???? 75%用作投票奖励,根据节点投票权重占比分配给出块节点和备用节点。
??出块节点得到的奖励是出块奖励和投票奖励两部分奖励之和,备用节点只能得到投票奖励,奖励额不足100 EOS,则无法获得奖励。
??出块奖励只向21个出块节点发放,其中涉及到一个出块奖励池的概念,由于每个节点领取时都会增发部分EOS,所以所有未领取的出块奖励都会放在出块奖励池中等待节点领取。每次单个节点领取时,能领取到的出块奖励数量计算公式如下:
??单个节点可领取的数量=出块奖励池里的EOS数量 * 该BP未领取奖励的出块数量 / 所有未领取奖励的区块数量
??由此看出节点出块数量,是节点领取奖励的重要依据,那节点出块数量是由谁统计又怎么实现共识的呢,下面我们会对这两点进行展开介绍。
二、节点出块量统计
??出块节点每出一个块,都会创建一个出块量累计交易(后面我们会叫块奖励交易),执行该交易会触发系统合约on_block动作,增加db状态库的出块量计数。
??生产节点每次出块前,会先准备块环境,主要是准备pending块,这部分够工作由chain/controller.cpp中的controller_impl::start_block函数实现,该函数会初始化pending块的_pending_block_state,需要打包进块的交易都会放入该pending块,start_block函数结束前还会创建一个块奖励交易,并调用push_transaction()函数进行执行,该交易执行时,会调用系统合约的on_block动作。 on_block是一个很基础的合约动作,在eosio.system合约下的 producer_pay.cpp文件中,主要功能是添加出块量计数和重选出块节点。下面通过代码展示说明这个过程。
1) controller_impl::start_block()函数
构造块奖励交易:
??这里说明一下,系统启动起来,会创建默认特权账户eosio,在没有加载系统合约system_contract时,块奖励交易onblock动作的合约执行体是空,不会执行任何操作。只有加载系统合约system_contract eosio到eosio账户后,才会真正调用该合约的onblock动作,进行块奖励累加计数操作。
2)交易执行:controller_impl::push_transaction()函数
3)在第2)步执行交易时,会根据1)中构造的交易体,执行onblock动作
4)出块时间到后,节点会打包pinding块,进行一些扫尾工作,对块进行签名完成本次出块动作。
三 、块奖励交易的共识及状态平衡实现
??细心的朋友肯定发现了,出块节点创建并执行了块奖励交易,将自己节点的db数据库中本节点出块数加一,但并没有打包到块里。那其它节点接收到该块,并不会收到该奖励交易,也就无从执行。那这笔块奖励交易是如何实现共识并保证节点间状态平衡的呢?
1、验证节点处理
??其实,其它生产节点作为验证节点在接收到新块后,先做了一些块验证操作,比如是否已经收到过该块,是否需要进行分叉处理等,通过验证处理后,就需要在节点内执行块中所有交易,保证节点间状态平衡。
??在执行块中交易前,也会和出块节点调用同样的函数controller_impl::start_block(),构造块处理环境,此时块奖励交易也同样会在收块节点创建并执行一遍。将块头所带的块生产者的出块值,在本节点db状态库中进行累加。实现了节点间该数据的状态平衡。
??有朋友可能要问了,节点接到块,就把生产者的出块数+1了,此时该块还没达到不可逆呢,万一后面在处理分叉时,该块被分叉废弃掉了,没有达到最终不可逆,那块奖励值还能减回来么?这就要感谢db状态库的回滚操作了,在需要废弃块时,会先对该块进行回滚操作,这笔块奖励交易也同样会被会滚掉的。
??上面讲的是块奖励交易的节点同步,也就是状态平衡的实现,但这笔交易没有挂在块上,块的全网共识是不包含此交易的,那块奖励交易的共识是如何实现的呢?
??这也是EOS实现巧妙的地方,需要各位自己理解啦,哈哈…。这里只简单提示一下,如果把这笔交易放到块中,由块共识,验证节点直接执行块中交易实现同步。那生产节点创建奖励交易时,可以多创建个几十次放到块上,那其它节点同步时,是不是也就同步了几十次,其实生产者只生产了一次块,却实现了几十次的计数,怎么规避?这样,由验证者收到块后,自行创建完成块奖励计数。是不是自动实现共识了呢?
2、块重播时处理
??块奖励交易不在块上,也就不会写入block_log文件中,那在节点重启需要通过块重播进行数据恢复时,块奖励交易如何写入db状态库的呢?其实理解了验证节点该操作的处理方式,这点就不难理解了。块重播,每次播放块中交易前,也要先调用controller_impl::start_block()构造pending块,这个块奖励交易的构造执行过程也就被执行了。
四、链接
星河公链
原文地址:https://blog.51cto.com/14267585/2415367