您正在查看: Surou 发布的文章

EOSPark 杂谈 | 投票

投票的分数是怎么计算的

score_of_vote=stake_of_EOS∗2^{current_year−2000}
举个例子,比如现在是2018年7月1号0点,我抵押了100个eos,那么我给超级节点A投了一票的分值就是:100 * 2^{18.5} = 37072760
过了半年,到了2019年1月1号0点,还是抵押了100个eos,那么我再次给超级节点A投了一票,那么节点A的总得分会先减去我前一票的分值37072760,然后再加上我当前的分值:100 * 2^{19}=52428800,详情可参见源码
当减少或者增加自己抵押的eos时,以前的投票的分数也会被即时更新,被投的节点总得分也会相应减少或增加。所以就是为什么你明明已经给某节点投过票,他们还在催你继续给他投的原因了,因为可能尽管你抵押的EOS数量没变,但你不同时刻的每一票的的分数是不一样的,它是随着时间递增的。

投票账户数是什么意思

投票账户数是从另一个维度来描述节点的支持率。表示有这么多个EOS用户来给他们喜欢的节点投票。不过,节点的排名并不是根据投票账户数来的,而是看上面讲的投票的总得分数来排序的。
所以你会经常发现有些节点的投票账户数很少,但是他们的得分却很高,原因就是有很多EOS大户给他们投票了,一个大户的一张票含金量非常高了。
前段时间发现一个很有意思的帐户 bpvoter.one,这个帐户下面创建了600多个小号,然后随便点进一个小号大概率都可以发现他们都抵押了2000到5000不等的EOS,这些小号基本上除了投票之外啥也不干,为啥不直接用一个帐号投呢。嘿嘿,人多热闹嘛,你懂的~

待申领奖励是怎么来的

节点们辛辛苦苦给我们出块、记账,活可不是白干的(每年的服务器成本还是很高的)。再加上EOS通过一些比如竞拍、买卖RAM过程中的手续费等操作会白白烧掉EOS,没有增发的话也会导致通货紧缩,所以有了每年增发不超过5%的EOS。那么这些增发的EOS是怎么分配的呢?
首先,增发的这部分EOS中的80%会打到一个叫 eosio.saving的账户里,可以看到现在为止已经有9百多万个EOS了,据说这账户里的EOS会用于社区建设。
然后,剩下的20%就是奖励给节点的了。这部分奖励又分两部分,其中的25%是作为出块奖励,剩下的75%就是我们这篇文章要介绍的投票奖励了。
那么这每年增发的5%里的20%里的75%的EOS是按什么规则分配给这么多节点的呢?

合约版本1.3.0之前的投票奖励分配规则

之前的分配规则比较简单粗暴,各自按照其得票的分数占比来瓜分这些奖励。以此刻的排名第一的eoshuobipool为例子,此时它的得分占比为2.596%,那么假如从现在开始它保持这个得票比率坚持一百年不动摇,那么它的得票奖励一年获得的奖励大致就是:
1000000000*0.05*0.2*0.75*0.02596 = 194700
每天的得票奖励大约为194700/365=533。不过这并不是一个节点的全部奖励,别忘了上面说过的还有出块奖励的哈。

合约版本1.3.0之后的投票奖励分配规则

终于来到本篇文章的重点了,该版本发布说明在 这里。新的分配规则在New producer pay algorithm章节里有说明,反正我是读不太懂,只能去源码里读全球通用语言了。
首先介绍一下大背景,新版本引入了一个叫做votepay share的概念,通过阅读代码我理解为这个新出的概念是一个类似于 得票分数随着时间成正比增长的股份 ,后面就是依据这个得票股份占比来分配投票奖励。这个得票股份的计算大致如下:
得票股份=得票分数*时间差
这个时间差就是任何两个 涉及到更新得票分数 的操作之间的时间差,比如:投票给某节点、增加/减少抵押的EOS、节点的申领奖励的操作等等。
如果仅仅是这样的话,其实跟旧规则差别不大,只是换个壳而已,但是其中有一个特别的限制:当节点有超过三天没有做claimrewards操作的时候,它就申领不到任何奖励,这些奖励会变相地被别的勤快的节点领走。
那么这个特别的限制会带来什么影响呢?你也许会说,现在的节点基本上都是天天领奖励,有些节点甚至都写了个脚本天天定时领,很少会有超过三天没领的。嗯,对于前21个出块节点来说是这样的,但是备选节点呢?我们知道通常备选节点没有机会出块,所以只有得票奖励,而得票奖励不满100EOS是无法领取的,所以就极有可能会造成三天没有claimrewards操作的尴尬情况。如果这次新版本的目的就是过滤掉垃圾备选节点的话,那我可以悄悄地告诉你一声,这个版本的系统合约是有bug的。
解释这个bug前,得先了解下新版本的逻辑,从两个action来阐述吧,一个是给节点投票的voteproducer,另一个就是节点的申领操作claimrewards。便于后面示例的解释,先给出一个宏定义:

公式的编号 公式的具体内容
A 节点得票股份+=节点得票分数*时间差
B 全网得票股份+=全网得票股份变化率*时间差
C 全网得票股份变化率+=节点得票分数
D 全网得票股份-=节点的得票股份
E 全网得票股份变化率-=节点得票分数
F 节点得票股份=0
G 节点奖励=(节点得分/全网总得分)*增发的得票EOS
H 节点奖励=(节点得票股份/全网得票股份)*增发的得票EOS
I 节点奖励=0

Voteproducer

示例编号 操作编号 节点的得票股份变化 全网的得票股份变化
0 vote0 A BC
1 vote1 F BDE
2 vote2 F B
3 vote3 A BC

Claimrewards
因为部署了新版本的系统合约后,还需要节点手动做一次updtrevision才开始走新版本的得票奖励结算逻辑,之后可以手动用regproducer重新更新一次节点,或者在下一次claimrewards的时候自动更新一次。
当updtrevision与regproducer/claimrewards之间无涉及到更新得票分数的操作时

示例编号 操作编号 节点获得的奖励 全网得票股份的变化
4 claim0 FG BC
5 claim1 ABHF D
6 claim2 I BADF

示例编号 操作编号 节点获得的奖励 全网得票股份的变化
7 claim1 I BDCF

当updtrevision与regproducer/claimrewards之间有涉及到更新得票分数的操作时

示例编号 操作编号 节点获得的奖励 全网得票股份的变化
8 vote0+claim0 ABHF D
9 vote0+claim0 AABHF D

示例总结

  • 通过示例1、2、6、7可以知道节点超过3天不claimrewards的话,得票奖励会被清0,损失的奖励继续在得票奖励池子里。等于变相的增加了其他节点的奖励。
  • 通过示例8、9可以知道节点在做完updtrevision操作后,要尽快执行一次regproducer或者claimrewards操作,否则会丢失这期间的可能的来自用户投票的奖励。这也是原文里最后一句话说可能遗失某些奖励的原因。

关于bug

现在再来解释前面提到的bug,这个bug存在于判断本次claimrewards离上次claimrewards是否已经超过3天。
相关源码如下:

if( producer_per_vote_pay < min_pervote_daily_pay ) {
         producer_per_vote_pay = 0;
}

......

_producers.modify( prod, 0, [&](auto& p) {
   p.last_claim_time = ct;
   p.unpaid_blocks   = 0;
});

在判断完得票奖励不足100EOS时,没有做任何处理,代码会径直走到p.last_claim_time = ct;这一行,个人觉得这应该是个bug,因为备选几点可以写个定时脚本天天做一次claimrewards操作,尽管他们可能并不能申领到任何奖励,但是依旧能成功刷新他们的last_claim_time时间。这样的话,新版本的关于超过3天未做claimrewards的判断就不可能成功了。

原文地址:https://articles.eospark.com/?p=74

EOS佳能离线工具

EOS佳能离线工具

工具简介:

EOS佳能离线工具是由EOS佳能主导,为保护数字货币投资者安全交易而开发的工具。

目前工具提供创建账号、质押/解质押、代理/解代理、投票、转账、赎回、购买/出售内存、修改私钥等功能。工具仍在完善中,欢迎提供建议。

免责声明:该工具仅供学习、交流,不对使用过程中产生的收益、损失负责,请知悉。

使用方法:

准备两台设备:离线设备、联网设备

首先:使用离线设备 ("重新build"、"使用已build的文件",选择其中一种方式)
重新build:
  1. 下载项目,打开控制台
  2. cd 项目根目录
  3. npm install
  4. npm start
  5. 在浏览器地址栏输入:http://localhost:3000
  6. 自行打包时,需注意:先将internals/webpack/webpack.base.babel.js中的 “ publicPath: '/' ” 改为:“ publicPath: './' ”,打包完成后,将其改回,避免影响 npm start。
    使用已build的文件:

    1.下载build.zip文件,解压后,使用浏览器打开index.html即可使用。

    然后:使用联网设备
  7. 打开 https://tool.eoscannon.io/
  8. 点击 复制初始化信息 按钮
  9. image
    然后:使用离线设备
  10. 打开http://localhost:3000,选择想要进行的操作页面
  11. 在json字段输入框,输入已复制的初始化信息
  12. image
  13. 按照提示输入生成签名报文所需的字段
  14. 点击 生成签名报文 按钮,生成的签名报文会自动填充在下面的输入框中。
  15. image
  16. 点击 复制签名报文 按钮,或扫描二维码,获取签名报文。
  17. image
    最后:使用联网设备
  18. https://tool.eoscannon.io/页面的发送交易输入框粘贴已复制的签名报文
  19. 点击 发送已签名报文 按钮
  20. image
  21. 根据提示确认是否交易成功

源代码地址:https://github.com/eoscannon/EosCannon-Offline-Tools

修改系统合约遇到的琐碎问题

  • EOSLIB_SERIALIZE 添加的变量名顺序要与struct添加变量名顺序一致,不然实例化后的存的变量数据会错位
  • Error 3080006: transaction took too long
    nodeos --max-transaction-time=1000
  • 之前table find 的iterator获取的是最新值
    如果后面有modify,再用前面iterator获取的数据将是后面modify后的新数据,如果想要旧数据,需要先保存下。

持续收集

设置vscode 换行符 (\n)

设置-->用户设置-->文本编辑器-->文件-->eol-->
设置为\n
或者直接搜索files:eol进行设置。

error: "assertion failure with message: system contract must first be initialized"

部署完eosio.system后,执行

cleos push action eosio init '[0,"4,SYS"]' -p eosio@active

参考:https://github.com/EOSIO/eos/issues/7061