【刘文彬】EOS多节点组网:商业场景分析以及节点启动时序

原文连接:醒者呆的博客园,www.cnblogs.com/Evsward/p/e…html

区块链公链都是基于p2p网络,本篇文章将创建一个多节点不一样职责参与的EOS的测试网络,根据路上发现的可作文章的技术点大作文章。 关键字:EOS组网,全节点,交易确认,boot sequence,stake,帕累托分配模型,竞选出块节点,EOS出块奖励,代理投票,resignnode

构建源节点

源节点就是第一个EOS节点(Genesis node),也能够叫主节点,EOS多节点组网的前提是已经对单机环境很是熟悉,咱们的架构以下:python

  • 配置config.ini,默认位置: ~/.local/share/nodeos/config/config.ini,须要解释的几个配置项:ios

    • http-server-address = 0.0.0.0:8888,这里设置四个0表明本地能够经过localhost或者127.0.0.1调用http接口,同时外部能够经过本机固定ip访问。
    • p2p-listen-endpoint = 0.0.0.0:9876,p2p网络本机监听端口,监听外部接入的p2p节点,这里的四个0的ip配置意义同上。
    • bnet-endpoint = 0.0.0.0:4321,bnet是使用一个很是简单的算法来同步两条区块链。主要工做是两条链上的确权,共识,广播,同步区块,保持默认配置便可。
    • p2p-peer-address = ip:port,对端p2p节点地址,能够设置多个。
    • enable-stale-production = true,意思是能够不通过确权直接出块,单节点时要配置为true,多节点出块因为须要各方确权共识,要配置为false。
    • producer-name = eosio,出块者,创世块,默认eosio帐户
    • signature-provider = EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV=KEY:5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3 ,密钥对,公钥加私钥,对应eosio帐户,这对秘钥是写死的,不可改变。

    注意对钱包进行修改时,例如删除钱包数据,从新建立,要预先手动kill掉keosd进程。算法

  • 采用后台进程的方式启动节点,同时保存日志。json

nohup nodeos>logs/nodeos-log.log 2>&1&api

  • 采用后台进程的方式启动钱包,同时保存日志。 nohup keosd>logs/keosd-log.log 2>&1&
  • 查看日志,经过 tail -500f logs/[filename] 的方式动态追踪日志。
  • 查看进程
liuwenbin@liuwenbin:~$ pgrep nodeos
1959
liuwenbin@liuwenbin:~$ pgrep keosd
1978
复制代码
  • 为cleos设置携带keosd的别名(keosd服务通常会与nodeos部署在同一台机器上,若是是普通用户的业务场景,则与nodeos服务不在一台机器,须要指定ip),保险起见,咱们直接将其设置到.bashrc文件中,并source使其生效。 alias cleos='cleos --wallet-url="http://localhost:8889"' 注意这里的--wallet-url的值要与钱包目录,默认是用户根目录下的eosio-wallet/config.ini中的http-server-address配置相同,从而保证咱们访问的钱包是同一个。若是要更换ip或端口的话,首先要修改config.ini的配置,而后启动keosd,而后alias别名覆盖设置便可。
  • 中止进程,注意因为咱们使用的

其余更详细的描述请转到《启动一个单独节点》。安全

单机准备就完成了,能够看出nodeos和keosd是分开的进程,最后经过alias别名将他们结合在了一块儿。
复制代码

构建全节点

全节点不出块但会保持同步完整区块数据到本地。在另外一台机器上,一样的拉取同版本源码构建安装命令,而后修改配置文件config.ini。这里咱们要修改的是:bash

去掉producer-name以及signature-provider配置项。
enable-stale-production配置在全节点无所谓,由于它只约束出块者,因此在这里能够去掉。
p2p-peer-address = ip:port,对端p2p节点地址,能够设置多个。
sync-fetch-span = 1000,同步区块的速度,步进。
复制代码

直接键入命令nodeos启动节点。网络

全节点版本更新

源码拉取-> checkout 最新版本号 -> 构建执行环境 -> 修改本地配置文件 而后使用命令:

nodeos --delete-all-block

清空旧的区块数据,从新启动链。

###全节点日志分析

3435662ms thread-0   net_plugin.cpp:3055           plugin_startup       ] starting listener, max clients is 2
3435671ms thread-0   net_plugin.cpp:749            connection           ] created connection to 47.93.127.182:9876
3435672ms thread-0   net_plugin.cpp:1969           connect              ] host: 47.93.127.182 port: 9876
3449419ms thread-0   net_plugin.cpp:773            connection           ] accepted network connection
3449851ms thread-0   producer_plugin.cpp:290       on_incoming_block    ] Received block 5f1a90b86a211c11... #1000 @ 2018-06-21T03:24:52.500 signed by eosio [trxs: 0, lib: 999, conf: 0, latency: 109957351 ms]
3450291ms thread-0   producer_plugin.cpp:290       on_incoming_block    ] Received block 1476bbf0e003fcf4... #2000 @ 2018-06-21T03:33:12.500 signed by eosio [trxs: 0, lib: 1999, conf: 0, latency: 109457791 ms]
3450785ms thread-0   producer_plugin.cpp:290       on_incoming_block    ] Received block 8c4bea86b3433b78... #3000 @ 2018-06-21T03:41:32.500 signed by eosio [trxs: 0, lib: 2999, conf: 0, latency: 108958285 ms]
3451298ms thread-0   producer_plugin.cpp:290       on_incoming_block    ] Received block ddd23622b0174f2c... #4000 @ 2018-06-21T03:49:52.500 signed by eosio [trxs: 0, lib: 3999, conf: 0, latency: 108458798 ms]
3451794ms thread-0   producer_plugin.cpp:290       on_incoming_block    ] Received block 37d4aa8148f4a429... #5000 @ 2018-06-21T03:58:12.500 signed by eosio [trxs: 0, lib: 4999, conf: 0, latency: 107959294 ms]
复制代码

全节点从新启动之后,能够观察到日志的内容与主节点有所不一样:

  • 首先它的区块的状态是on_incoming_block,而不是produce_block
  • Received block 5f1a90b86a211c11... #1000,后面是#2000, #3000 能够看出它是一千一千在同步的,这是依据config.ini的配置“sync-fetch-span = 1000” 决定的。在追上主节点出块之后,全节点就开始正常逐个同步了。

全节点服务

全节点只同步区块,不生成区块,它拥有完整的区块数据,所以能够经过全节点暴露的接口对链上数据进行查询,

http://全节点IP:8888/v1/chain/get_info

{
    "server_version": "79651199",
    "chain_id": "cf057bbfb72640471fd910bcb67639c22df9f92470936cddc1ade0e2f2e7dc4f",
    "head_block_num": 3381,
    "last_irreversible_block_num": 3380,
    "last_irreversible_block_id": "00000d349eb386e22de1b2bdde422377d49b3d3e997af25de1124ff41bad8eb8",
    "head_block_id": "00000d3500aec9d772fa3c0801b79366e76dc5e4426a574e6b14a56e220b865e",
    "head_block_time": "2018-06-25T08:06:55.000",
    "head_block_producer": "eosio",
    "virtual_block_cpu_limit": 5869808,
    "virtual_block_net_limit": 30835535,
    "block_cpu_limit": 199900,
    "block_net_limit": 1048576
}
复制代码

全节点功能模拟测试

如今有一台出块节点别名239,一台全节点别名182。

  • 此时全网只有一个eosio帐户,咱们要使用它建立一个新的帐户,咱们指望出块节点维护本身的秘钥,因此在239上用钱包导入eosio的私钥(虽然eosio的秘钥是公开的,这里只是模拟)
  • 182上导入一个新生成的私钥A,而后在239上建立帐户jack,creator是eosio,公钥是A的公钥。

@jack

182(全节点) 239(出块节点)
私钥A eosio

这样一来,182模拟是小白客户端,239是业务带头人,小白的秘钥彻底是由本身建立本身保存,而小白的帐户是业务带头人来建立的,小白只须要提供本身的公钥便可。这样一来,小白颇有安全感,由于帐户彻底是本身的,本身作任何事情都须要本地私钥签名,不会被冒名。而业务带头人也会很开心,由于他仍旧能够经营本身的社区,知道谁是经过本身建立的,是本身的用户,但也仅此而已,业务带头人并不能对小白有任何多余的管辖。

交易确认的方案分析

下面从区块数据上面研究以上行为:

方法一

帐户被建立是一个行为或者一个事务,建立时会返回一个transaction id,咱们手动去查一下这个transaction,

cleos get transaction 3b0b14a72cc4a98dd9145989xxxxxxxx

返回的数据很是庞大,其中包含了该transaction被记录的区块号,咱们经过区块号去查找区块信息,

cleos get block 203xx

返回的数据中,能够看到不少字段信息,其中有一个confirmed字段。

猜测TODO:这是区块确权的值,只要超过出块节点总数的2/3 + 1,就能够被认定为不可逆区块。但因为目前只有一个出块节点,该字段为0,因此这个猜测仍须要测试。
复制代码

方法二

在239上的事务的确认,咱们是否能够经过182上对事务结果的查询进行验证呢?答案是确定的。以上咱们在239上建立了帐户jack,咱们转到182,去查询

cleos get account jack

结果返回jack帐户是正常有效的,这就能够肯定另外一台机器239上的建立帐户的事务被确认。这种交易确认的方法要简单的多,属于结果验证论,意思也就是经过结果来判断是否完成一个动做。EOS就有可逆区块大小的配置,可逆区块就是未经确权的区块,一经确权就会变为不可逆区块上链。

实际上,在可逆区块确权的过程当中,以太坊是会全网广播的,但EOS只会BP之间广播,所以全节点接收到的必定是不可逆区块,经过全节点来确认交易是个不错的方法。
复制代码

方法二逆证

咱们在182上使用刚刚建立的jack来建立一个新的bob帐户,

root@iZ2ze5wsiqz8cj0lqgf73xZ:~/182# cleos create account jack bob EOS5MLNon1NFXqnS4koDiKdVg2iTuu5ZS2NeZxve1RHTTifiCUfjg
executed transaction: 0e95f8e9f3abdfbada4f1c10304f04f052a0b58364c3165da4551e9275ab86bb  200 bytes  298 us
# eosio <= eosio::newaccount {"creator":"jack","name":"bob","owner":{"threshold":1,"keys":[{"key":"EOS5MLNon1NFXqnS4koDiKdVg2iTuu...
warning: transaction executed locally, but may not be confirmed by the network yet
复制代码

而后在239上查询,

cleos get account bob

结果是一样的。也就是说,

方法二的交易确认重点不在因而否全节点来确认交易,出块节点一样能够确认交易。因此重点是是否可在其余机器上查到结果。只不过是由于EOS BP之间广播可逆区块的特性,因此去全节点上查询结果显得更稳妥。
复制代码

启动序列

前面咱们的主节点+全节点的测试采用的是按需研究,下面咱们整理一下真正去完整地启动一条链的步骤,也叫boot sequence,在这过程当中,也会包括我结合源码位置 tutorials/bios-boot-tutorial/bios-boot-tutorial.py 脚本进行某些操做的具体实现的分析,步骤以下:

Base 阶段

首先我定义为base阶段,由于这些操做咱们耳熟能详,这里进行一个总结:

kill全部nodeos以及keosd进程。
复制代码

killall keosd nodeos || true

  • 删除原钱包目录,再建立一个钱包目录,启动keosd,建立钱包,导入keys
  • 配置config.ini(以前提到屡次了,能够翻阅查看),启动链进程
  • 使用eosio建立系统级用户:'eosio.bpay','eosio.msig','eosio.names','eosio.ram','eosio.ramfee','eosio.saving','eosio.stake','eosio.token','eosio.vpay'(必须所有建立,不然暂时不报错,但后面会有不少坑)
  • 使用对应的系统级用户部署eosio.token和eosio.msig合约
  • 建立token并issue,注意:建立者为eosio的token就是主币的概念,默认的符号是SYS,是配置在源码中的,若是咱们须要修改主币符号须要更改源码从新部署。
  • eosio帐户部署system合约(部署system合约成功之后,没法再使用cleos create account了),而后开启多签名帐户受权:cleos push action eosio setpriv '["eosio.msig", 1]' -p eosio,这是上一篇文章中的坑。

Advance 阶段

启动序列运行到这里,咱们就已经拥有了一个独立节点,它安装了eosio.token, eosio.msig, eosio.system三个合约,目前它有eosio和eosio.msig两个特权帐户(eosio.msig帐户是eosio.msig合约的owner),以及其余eosio.*系统级用户,目前无普通用户。下面的操做由于咱们以前的研究中未涉及,因此这里另起一小节进行描述。

一,股权帐户

股权帐户staked accounts,就是咱们理解的普通用户。

  • 持股动做就是为EOSIO 区块链系统中的一个帐户分配token,从而获取一个实体(真实世界的实体,例如ICO中我的购买的某些东西)的过程。
  • 反之,抛股就是回购帐户的token,从而使其放弃某个实体的拥有权的过程。

持股和抛股是区块链整个生命周期中的重要行为模式。可是在启动阶段时的持股初始化操做是特殊的,帐户经过他们的token持股,然而直到producer选举出来以前,token都是冻结状态,也就是说帐户的持股身份不可抛弃。所以启动阶段的初始化持股操做的目的是:

分配token到帐户,准备使用,而后是参与投票过程,producer才能被选举出来,整个区块链才算是“活了”。
复制代码

Stake 流程

  1. 0.1个token(准确来说,不超过帐户token总数的10%)被用来持股内存Ram资源。默认状况下,cleos程序会持有8KB的内存在帐户的建立上,是由帐户建立者来支付的。在初始化阶段,帐户建立者都是eosio。
  2. 0.45个token抵押用来持有CPU资源,额外的,0.45个token用来持有network资源。
  3. 共须要9个token做为流动liquid token。
  4. 剩余的token均分为两部分,用来持有CPU和network各一半。

举例说明①:帐户A共拥有100个SYS,初始化持股操做为:

entity staked
RAM 0.1 SYS
CPU (0.45+45) SYS
network (0.45+45) SYS
liquid 9 SYS

这个抵押token置换资源使用权的过程很清晰,由于用户的token量是足够的,能够彻底按照上面的流程操做。 举例说明②:帐户B共拥有5个SYS,初始化持股操做为:

entity staked
RAM 0.1 SYS
CPU (0.45+0) SYS
network (0.45+0) SYS
liquid 4 SYS

这个抵押token置换资源使用权的过程与上面稍有不一样,由于用户的token量不足,因此按照上面流程操做,第三步流动liquid token的个数不足9个,经历前两步之后,帐户B仅剩余4个SYS,免为其难地,liquid token只能抵押4个SYS。而第四步,因为没有剩余token,因此也没必要执行了。

帕累托分配模型

根据以上对帐户持股抵押的研究结果,咱们翻回来讲boot sequence base 阶段的token SYS的分配策略,这个过程是夹在SYS create和issue的中间。是使用帕累托分配模型(Pareto distribution)将 十亿个SYS分发出去。

帕累托分配模型:是一个80-20规则,即80%的token被20%的人持有。具体实现过程在脚本bios-boot-tutorial.py中是经过Python Numpy库来生成帕累托分配的。
复制代码
def allocateFunds(b, e):
    dist = numpy.random.pareto(1.161, e - b).tolist() # 1.161 = 80/20 rule
    dist.sort()
    dist.reverse()
    factor = 1_000_000_000 / sum(dist)
    total = 0
    for i in range(b, e):
        funds = round(factor * dist[i - b] * 10000)
        if i >= firstProducer and i < firstProducer + numProducers:
            funds = max(funds, round(args.min_producer_funds * 10000))
        total += funds
        accounts[i]['funds'] = funds
    return total
复制代码

经过对源码的分析,能够知道accounts是accounts.json数据的集合,包含字段name、pub以及ppvt,分别表明帐户名称、公钥和私钥的属性。然而,allocateFunds函数要作的事情是为accounts集合的每个对象增长一个字段‘funds’,这个字段的值是经过帕累托分配模型计算出来的,可使众多的普通帐户的fund值呈现80-20规则。而目前funds的值并未真正是帐户所拥有的token,而是至关于一个计划!后面会有使用到的地方,这里系个扣b1。

感兴趣的同窗能够经过Python numpy.random.pareto函数的文档来研究它具体的思想以及实现方法。

建立股权帐户

下面使用system newaccount建立帐户,并抵押资产。

root@iZ2ze5wsiqz8cj0lqgf73tZ:~/239# cleos system newaccount eosio --transfer accountnum11 "EOS8aCaHAARJvWqD7XsbqK25c4ahDKT4TwmqjvSCFbD3bof8L16Fb" --stake-net "100000.0000 SYS" --stake-cpu "100000.0000 SYS" --buy-ram="0.1 SYS"
1601937ms thread-0   main.cpp:429                  create_action        ] result: {"binargs":"0000000000ea30551082d4334f4d1132e8030000000000000453595300000000"} arg: {"code":"eosio","action":"buyram","args":{"payer":"eosio","receiver":"accountnum11","quant":"0.1000 SYS"}}
1601938ms thread-0   main.cpp:429                  create_action        ] result: {"binargs":"0000000000ea30551082d4334f4d113200ca9a3b00000000045359530000000000ca9a3b00000000045359530000000001"} arg: {"code":"eosio","action":"delegatebw","args":{"from":"eosio","receiver":"accountnum11","stake_net_quantity":"100000.0000 SYS","stake_cpu_quantity":"100000.0000 SYS","transfer":true}}
executed transaction: 24a805a6a582a35ddd594ae25b7cf4a506244201d3fbcb4cfb4d079bf582764d  344 bytes  6072 us
# eosio <= eosio::newaccount {"creator":"eosio","name":"accountnum11","owner":{"threshold":1,"keys":[{"key":"EOS8aCaHAARJvWqD7Xsb...
# eosio <= eosio::buyram {"payer":"eosio","receiver":"accountnum11","quant":"0.1000 SYS"}
# eosio.token <= eosio.token::transfer {"from":"eosio","to":"eosio.ram","quantity":"0.0995 SYS","memo":"buy ram"}
# eosio <= eosio.token::transfer {"from":"eosio","to":"eosio.ram","quantity":"0.0995 SYS","memo":"buy ram"}
# eosio.ram <= eosio.token::transfer {"from":"eosio","to":"eosio.ram","quantity":"0.0995 SYS","memo":"buy ram"}
# eosio.token <= eosio.token::transfer {"from":"eosio","to":"eosio.ramfee","quantity":"0.0005 SYS","memo":"ram fee"}
# eosio <= eosio.token::transfer {"from":"eosio","to":"eosio.ramfee","quantity":"0.0005 SYS","memo":"ram fee"}
# eosio.ramfee <= eosio.token::transfer {"from":"eosio","to":"eosio.ramfee","quantity":"0.0005 SYS","memo":"ram fee"}
# eosio <= eosio::delegatebw {"from":"eosio","receiver":"accountnum11","stake_net_quantity":"100000.0000 SYS","stake_cpu_quantity...
# eosio.token <= eosio.token::transfer {"from":"eosio","to":"eosio.stake","quantity":"200000.0000 SYS","memo":"stake bandwidth"}
# eosio <= eosio.token::transfer {"from":"eosio","to":"eosio.stake","quantity":"200000.0000 SYS","memo":"stake bandwidth"}
# eosio.stake <= eosio.token::transfer {"from":"eosio","to":"eosio.stake","quantity":"200000.0000 SYS","memo":"stake bandwidth"}
warning: transaction executed locally, but may not be confirmed by the network yet
复制代码
注意这里--stake-net, --stake-cpu, --buy-ram的值都是手动随意填的,并非自动算出来的。
复制代码

关于这个问题,咱们就能够解扣了,扣b1提到的填充组装到accounts集合的字段‘funds’,就是用来计算这些参数的值的,具体计算方式,能够经过脚本源码来看:

def createStakedAccounts(b, e):
    ramFunds = round(args.ram_funds * 10000) # 经过参数ram_funds设置用于购买内存的资金
    configuredMinStake = round(args.min_stake * 10000) # 经过参数min_stake设置最小抵押值
    maxUnstaked = round(args.max_unstaked * 10000) # 最大非抵押值
    for i in range(b, e):
        a = accounts[i]
        funds = a['funds'] # 获取‘funds’值
        print('#' * 80)
        print('# %d/%d %s %s' % (i, e, a['name'], intToCurrency(funds)))
        print('#' * 80)
        if funds < ramFunds:
            print('skipping %s: not enough funds to cover ram' % a['name'])
            continue
        minStake = min(funds - ramFunds, configuredMinStake) # 最小抵押值
        unstaked = min(funds - ramFunds - minStake, maxUnstaked) # 非抵押值
        stake = funds - ramFunds - unstaked # 剩余可分配抵押值总数
        stakeNet = round(stake / 2) # net和cpu均分,各抵押一半。
        stakeCpu = stake - stakeNet
        print('%s: total funds=%s, ram=%s, net=%s, cpu=%s, unstaked=%s' % (a['name'], intToCurrency(a['funds']), intToCurrency(ramFunds), intToCurrency(stakeNet), intToCurrency(stakeCpu), intToCurrency(unstaked)))
        assert(funds == ramFunds + stakeNet + stakeCpu + unstaked)
        retry(args.cleos + 'system newaccount --transfer eosio %s %s --stake-net "%s" --stake-cpu "%s" --buy-ram "%s" ' % 
            (a['name'], a['pub'], intToCurrency(stakeNet), intToCurrency(stakeCpu), intToCurrency(ramFunds)))
        if unstaked: # 用完资源之后,再还回帐户。
            retry(args.cleos + 'transfer eosio %s "%s"' % (a['name'], intToCurrency(unstaked)))
复制代码

三个变量stakeNet,stakeCpu,ramFunds就是咱们用来抵押资源的值,这个策略与前面提到的“Stake 流程”有些不一样,咱们经过脚本参数--ram-funds指定了内存购买数,默认值是上面提到的0.1 SYS,另外还有最小抵押值和最大非抵押值等,因此这个流程更加复杂,具有生产可行性。

二,注册区块生产者的候选人

咱们能够指定某个或某些个股权帐户做为区块生产者。这个过程首先要先将股权帐户注册为一个区块生产者候选人,经过如下命令执行:

root@iZ2ze5wsiqz8cj0lqgf73tZ:~/239# cleos system regproducer accountnum11 EOS8aCaHAARJvWqD7XsbqK25c4ahDKT4TwmqjvSCFbD3bof8L16Fb https://accountnum11.com/EOS8aCaHAARJvWqD7XsbqK25c4ahDKT4TwmqjvSCFbD3bof8L16Fb
400025ms thread-0   main.cpp:429                  create_action        ] result: {"binargs":"1082d4334f4d11320003e5419cfdd7d6d511bc2c2f7f88c0e93432cf0ff39718fe99491e18e2069dd2674e68747470733a2f2f6163636f756e746e756d31312e636f6d2f454f5338614361484141524a7657714437587362714b323563346168444b543454776d716a76534346624433626f66384c313646620000"} arg: {"code":"eosio","action":"regproducer","args":{"producer":"accountnum11","producer_key":"EOS8aCaHAARJvWqD7XsbqK25c4ahDKT4TwmqjvSCFbD3bof8L16Fb","url":"https://accountnum11.com/EOS8aCaHAARJvWqD7XsbqK25c4ahDKT4TwmqjvSCFbD3bof8L16Fb","location":0}}
executed transaction: 8181fe1cd180afeae280b8f8f2ffc735aa63cb10a8c0cf12a86198e179203228  216 bytes  1481 us
# eosio <= eosio::regproducer {"producer":"accountnum11","producer_key":"EOS8aCaHAARJvWqD7XsbqK25c4ahDKT4TwmqjvSCFbD3bof8L16Fb","u...
warning: transaction executed locally, but may not be confirmed by the network yet
复制代码

参数介绍:

  • 指定股权帐户名称
  • 指定该帐户将来做为区块生产者的公钥(这个能够与帐户自己的公钥不一样)
  • url,通常由生产者帐户名加公钥组成。用来展现区块生产者的信息的网址,这个网址是咱们本身维护的,至关于咱们的官网,主要介绍一些区块生产者的名称,愿景,意义等,让其余节点更加了解本身,从而为本身投票。

候选人列表展现

下面咱们再用相同的流程多注册几个候选人,而后展现候选人列表:

root@iZ2ze5wsiqz8cj0lqgf73tZ:~/239# cleos system listproducers
Producer      Producer key                                           Url                                                         Scaled votes
a             EOS8aCaHAARJvWqD7XsbqK25c4ahDKT4TwmqjvSCFbD3bof8L16Fb  https://www.baidu.com                                       0.0000
accountnum1   EOS8aCaHAARJvWqD7XsbqK25c4ahDKT4TwmqjvSCFbD3bof8L16Fb  https://www.google.com                                      0.0000
accountnum11  EOS8aCaHAARJvWqD7XsbqK25c4ahDKT4TwmqjvSCFbD3bof8L16Fb  https://accountnum11.com/EOS8aCaHAARJvWqD7XsbqK25c4ahDKT4Tw 0.0000
复制代码

两个问题:

  • 我注册的三个候选人的生产公钥都是相同的,好像也没有失败,看看后面有没有坑吧。
  • 使用system newaccount时并未有帐户长度的限制,没有让我去bid 名字,这个后面再观察研究。

三,候选人启动链

使用一个候选人帐户开启一条链,配置config.ini,手动去写比较复杂。咱们直接使用脚本执行,执行前先安装numpy

sudo apt-get install python3-numpy

而后修改脚本中的一些数字为有效值,开始执行(咱们约束只要3个bp,8个普通帐户),

./bios-boot-tutorial.py -a --user-limit 8 --producer-limit 3

前面提到的流程全都跑完了,跑到当前位置停下,能够看到,先来查一下候选人列表:

bios-boot-tutorial.py: ../../build/programs/cleos/cleos --wallet-url http://localhost:6666 --url http://localhost:8000 system listproducers
Producer      Producer key                                           Url                                                         Scaled votes
producer111a  EOS8imf2TDq6FKtLZ8mvXPWcd6EF2rQwo8zKdLNzsbU9EiMSt9Lwz  https://producer111a.com/EOS8imf2TDq6FKtLZ8mvXPWcd6EF2rQwo8 0.0000
producer111b  EOS7Ef4kuyTbXbtSPP5Bgethvo6pbitpuEz2RMWhXb8LXxEgcR7MC  https://producer111b.com/EOS7Ef4kuyTbXbtSPP5Bgethvo6pbitpuE 0.0000
producer111c  EOS5n442Qz4yVc4LbdPCDnxNSseAiUCrNjRxAfPhUvM8tWS5svid6  https://producer111c.com/EOS5n442Qz4yVc4LbdPCDnxNSseAiUCrNj 0.0000
复制代码

而后分别开启这三个帐户的链,

bios-boot-tutorial.py: rm -rf ./nodes/01-producer111a/
bios-boot-tutorial.py: mkdir -p ./nodes/01-producer111a/

bios-boot-tutorial.py: ../../build/programs/nodeos/nodeos    --max-irreversible-block-age 9999999    --contracts-console    --genesis-json /root/lwb-work/eos/tutorials/bios-boot-tutorial/genesis.json    --blocks-dir /root/lwb-work/eos/tutorials/bios-boot-tutorial/nodes/01-producer111a/blocks    --config-dir /root/lwb-work/eos/tutorials/bios-boot-tutorial/nodes/01-producer111a    --data-dir /root/lwb-work/eos/tutorials/bios-boot-tutorial/nodes/01-producer111a    --chain-state-db-size-mb 1024    --http-server-address 127.0.0.1:8001    --p2p-listen-endpoint 127.0.0.1:9001    --max-clients 13    --p2p-max-nodes-per-host 13    --enable-stale-production    --producer-name producer111a    --private-key '["EOS8imf2TDq6FKtLZ8mvXPWcd6EF2rQwo8zKdLNzsbU9EiMSt9Lwz","5KLGj1HGRWbk5xNmoKfrcrQHXvcVJBPdAckoiJgFftXSJjLPp7b"]'    --plugin eosio::http_plugin    --plugin eosio::chain_api_plugin    --plugin eosio::producer_plugin    --p2p-peer-address localhost:9000    2>>./nodes/01-producer111a/stderr


bios-boot-tutorial.py: rm -rf ./nodes/02-producer111b/
bios-boot-tutorial.py: mkdir -p ./nodes/02-producer111b/

bios-boot-tutorial.py: ../../build/programs/nodeos/nodeos    --max-irreversible-block-age 9999999    --contracts-console    --genesis-json /root/lwb-work/eos/tutorials/bios-boot-tutorial/genesis.json    --blocks-dir /root/lwb-work/eos/tutorials/bios-boot-tutorial/nodes/02-producer111b/blocks    --config-dir /root/lwb-work/eos/tutorials/bios-boot-tutorial/nodes/02-producer111b    --data-dir /root/lwb-work/eos/tutorials/bios-boot-tutorial/nodes/02-producer111b    --chain-state-db-size-mb 1024    --http-server-address 127.0.0.1:8002    --p2p-listen-endpoint 127.0.0.1:9002    --max-clients 13    --p2p-max-nodes-per-host 13    --enable-stale-production    --producer-name producer111b    --private-key '["EOS7Ef4kuyTbXbtSPP5Bgethvo6pbitpuEz2RMWhXb8LXxEgcR7MC","5K6qk1KaCYYWX86UhAfUsbMwhGPUqrqHrZEQDjs9ekP5j6LgHUu"]'    --plugin eosio::http_plugin    --plugin eosio::chain_api_plugin    --plugin eosio::producer_plugin    --p2p-peer-address localhost:9000    --p2p-peer-address localhost:9001    2>>./nodes/02-producer111b/stderr


bios-boot-tutorial.py: rm -rf ./nodes/03-producer111c/
bios-boot-tutorial.py: mkdir -p ./nodes/03-producer111c/

bios-boot-tutorial.py: ../../build/programs/nodeos/nodeos    --max-irreversible-block-age 9999999    --contracts-console    --genesis-json /root/lwb-work/eos/tutorials/bios-boot-tutorial/genesis.json    --blocks-dir /root/lwb-work/eos/tutorials/bios-boot-tutorial/nodes/03-producer111c/blocks    --config-dir /root/lwb-work/eos/tutorials/bios-boot-tutorial/nodes/03-producer111c    --data-dir /root/lwb-work/eos/tutorials/bios-boot-tutorial/nodes/03-producer111c    --chain-state-db-size-mb 1024    --http-server-address 127.0.0.1:8003    --p2p-listen-endpoint 127.0.0.1:9003    --max-clients 13    --p2p-max-nodes-per-host 13    --enable-stale-production    --producer-name producer111c    --private-key '["EOS5n442Qz4yVc4LbdPCDnxNSseAiUCrNjRxAfPhUvM8tWS5svid6","5JCStvbRgUZ6hjyfUiUaxt5iU3HP6zC1kwx3W7SweaEGvs4EPfQ"]'    --plugin eosio::http_plugin    --plugin eosio::chain_api_plugin    --plugin eosio::producer_plugin    --p2p-peer-address localhost:9000    --p2p-peer-address localhost:9001    --p2p-peer-address localhost:9002    2>>./nodes/03-producer111c/stderr
复制代码

启动候选人链时有几点注意:

  1. 要保证路径下包含genesis.json文件,用于描述启动初始化链属性信息。
  2. 命令中组装的参数做用域仅对当下生效,与在/nodes/01-producer111a目录下的config.ini文件中的配置不一样。
  3. 这三个候选人分别占用了http的端口8001,8002,8003,p2p端口9001,9002,9003,分别监听其余p2p地址。
  4. 三个候选人的出块帐户均设为本身,同时设置了对应的密钥对。
  5. 每一个链的日志,包括源节点和三个候选人的都时刻同步在各自节点目录下的文件stderr中。

四,为候选人投票

任意一个股权用户都可以投票,

root@iZ2ze5wsiqz8cj0lqgf73tZ:~/lwb-work/eos/tutorials/bios-boot-tutorial/nodes# cleos --wallet-url http://localhost:6666 --url http://localhost:8000 system voteproducer prods useraaaaaaab producer111a
2190240ms thread-0   main.cpp:429                  create_action        ] result: {"binargs":"708c31c6187315d600000000000000000160420857219de8ad"} arg: {"code":"eosio","action":"voteproducer","args":{"voter":"useraaaaaaab","proxy":"","producers":["producer111a"]}}
executed transaction: 729381cc691690061d9724b3553e1eca834317d9b4ebf8067f5093a97345d056  120 bytes  2242 us
# eosio <= eosio::voteproducer {"voter":"useraaaaaaab","proxy":"","producers":["producer111a"]}
warning: transaction executed locally, but may not be confirmed by the network yet
复制代码

再来查看候选人列表:

root@iZ2ze5wsiqz8cj0lqgf73tZ:~/lwb-work/eos/tutorials/bios-boot-tutorial/nodes# cleos --wallet-url http://localhost:6666 --url http://localhost:8000 system listproducers
Producer      Producer key                                           Url                                                         Scaled votes
producer111a  EOS8imf2TDq6FKtLZ8mvXPWcd6EF2rQwo8zKdLNzsbU9EiMSt9Lwz  https://producer111a.com/EOS8imf2TDq6FKtLZ8mvXPWcd6EF2rQwo8 1.0000
producer111b  EOS7Ef4kuyTbXbtSPP5Bgethvo6pbitpuEz2RMWhXb8LXxEgcR7MC  https://producer111b.com/EOS7Ef4kuyTbXbtSPP5Bgethvo6pbitpuE 0.0000
producer111c  EOS5n442Qz4yVc4LbdPCDnxNSseAiUCrNjRxAfPhUvM8tWS5svid6  https://producer111c.com/EOS5n442Qz4yVc4LbdPCDnxNSseAiUCrNj 0.0000
复制代码

能够看到候选人producer111a的Scaled项变为1。那么何时算投票结束呢?

直到有效投票数超过总可投票的15%,排在前面的候选者就开始出块。
复制代码

候选人竞选成功,开始出块

注意一个帐户只能头一次票给一个候选人,屡次投票能够执行成功,但票数仅第一次有效。
复制代码

给producer111a投票之后,我一直在监控几个日志平台,发现不知何时,00-eosio节点已经不出块了,开始接受块,而01-producer111a节点显示开始出块,其余候选人仍旧接受块。这时候我更换策略,开始用股权帐户为producer111b投票,投完之后,没过多久,让我捕捉到01-producer111a节点的日志和producer111b节点的日志变化了。

01-producer111a节点的日志:

2887500ms thread-0   producer_plugin.cpp:1073      produce_block        ] Produced block 00000a7bd2326f26... #2683 @ 2018-06-27T11:48:07.500 signed by producer111a [trxs: 0, lib: 2682, confirmed: 0]
2887504ms thread-0   controller.cpp:752            start_block          ] promoting proposed schedule (set in block 2683) to pending; current block: 2684 lib: 2683 schedule: {"version":2,"producers":[{"producer_name":"producer111a","block_signing_key":"EOS8imf2TDq6FKtLZ8mvXPWcd6EF2rQwo8zKdLNzsbU9EiMSt9Lwz"},{"producer_name":"producer111b","block_signing_key":"EOS7Ef4kuyTbXbtSPP5Bgethvo6pbitpuEz2RMWhXb8LXxEgcR7MC"}]}
2888000ms thread-0   producer_plugin.cpp:1073      produce_block        ] Produced block 00000a7c22b963b7... #2684 @ 2018-06-27T11:48:08.000 signed by producer111a [trxs: 0, lib: 2683, confirmed: 0]
2888500ms thread-0   producer_plugin.cpp:1073      produce_block        ] Produced block 00000a7d96adbfc0... #2685 @ 2018-06-27T11:48:08.500 signed by producer111a [trxs: 0, lib: 2684, confirmed: 0]
2889003ms thread-0   producer_plugin.cpp:290       on_incoming_block    ] Received block 6189af49442e9971... #2686 @ 2018-06-27T11:48:09.000 signed by producer111b [trxs: 0, lib: 2684, conf: 0, latency: 3 ms]
复制代码

02-producer111b节点的日志:

2887510ms thread-0   producer_plugin.cpp:290       on_incoming_block    ] Received block d2326f262fefb570... #2683 @ 2018-06-27T11:48:07.500 signed by producer111a [trxs: 0, lib: 2682, conf: 0, latency: 10 ms]
2887510ms thread-0   controller.cpp:752            start_block          ] promoting proposed schedule (set in block 2683) to pending; current block: 2684 lib: 2683 schedule: {"version":2,"producers":[{"producer_name":"producer111a","block_signing_key":"EOS8imf2TDq6FKtLZ8mvXPWcd6EF2rQwo8zKdLNzsbU9EiMSt9Lwz"},{"producer_name":"producer111b","block_signing_key":"EOS7Ef4kuyTbXbtSPP5Bgethvo6pbitpuEz2RMWhXb8LXxEgcR7MC"}]}
2888002ms thread-0   controller.cpp:752            start_block          ] promoting proposed schedule (set in block 2683) to pending; current block: 2684 lib: 2683 schedule: {"version":2,"producers":[{"producer_name":"producer111a","block_signing_key":"EOS8imf2TDq6FKtLZ8mvXPWcd6EF2rQwo8zKdLNzsbU9EiMSt9Lwz"},{"producer_name":"producer111b","block_signing_key":"EOS7Ef4kuyTbXbtSPP5Bgethvo6pbitpuEz2RMWhXb8LXxEgcR7MC"}]}
2888004ms thread-0   producer_plugin.cpp:290       on_incoming_block    ] Received block 22b963b7ef2954ae... #2684 @ 2018-06-27T11:48:08.000 signed by producer111a [trxs: 0, lib: 2683, conf: 0, latency: 4 ms]
2888503ms thread-0   producer_plugin.cpp:290       on_incoming_block    ] Received block 96adbfc0c04b06eb... #2685 @ 2018-06-27T11:48:08.500 signed by producer111a [trxs: 0, lib: 2684, conf: 0, latency: 3 ms]
2889000ms thread-0   producer_plugin.cpp:1073      produce_block        ] Produced block 00000a7e6189af49... #2686 @ 2018-06-27T11:48:09.000 signed by producer111b [trxs: 0, lib: 2684, confirmed: 0]
复制代码

能够看出,

  • 01-producer111a节点由produce_block,经历start_block之后,改成on_incoming_block。
  • 02-producer111b节点由on_incoming_block,经历start_block之后,改成produce_block。

那么这个start_block事件的内容在两个节点里报出来的都是相同的内容:

promoting proposed schedule (set in block 2683) to pending; current block: 2684 lib: 2683 schedule: {"version":2,"producers":[{"producer_name":"producer111a","block_signing_key":"EOS8imf2TDq6FKtLZ8mvXPWcd6EF2rQwo8zKdLNzsbU9EiMSt9Lwz"},{"producer_name":"producer111b","block_signing_key":"EOS7Ef4kuyTbXbtSPP5Bgethvo6pbitpuEz2RMWhXb8LXxEgcR7MC"}]}
复制代码

意思就是producer111b晋升为出块节点。接着咱们再继续观察日志,会发现:

producer111a和producer111b是交替出块,producer111a节点并无由于producer111b的晋升而再也不出块。
复制代码

producer111c没有人给他投票,因此继续接收。

查看全部候选人状态

经过table来查询全部候选人(包含出块者)目前的状态,

root@iZ2ze5wsiqz8cj0lqgf73tZ:~/lwb-work/eos/tutorials/bios-boot-tutorial/nodes# cleos --wallet-url http://localhost:6666 --url http://localhost:8000 get table eosio eosio producers
{
  "rows": [{
      "owner": "producer111a",
      "total_votes": "140.00000000000000000",
      "producer_key": "EOS8imf2TDq6FKtLZ8mvXPWcd6EF2rQwo8zKdLNzsbU9EiMSt9Lwz",
      "is_active": 1,
      "url": "https://producer111a.com/EOS8imf2TDq6FKtLZ8mvXPWcd6EF2rQwo8zKdLNzsbU9EiMSt9Lwz",
      "unpaid_blocks": 1124,
      "last_claim_time": "1530101102000000",
      "location": 0
    },{
      "owner": "producer111b",
      "total_votes": "3767537711703276032.00000000000000000",
      "producer_key": "EOS7Ef4kuyTbXbtSPP5Bgethvo6pbitpuEz2RMWhXb8LXxEgcR7MC",
      "is_active": 1,
      "url": "https://producer111b.com/EOS7Ef4kuyTbXbtSPP5Bgethvo6pbitpuEz2RMWhXb8LXxEgcR7MC",
      "unpaid_blocks": 2138,
      "last_claim_time": 0,
      "location": 0
    },{
      "owner": "producer111c",
      "total_votes": "0.00000000000000000",
      "producer_key": "EOS5n442Qz4yVc4LbdPCDnxNSseAiUCrNjRxAfPhUvM8tWS5svid6",
      "is_active": 1,
      "url": "https://producer111c.com/EOS5n442Qz4yVc4LbdPCDnxNSseAiUCrNjRxAfPhUvM8tWS5svid6",
      "unpaid_blocks": 0,
      "last_claim_time": 0,
      "location": 0
    }
  ],
  "more": false
}
复制代码

经过打印结果能够观察到三个候选节点的收到的投票数,公钥,url等属性,其中unpaid_blocks属性是还未申领奖励的区块数(属于该节点出的块),last_claim_time属性是上一次申领时间。

五,区块生产者认领奖励

与比特币和以太坊相同的是,EOS的出块者也有挖矿奖励,只是比起前两者自动发放奖励,EOS出块者须要自行申领奖励,

root@iZ2ze5wsiqz8cj0lqgf73tZ:~/lwb-work/eos/tutorials/bios-boot-tutorial/nodes# cleos --wallet-url http://localhost:6666 --url http://localhost:8000 system claimrewards producer111a
301762ms thread-0   main.cpp:429                  create_action        ] result: {"binargs":"60420857219de8ad"} arg: {"code":"eosio","action":"claimrewards","args":{"owner":"producer111a"}}
executed transaction: 4b7e9b1bec0f04f4d96aa4e61f9bc45516411cf6be3f82720e9c8cb6dfb7a162  104 bytes  6343 us
# eosio <= eosio::claimrewards {"owner":"producer111a"}
# eosio.token <= eosio.token::issue {"to":"eosio","quantity":"1855.4398 SYS","memo":"issue tokens for producer pay and savings"}
# eosio.token <= eosio.token::transfer {"from":"eosio","to":"eosio.saving","quantity":"1484.3519 SYS","memo":"unallocated inflation"}
# eosio <= eosio.token::transfer {"from":"eosio","to":"eosio.saving","quantity":"1484.3519 SYS","memo":"unallocated inflation"}
# eosio.saving <= eosio.token::transfer {"from":"eosio","to":"eosio.saving","quantity":"1484.3519 SYS","memo":"unallocated inflation"}
# eosio.token <= eosio.token::transfer {"from":"eosio","to":"eosio.bpay","quantity":"92.7719 SYS","memo":"fund per-block bucket"}
# eosio <= eosio.token::transfer {"from":"eosio","to":"eosio.bpay","quantity":"92.7719 SYS","memo":"fund per-block bucket"}
# eosio.bpay <= eosio.token::transfer {"from":"eosio","to":"eosio.bpay","quantity":"92.7719 SYS","memo":"fund per-block bucket"}
# eosio.token <= eosio.token::transfer {"from":"eosio","to":"eosio.vpay","quantity":"278.3160 SYS","memo":"fund per-vote bucket"}
# eosio <= eosio.token::transfer {"from":"eosio","to":"eosio.vpay","quantity":"278.3160 SYS","memo":"fund per-vote bucket"}
# eosio.vpay <= eosio.token::transfer {"from":"eosio","to":"eosio.vpay","quantity":"278.3160 SYS","memo":"fund per-vote bucket"}
# eosio.token <= eosio.token::transfer {"from":"eosio.bpay","to":"producer111a","quantity":"53.4400 SYS","memo":"producer block pay"}
# eosio.bpay <= eosio.token::transfer {"from":"eosio.bpay","to":"producer111a","quantity":"53.4400 SYS","memo":"producer block pay"}
# producer111a <= eosio.token::transfer {"from":"eosio.bpay","to":"producer111a","quantity":"53.4400 SYS","memo":"producer block pay"}
warning: transaction executed locally, but may not be confirmed by the network yet
复制代码

从打印结果能够看到申领奖励的执行路径,这时候咱们再来检查一下producer111a帐户的余额,

root@iZ2ze5wsiqz8cj0lqgf73tZ:~/lwb-work/eos/tutorials/bios-boot-tutorial/nodes# cleos --wallet-url http://localhost:6666 --url http://localhost:8000 get currency balance eosio.token producer111a
63.4400 SYS
复制代码

刚刚发放的奖励53.4400 SYS已打入余额中,而以前的10 SYS是哪里来的?

脚本参数--max-unstaked,默认值为10,在股权帐户被建立的时候,会读取这个参数的值,根据这个值来计算抵押建立帐户消耗的资源,帐户建立过程当中,资源抵押的token是由eosio支付的,当帐户建立完毕,资源被释放(即unstake),则会将10 SYS从eosio转帐到帐户中去。
复制代码

六,代理投票

投票过程说实在有点麻烦,所以有了代理投票的功能,代理投票分为两步:

注册代理

咱们经过命令将某个股权帐户注册为一个代理,可接受小白的受权。

root@iZ2ze5wsiqz8cj0lqgf73tZ:~/lwb-work/eos/tutorials/bios-boot-tutorial/nodes# cleos --wallet-url http://localhost:6666 --url http://localhost:8000 system regproxy useraaaaaaab
2212425ms thread-0   main.cpp:429                  create_action        ] result: {"binargs":"708c31c6187315d601"} arg: {"code":"eosio","action":"regproxy","args":{"proxy":"useraaaaaaab","isproxy":true}}
executed transaction: 4a8f2bad3a6f2e0d34d5ec1134e241f850e8a0c659cc65ce3cf4bedfaf28c97c  104 bytes  1216 us
# eosio <= eosio::regproxy {"proxy":"useraaaaaaab","isproxy":1}
warning: transaction executed locally, but may not be confirmed by the network yet
复制代码

能够看到useraaaaaaab帐户的isproxy项已置为1,成为代理。

代理受权

root@iZ2ze5wsiqz8cj0lqgf73tZ:~/lwb-work/eos/tutorials/bios-boot-tutorial/nodes# cleos --wallet-url http://localhost:6666 --url http://localhost:8000 system voteproducer proxy useraaaaaaaa useraaaaaaab
2402472ms thread-0   main.cpp:429                  create_action        ] result: {"binargs":"608c31c6187315d6708c31c6187315d600"} arg: {"code":"eosio","action":"voteproducer","args":{"voter":"useraaaaaaaa","proxy":"useraaaaaaab","producers":[]}}
executed transaction: c5501c7487d9ffcf6ce86b76f5c75d9fd68e22c84b376612d5266ea76199d37e  112 bytes  3062 us
# eosio <= eosio::voteproducer {"voter":"useraaaaaaaa","proxy":"useraaaaaaab","producers":[]}
# useraaaaaaab <= eosio::voteproducer {"voter":"useraaaaaaaa","proxy":"useraaaaaaab","producers":[]}
warning: transaction executed locally, but may not be confirmed by the network yet
复制代码

咱们成功将帐户useraaaaaaaa的投票权代理给了代理帐户useraaaaaaab。

代理投票

因为每一个帐户给候选者只能投一次票,咱们能够经过这个特性来验证代理投票。首先咱们先经过get table查询三个候选者的票数,而后使用useraaaaaaab帐户为producer111a投票,再次get table查询能够发现producer111a的票数升高了,此时再使用useraaaaaaaa帐户为producer111a进行投票,操做成功,但get table去查询发现producer111a的票数不变,这说明useraaaaaaaa帐户的票数已经经过代理帐户useraaaaaaab成功代理投票。

*七,resign eosio以及eosio.系统级帐户

当咱们已经选举出来称职的出块者之后,出块者已经由原来的eosio变为众多出块者轮番出块,eosio变为接收块,随着启动时序接近尾声,eosio的做用愈来愈小,但它的权限还是公开的密钥对,这是一件颇有风险的事,因此综合考量,这一步骤,咱们要改造eosio的权限。

root@iZ2ze5wsiqz8cj0lqgf73tZ:~/lwb-work/eos/tutorials/bios-boot-tutorial/nodes# cleos --wallet-url http://localhost:6666 --url http://localhost:8000 push action eosio updateauth '{"account":"eosio","permission":"owner","parent":"","auth":{"threshold":1,"keys":[],"waits":[],"accounts":[{"weight":1,"permission":{"actor":"eosio.prods","permission":"active"}}]}}' -p eosio@owner
executed transaction: f738e289214b31b43255cd562bf12ac811f2c7b4cc0acc0b887a8ec7db603679  144 bytes  869 us
# eosio <= eosio::updateauth {"account":"eosio","permission":"owner","parent":"","auth":{"threshold":1,"keys":[],"accounts":[{"pe...
warning: transaction executed locally, but may not be confirmed by the network yet
复制代码

经过为eosio帐户更新permission,这里没有使用‘cleos set account permission ...’,是由于部署system合约之后,绝大部分的直接操做都失效了,因此转而使用system合约的push action eosio updateauth来更新eosio的permission为:

{
    "account": "eosio",
    "permission": "owner",
    "parent": "",
    "auth": {
        "threshold": 1,
        "keys": [],
        "waits": [],
        "accounts": [
            {
                "weight": 1,
                "permission": {
                    "actor": "eosio.prods",
                    "permission": "active"
                }
            }
        ]
    }
}
复制代码

最终,咱们检查eosio的owner权限为:

privileged: true
permissions:
     owner     1:    1 eosio.prods@active,
复制代码

而后对eosio.prods帐户产生了好奇,那么咱们就继续查看这个帐户:

root@iZ2ze5wsiqz8cj0lqgf73tZ:~/lwb-work/eos/tutorials/bios-boot-tutorial/nodes# cleos --wallet-url http://localhost:6666 --url http://localhost:8000 get account eosio.prods
permissions:
     owner     1:
        active     2:    1 producer111a@active, 1 producer111b@active,
           prod.major     2:    1 producer111a@active, 1 producer111b@active,
              prod.minor     1:    1 producer111a@active, 1 producer111b@active,
memory:
     quota:       unlimited  used:     2.594 KiB

net bandwidth:
     used:               unlimited
     available:          unlimited
     limit:              unlimited

cpu bandwidth:
     used:               unlimited
     available:          unlimited
     limit:              unlimited
复制代码

能够发现这个帐户eosio.prods已经彻底被出块者(注意不是候选者,而是成功出块的节点帐户)占据,而且有了prod.major和prod.minor两个自定义权限,这里不展开了。

这样一来,咱们已经干掉了eosio的owner权限,同理,干掉eosio的active权限。

resign系统帐户

eosio帐户的权限被resign之后,正像使用eosio.prods帐户来resign eosio同样,咱们使用eosio来resign 全部的系统帐户eosio.*。

resign目标:eosio帐户以及eosio.*帐户的权限被最终下发到区块生产者帐户。
复制代码

启动脚本

到目前为止,咱们已完成了全部启动阶段的操做的研究,能够看出这个启动流程有些麻烦,咱们第一次去手动操做是为了理解每一步的具体含义和内容,而若是以后的生产阶段仍旧采起手动配置的方式无疑效率过低,所以上面反复说起的源码自带的脚本bios-boot-tutorial.py很好的解决了这个问题。前面的分析已基本覆盖脚本的内容,这里介绍上面未涵盖的三个步骤,这三个步骤是在以上内容的最后来执行的:

使用多签名来替换eosio对system合约的控制,这个不难理解,system合约至关于“系统设置”,这个权限层级很高,咱们已经resign了eosio,之后system合约相关的操做须要经过提propose,而后经由参与resign eosio的权限帐户的审批来最终执行成功。这个过程不介绍了,能够参考《EOS商业落地利器:多签名操做与应用》来本身实践。
经过随机转帐的压测,每次转帐0.0001 SYS,能够经过启动参数--num-senders来控制参与压测的帐户数量,从而控制压测的最大范围。经过压测,能够看出EOS区块链在tps上的表现等指标。
追踪日志,实际上这部分工做我在前面分析候选人出块选举部分时,已经手动作了:在启动链的时候,有一堆参数,其中最末尾会将输出重定向到节点目录的一个文件位置,咱们能够经过命令来时刻追踪这个日志文件。
复制代码

总结

本文首先分为两大部分:第一部分介绍了手动启动一个源节点,全节点以及如何将这两个节点组网,并实现一些业务逻辑的设计,例如交易确认。第二部分,咱们完整详细地分析了启动一个节点的全部必须动做序列(咱们前面研究多签名也好,上面手动组网也好,碰到太多因为初始化 节点时缺少必要步骤所致使的问题,在这种状况下,我决定系统地研究eos的启动序列)。首先重点介绍了股权帐户的概念,其中在分配股权帐户的策略上,咱们也引入了帕累托分配模型;接着就是很是重要的出块者竞选的部分,包括如何注册,启动出块节点,投票,代理投票,成功出块,申领奖励一系列操做;最后,咱们分析了eos的风险模型,将eosio帐户以及其余eosio.*系统帐户进行resign,也引出了resign以后system合约的多签名方式调用,对于eos的性能表现,也给出了压测方案,日志分析办法。

参考资料

  • bios-boot-sequence.py脚本
  • eos官方文档
  • 本文基于EOS v1.0.7

相关文章和视频推荐

圆方圆学院聚集大批区块链名师,打造精品的区块链技术课程。 在各大平台都长期有优质免费公开课,欢迎报名收看。

公开课地址:ke.qq.com/course/3451…

相关文章
相关标签/搜索